From 3406ba3ebf20706d5100e4a88f8cf6b8709d8c80 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 2 Jun 2019 18:48:36 +0100 Subject: [PATCH 001/711] Fix a build from a clean state failing --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index a7e9aebe3..b4bf1056f 100644 --- a/build.gradle +++ b/build.gradle @@ -199,6 +199,7 @@ task compressJson(dependsOn: extractAnnotationsJar) { // Copy over all files in the current jar to the new one, running json files from GSON. As pretty printing // is turned off, they should be minified. new ZipFile(jarPath).withCloseable { inJar -> + tempPath.getParentFile().mkdirs() new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempPath))).withCloseable { outJar -> inJar.entries().each { entry -> if(entry.directory) { From 6f1b740c8f01fb8cdeebd55272764415cb759e94 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 3 Jun 2019 19:58:16 +0100 Subject: [PATCH 002/711] Un-localise paths in mount error messages This is probably a little more complex than it needs to be, as we try to handle the mounts as well (which generally don't error). Fixes #229 --- .../filesystem/FileOperationException.java | 41 ++++++++ .../core/filesystem/ComboMount.java | 9 +- .../core/filesystem/EmptyMount.java | 5 +- .../core/filesystem/FileMount.java | 29 +++--- .../core/filesystem/FileSystem.java | 86 +++++++++-------- .../core/filesystem/JarMount.java | 7 +- .../resources/test-rom/spec/apis/fs_spec.lua | 95 +++++++++++++++++++ 7 files changed, 211 insertions(+), 61 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java new file mode 100644 index 000000000..79c873051 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -0,0 +1,41 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.api.filesystem; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.Objects; + +/** + * An {@link IOException} which occurred on a specific file. + * + * This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure. + */ +public class FileOperationException extends IOException +{ + private static final long serialVersionUID = -8809108200853029849L; + + private String filename; + + public FileOperationException( @Nullable String filename, @Nonnull String message ) + { + super( Objects.requireNonNull( message, "message cannot be null" ) ); + this.filename = filename; + } + + public FileOperationException( String message ) + { + super( Objects.requireNonNull( message, "message cannot be null" ) ); + } + + @Nullable + public String getFilename() + { + return filename; + } +} diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index 1dce543c1..58bc62047 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.filesystem; +import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IMount; import javax.annotation.Nonnull; @@ -95,7 +96,7 @@ public class ComboMount implements IMount } else { - throw new IOException( "/" + path + ": Not a directory" ); + throw new FileOperationException( path, "Not a directory" ); } } @@ -110,7 +111,7 @@ public class ComboMount implements IMount return part.getSize( path ); } } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } @Nonnull @@ -126,7 +127,7 @@ public class ComboMount implements IMount return part.openForRead( path ); } } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } @Nonnull @@ -141,6 +142,6 @@ public class ComboMount implements IMount return part.openChannelForRead( path ); } } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java index 634a76649..5ad38de9b 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.filesystem; +import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IMount; import javax.annotation.Nonnull; @@ -44,7 +45,7 @@ public class EmptyMount implements IMount @Deprecated public InputStream openForRead( @Nonnull String path ) throws IOException { - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } @Nonnull @@ -52,6 +53,6 @@ public class EmptyMount implements IMount @Deprecated public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException { - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index 45cad041e..58c66228f 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -7,6 +7,7 @@ package dan200.computercraft.core.filesystem; import com.google.common.collect.Sets; +import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IWritableMount; import javax.annotation.Nonnull; @@ -167,12 +168,12 @@ public class FileMount implements IWritableMount { if( !created() ) { - if( !path.isEmpty() ) throw new IOException( "/" + path + ": Not a directory" ); + if( !path.isEmpty() ) throw new FileOperationException( path, "Not a directory" ); return; } File file = getRealPath( path ); - if( !file.exists() || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" ); + if( !file.exists() || !file.isDirectory() ) throw new FileOperationException( path, "Not a directory" ); String[] paths = file.list(); for( String subPath : paths ) @@ -194,7 +195,7 @@ public class FileMount implements IWritableMount if( file.exists() ) return file.isDirectory() ? 0 : file.length(); } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } @Nonnull @@ -208,7 +209,7 @@ public class FileMount implements IWritableMount if( file.exists() && !file.isDirectory() ) return new FileInputStream( file ); } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } @Nonnull @@ -221,7 +222,7 @@ public class FileMount implements IWritableMount if( file.exists() && !file.isDirectory() ) return FileChannel.open( file.toPath(), READ_OPTIONS ); } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } // IWritableMount implementation @@ -233,7 +234,7 @@ public class FileMount implements IWritableMount File file = getRealPath( path ); if( file.exists() ) { - if( !file.isDirectory() ) throw new IOException( "/" + path + ": File exists" ); + if( !file.isDirectory() ) throw new FileOperationException( path, "File exists" ); return; } @@ -247,7 +248,7 @@ public class FileMount implements IWritableMount if( getRemainingSpace() < dirsToCreate * MINIMUM_FILE_SIZE ) { - throw new IOException( "/" + path + ": Out of space" ); + throw new FileOperationException( path, "Out of space" ); } if( file.mkdirs() ) @@ -256,14 +257,14 @@ public class FileMount implements IWritableMount } else { - throw new IOException( "/" + path + ": Access denied" ); + throw new FileOperationException( path, "Access denied" ); } } @Override public void delete( @Nonnull String path ) throws IOException { - if( path.isEmpty() ) throw new IOException( "/" + path + ": Access denied" ); + if( path.isEmpty() ) throw new FileOperationException( path, "Access denied" ); if( created() ) { @@ -319,7 +320,7 @@ public class FileMount implements IWritableMount { create(); File file = getRealPath( path ); - if( file.exists() && file.isDirectory() ) throw new IOException( "/" + path + ": Cannot write to directory" ); + if( file.exists() && file.isDirectory() ) throw new FileOperationException( path, "Cannot write to directory" ); if( file.exists() ) { @@ -327,7 +328,7 @@ public class FileMount implements IWritableMount } else if( getRemainingSpace() < MINIMUM_FILE_SIZE ) { - throw new IOException( "/" + path + ": Out of space" ); + throw new FileOperationException( path, "Out of space" ); } m_usedSpace += MINIMUM_FILE_SIZE; @@ -340,12 +341,12 @@ public class FileMount implements IWritableMount { if( !created() ) { - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } File file = getRealPath( path ); - if( !file.exists() ) throw new IOException( "/" + path + ": No such file" ); - if( file.isDirectory() ) throw new IOException( "/" + path + ": Cannot write to directory" ); + if( !file.exists() ) throw new FileOperationException( path, "No such file" ); + if( file.isDirectory() ) throw new FileOperationException( path, "Cannot write to directory" ); // Allowing seeking when appending is not recommended, so we use a separate channel. return new WritableCountingChannel( diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index e36d41af3..98185cc96 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -8,6 +8,7 @@ package dan200.computercraft.core.filesystem; import com.google.common.io.ByteStreams; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -107,7 +108,7 @@ public class FileSystem } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } @@ -122,12 +123,12 @@ public class FileSystem } else { - throw new FileSystemException( "/" + path + ": Not a directory" ); + throw localExceptionOf( path, "Not a directory" ); } } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } @@ -149,12 +150,12 @@ public class FileSystem } else { - throw new FileSystemException( "/" + path + ": No such file" ); + throw localExceptionOf( path, "No such file" ); } } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } @@ -169,12 +170,12 @@ public class FileSystem } else { - throw new FileSystemException( "/" + path + ": No such file" ); + throw localExceptionOf( path, "No such file" ); } } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } @@ -182,19 +183,14 @@ public class FileSystem public void makeDirectory( String path ) throws FileSystemException { - if( m_writableMount == null ) - { - throw new FileSystemException( "/" + path + ": Access denied" ); - } + if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); try { - path = toLocal( path ); if( m_mount.exists( path ) ) { - if( !m_mount.isDirectory( path ) ) - { - throw new FileSystemException( "/" + path + ": File exists" ); - } + if( !m_mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" ); } else { @@ -203,16 +199,14 @@ public class FileSystem } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } public void delete( String path ) throws FileSystemException { - if( m_writableMount == null ) - { - throw new FileSystemException( "/" + path + ": Access denied" ); - } + if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); + try { path = toLocal( path ); @@ -227,22 +221,20 @@ public class FileSystem } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } public WritableByteChannel openForWrite( String path ) throws FileSystemException { - if( m_writableMount == null ) - { - throw new FileSystemException( "/" + path + ": Access denied" ); - } + if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); try { - path = toLocal( path ); if( m_mount.exists( path ) && m_mount.isDirectory( path ) ) { - throw new FileSystemException( "/" + path + ": Cannot write to directory" ); + throw localExceptionOf( path, "Cannot write to directory" ); } else { @@ -263,19 +255,17 @@ public class FileSystem } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } public WritableByteChannel openForAppend( String path ) throws FileSystemException { - if( m_writableMount == null ) - { - throw new FileSystemException( "/" + path + ": Access denied" ); - } + if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); try { - path = toLocal( path ); if( !m_mount.exists( path ) ) { if( !path.isEmpty() ) @@ -290,7 +280,7 @@ public class FileSystem } else if( m_mount.isDirectory( path ) ) { - throw new FileSystemException( "/" + path + ": Cannot write to directory" ); + throw localExceptionOf( path, "Cannot write to directory" ); } else { @@ -303,16 +293,36 @@ public class FileSystem } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( e ); } } - // private members - private String toLocal( String path ) { return FileSystem.toLocal( path, m_location ); } + + private FileSystemException localExceptionOf( IOException e ) + { + if( !m_location.isEmpty() && e instanceof FileOperationException ) + { + FileOperationException ex = (FileOperationException) e; + if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); + } + + return new FileSystemException( e.getMessage() ); + } + + private FileSystemException localExceptionOf( String path, String message ) + { + if( !m_location.isEmpty() ) path = path.isEmpty() ? m_location : m_location + "/" + path; + return exceptionOf( path, message ); + } + + private static FileSystemException exceptionOf( String path, String message ) + { + return new FileSystemException( "/" + path + ": " + message ); + } } private final FileSystemWrapperMount m_wrapper = new FileSystemWrapperMount( this ); diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 941837c94..3bedd1eca 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -9,6 +9,7 @@ package dan200.computercraft.core.filesystem; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.io.ByteStreams; +import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.shared.util.IoUtil; @@ -166,7 +167,7 @@ public class JarMount implements IMount public void list( @Nonnull String path, @Nonnull List contents ) throws IOException { FileEntry file = get( path ); - if( file == null || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" ); + if( file == null || !file.isDirectory() ) throw new FileOperationException( path, "Not a directory" ); file.list( contents ); } @@ -176,7 +177,7 @@ public class JarMount implements IMount { FileEntry file = get( path ); if( file != null ) return file.size; - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } @Nonnull @@ -218,7 +219,7 @@ public class JarMount implements IMount } } - throw new IOException( "/" + path + ": No such file" ); + throw new FileOperationException( path, "No such file" ); } private static class FileEntry diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index 883b8c575..157e0be88 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -11,4 +11,99 @@ describe("The fs library", function() expect.error(fs.complete, "", "", true, 1):eq("bad argument #4 (expected boolean, got number)") end) end) + + describe("fs.list", function() + it("fails on files", function() + expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory") + expect.error(fs.list, "startup.lua"):eq("/startup.lua: Not a directory") + end) + + it("fails on non-existent nodes", function() + expect.error(fs.list, "rom/x"):eq("/rom/x: Not a directory") + expect.error(fs.list, "x"):eq("/x: Not a directory") + end) + end) + + describe("fs.list", function() + it("fails on files", function() + expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory") + expect.error(fs.list, "startup.lua"):eq("/startup.lua: Not a directory") + end) + + it("fails on non-existent nodes", function() + expect.error(fs.list, "rom/x"):eq("/rom/x: Not a directory") + expect.error(fs.list, "x"):eq("/x: Not a directory") + end) + end) + + describe("fs.getSize", function() + it("fails on non-existent nodes", function() + expect.error(fs.getSize, "rom/x"):eq("/rom/x: No such file") + expect.error(fs.getSize, "x"):eq("/x: No such file") + end) + end) + + describe("fs.open", function() + describe("reading", function() + it("fails on directories", function() + expect { fs.open("rom", "r") }:same { nil, "/rom: No such file" } + expect { fs.open("", "r") }:same { nil, "/: No such file" } + end) + + it("fails on non-existent nodes", function() + expect { fs.open("rom/x", "r") }:same { nil, "/rom/x: No such file" } + expect { fs.open("x", "r") }:same { nil, "/x: No such file" } + end) + end) + + describe("writing", function() + it("fails on directories", function() + expect { fs.open("", "w") }:same { nil, "/: Cannot write to directory" } + end) + + it("fails on read-only mounts", function() + expect { fs.open("rom/x", "w") }:same { nil, "/rom/x: Access denied" } + end) + end) + + describe("appending", function() + it("fails on directories", function() + expect { fs.open("", "a") }:same { nil, "/: Cannot write to directory" } + end) + + it("fails on read-only mounts", function() + expect { fs.open("rom/x", "a") }:same { nil, "/rom/x: Access denied" } + end) + end) + end) + + describe("fs.makeDir", function() + it("fails on files", function() + expect.error(fs.makeDir, "startup.lua"):eq("/startup.lua: File exists") + end) + + it("fails on read-only mounts", function() + expect.error(fs.makeDir, "rom/x"):eq("/rom/x: Access denied") + end) + end) + + describe("fs.delete", function() + it("fails on read-only mounts", function() + expect.error(fs.delete, "rom/x"):eq("/rom/x: Access denied") + end) + end) + + describe("fs.copy", function() + it("fails on read-only mounts", function() + expect.error(fs.copy, "rom", "rom/startup"):eq("/rom/startup: Access denied") + end) + end) + + describe("fs.move", function() + it("fails on read-only mounts", function() + expect.error(fs.move, "rom", "rom/move"):eq("Access denied") + expect.error(fs.move, "test-files", "rom/move"):eq("Access denied") + expect.error(fs.move, "rom", "test-files"):eq("Access denied") + end) + end) end) From ffa4cc241bb3c244f408a2040558843409773369 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 3 Jun 2019 20:33:09 +0100 Subject: [PATCH 003/711] Add a test utility for capturing program output - Make mcfly's stubbing system a little more fault-tolerant. - Add a small utility function which redirects print, printError and write to capture their output, rather than printing to the terminal. This can then be matched against in order to determine a program's output. It's a little flakey - you can't use it multiple times in an it block, etc... but it's a nice feature. - Add a small couple of tests to delete as a proof-of-concept. --- src/test/resources/test-rom/mcfly.lua | 13 ++++-- .../test-rom/spec/programs/delete_spec.lua | 12 +++++ .../resources/test-rom/spec/test_helpers.lua | 46 +++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/test/resources/test-rom/spec/test_helpers.lua diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 56a4430e8..02b4b26ed 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -34,10 +34,12 @@ local active_stubs = {} -- @tparam string var The variable to stub -- @param value The value to stub it with local function stub(tbl, var, value) - table.insert(active_stubs, { tbl = tbl, var = var, value = tbl[var] }) - _G[var] = value -end + check('stub', 1, 'table', tbl) + check('stub', 2, 'string', var) + table.insert(active_stubs, { tbl = tbl, var = var, value = tbl[var] }) + rawset(tbl, var, value) +end --- Capture the current global state of the computer local function push_state() @@ -55,7 +57,7 @@ end local function pop_state(state) for i = #active_stubs, 1, -1 do local stub = active_stubs[i] - stub.tbl[stub.var] = stub.value + rawset(stub.tbl, stub.var, stub.value) end active_stubs = state.stubs @@ -353,6 +355,9 @@ if not fs.isDir(root_dir) then error() end +-- Ensure the test folder is also on the package path +package.path = ("/%s/?.lua;/%s/?/init.lua;%s"):format(root_dir, root_dir, package.path) + do -- Load in the tests from all our files local env = setmetatable({}, { __index = _ENV }) diff --git a/src/test/resources/test-rom/spec/programs/delete_spec.lua b/src/test/resources/test-rom/spec/programs/delete_spec.lua index bf2433467..d7434e550 100644 --- a/src/test/resources/test-rom/spec/programs/delete_spec.lua +++ b/src/test/resources/test-rom/spec/programs/delete_spec.lua @@ -1,3 +1,5 @@ +local capture = require "test_helpers".capture_program + describe("The rm program", function() local function touch(file) io.open(file, "w"):close() @@ -32,4 +34,14 @@ describe("The rm program", function() expect(fs.exists("/test-files/a.txt")):eq(false) expect(fs.exists("/test-files/b.txt")):eq(false) end) + + it("displays the usage with no arguments", function() + expect(capture(stub, "rm")) + :matches { ok = true, output = "Usage: rm \n", error = "" } + end) + + it("errors when a glob fails to match", function() + expect(capture(stub, "rm", "never-existed")) + :matches { ok = true, output = "", error = "never-existed: No matching files\n" } + end) end) diff --git a/src/test/resources/test-rom/spec/test_helpers.lua b/src/test/resources/test-rom/spec/test_helpers.lua new file mode 100644 index 000000000..6ffe3942d --- /dev/null +++ b/src/test/resources/test-rom/spec/test_helpers.lua @@ -0,0 +1,46 @@ +--- Run a program and capture its output +-- +-- @tparam function(tbl:table, var:string, value:string) stub The active stub function. +-- @tparam string program The program name. +-- @tparam string ... Arguments to this program. +-- @treturn { ok = boolean, output = string, error = string, combined = string } +-- Whether this program terminated successfully, and the various output streams. +local function capture_program(stub, program, ...) + local output, error, combined = {}, {}, {} + + local function out(stream, msg) + table.insert(stream, msg) + table.insert(combined, msg) + end + + stub(_G, "print", function(...) + for i = 1, select('#', ...) do + if i > 1 then out(output, " ") end + out(output, tostring(select(i, ...))) + end + out(output, "\n") + end) + + stub(_G, "printError", function(...) + for i = 1, select('#', ...) do + if i > 1 then out(error, " ") end + out(error, tostring(select(i, ...))) + end + out(error, "\n") + end) + + stub(_G, "write", function(msg) out(output, tostring(msg)) end) + + local ok = shell.run(program, ...) + + return { + output = table.concat(output), + error = table.concat(error), + combined = table.concat(combined), + ok = ok + } +end + +return { + capture_program = capture_program, +} From d8e1c73d265b83d5fc6744c715cd439d4e6d91c8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 4 Jun 2019 21:34:19 +0100 Subject: [PATCH 004/711] Ensure files cannot be closed multiple times Also fix an NPE if we try to close them twice. Fixes #230 --- .../apis/handles/BinaryReadableHandle.java | 1 + .../apis/handles/BinaryWritableHandle.java | 1 + .../apis/handles/EncodedReadableHandle.java | 1 + .../apis/handles/EncodedWritableHandle.java | 1 + .../core/apis/handles/HandleGeneric.java | 9 ++++-- .../resources/test-rom/spec/apis/fs_spec.lua | 28 +++++++++++++++++++ 6 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index 45f36eaca..77a3b032b 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -212,6 +212,7 @@ public class BinaryReadableHandle extends HandleGeneric } } case 3: // close + checkOpen(); close(); return null; case 4: // seek diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index 7d78411d3..b280ebdcc 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -95,6 +95,7 @@ public class BinaryWritableHandle extends HandleGeneric return null; } case 2: // close + checkOpen(); close(); return null; case 3: // seek diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index 412d29f09..68cdced49 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -152,6 +152,7 @@ public class EncodedReadableHandle extends HandleGeneric return null; } case 3: // close + checkOpen(); close(); return null; default: diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java index a844adaa3..9d81c1b21 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java @@ -93,6 +93,7 @@ public class EncodedWritableHandle extends HandleGeneric return null; } case 3: // close + checkOpen(); close(); return null; default: diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index 2be67444d..87b40ee2a 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -37,8 +37,13 @@ public abstract class HandleGeneric implements ILuaObject protected final void close() { m_open = false; - IoUtil.closeQuietly( m_closable ); - m_closable = null; + + Closeable closeable = m_closable; + if( closeable != null ) + { + IoUtil.closeQuietly( closeable ); + m_closable = null; + } } /** diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index 157e0be88..ad1bfb41c 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -54,6 +54,20 @@ describe("The fs library", function() expect { fs.open("rom/x", "r") }:same { nil, "/rom/x: No such file" } expect { fs.open("x", "r") }:same { nil, "/x: No such file" } end) + + it("errors when closing twice", function() + local handle = fs.open("rom/startup.lua", "r") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) + end) + + describe("reading in binary mode", function() + it("errors when closing twice", function() + local handle = fs.open("rom/startup.lua", "rb") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) end) describe("writing", function() @@ -64,6 +78,20 @@ describe("The fs library", function() it("fails on read-only mounts", function() expect { fs.open("rom/x", "w") }:same { nil, "/rom/x: Access denied" } end) + + it("errors when closing twice", function() + local handle = fs.open("test-files/out.txt", "w") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) + end) + + describe("writing in binary mode", function() + it("errors when closing twice", function() + local handle = fs.open("test-files/out.txt", "wb") + handle.close() + expect.error(handle.close):eq("attempt to use a closed file") + end) end) describe("appending", function() From 00c395f68966e7b0673a3071794404d2ae75f7b7 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Thu, 6 Jun 2019 17:43:48 +0200 Subject: [PATCH 005/711] Add Check to delete.lua (#236) --- .../assets/computercraft/lua/rom/programs/delete.lua | 5 ++++- src/test/resources/test-rom/spec/programs/delete_spec.lua | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua b/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua index 51e8d288c..e2d296805 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua @@ -9,7 +9,10 @@ for i = 1, args.n do local files = fs.find(shell.resolve(args[i])) if #files > 0 then for n, file in ipairs(files) do - fs.delete(file) + local ok, err = pcall(fs.delete, file) + if not ok then + printError((err:gsub("^pcall: ", ""))) + end end else printError(args[i] .. ": No matching files") diff --git a/src/test/resources/test-rom/spec/programs/delete_spec.lua b/src/test/resources/test-rom/spec/programs/delete_spec.lua index d7434e550..5036f7eae 100644 --- a/src/test/resources/test-rom/spec/programs/delete_spec.lua +++ b/src/test/resources/test-rom/spec/programs/delete_spec.lua @@ -39,6 +39,11 @@ describe("The rm program", function() expect(capture(stub, "rm")) :matches { ok = true, output = "Usage: rm \n", error = "" } end) + + it("errors when trying to delete a read-only file", function() + expect(capture(stub, "rm /rom/startup.lua")) + :matches { ok = true, output = "", error = "/rom/startup.lua: Access denied\n" } + end) it("errors when a glob fails to match", function() expect(capture(stub, "rm", "never-existed")) From 7d428030df1995c347759837676cf56fd2703872 Mon Sep 17 00:00:00 2001 From: Lignum Date: Fri, 7 Jun 2019 15:35:17 +0200 Subject: [PATCH 006/711] Fix some warnings (#235) Remove some unused code and fix a bunch of warnings --- .gitignore | 6 ++++++ .../computercraft/api/filesystem/IMount.java | 1 - .../api/filesystem/IWritableMount.java | 2 -- .../dan200/computercraft/core/apis/HTTPAPI.java | 4 ++-- .../dan200/computercraft/core/apis/OSAPI.java | 1 - .../computercraft/core/apis/PeripheralAPI.java | 1 - .../computercraft/core/computer/Computer.java | 1 - .../computercraft/core/filesystem/JarMount.java | 11 ++--------- .../computercraft/shared/common/BlockGeneric.java | 1 - .../computercraft/shared/common/TileGeneric.java | 1 - .../shared/computer/core/ServerComputer.java | 7 +++++++ .../shared/integration/jei/JEIComputerCraft.java | 1 + .../peripheral/speaker/SpeakerPeripheral.java | 2 +- .../shared/turtle/core/TurtlePlaceCommand.java | 1 - .../computercraft/shared/util/StringUtil.java | 2 -- .../computercraft/shared/wired/NetworkTest.java | 15 --------------- 16 files changed, 19 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 0b28ad333..80c50f9b8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,9 @@ .idea .gradle *.DS_Store + +.classpath +.project +.settings/ +bin/ +*.launch diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 1fec70994..1952ee9e0 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -90,7 +90,6 @@ public interface IMount * @throws IOException If the file does not exist, or could not be opened. */ @Nonnull - @SuppressWarnings( "deprecation" ) default ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException { return Channels.newChannel( openForRead( path ) ); diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index e265842e7..38ae27da0 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -67,7 +67,6 @@ public interface IWritableMount extends IMount * @throws IOException If the file could not be opened for writing. */ @Nonnull - @SuppressWarnings( "deprecation" ) default WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException { return Channels.newChannel( openForWrite( path ) ); @@ -94,7 +93,6 @@ public interface IWritableMount extends IMount * @throws IOException If the file could not be opened for writing. */ @Nonnull - @SuppressWarnings( "deprecation" ) default WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException { return Channels.newChannel( openForAppend( path ) ); diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 23fb93ed3..d1d808f6e 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -83,6 +83,7 @@ public class HTTPAPI implements ILuaAPI } @Override + @SuppressWarnings( "resource" ) public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException { switch( method ) @@ -95,7 +96,7 @@ public class HTTPAPI implements ILuaAPI if( args.length >= 1 && args[0] instanceof Map ) { - Map options = (Map) args[0]; + Map options = (Map) args[0]; address = getStringField( options, "url" ); postString = optStringField( options, "body", null ); headerTable = optTableField( options, "headers", Collections.emptyMap() ); @@ -135,7 +136,6 @@ public class HTTPAPI implements ILuaAPI try { URI uri = HttpRequest.checkUri( address ); - HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect ); long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers ); diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index fbbfe5e0f..d83559207 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -401,7 +401,6 @@ public class OSAPI implements ILuaAPI Instant instant = Instant.ofEpochSecond( time ); ZonedDateTime date; ZoneOffset offset; - boolean isDst; if( format.startsWith( "!" ) ) { offset = ZoneOffset.UTC; diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index eb77fe12b..09025978c 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -356,7 +356,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); if( side != null ) { - String type = null; synchronized( m_peripherals ) { PeripheralWrapper p = m_peripherals[side.ordinal()]; diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index e1ee67083..101707ca6 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -239,7 +239,6 @@ public class Computer } @Deprecated - @SuppressWarnings( "unused" ) public void advance( double dt ) { tick(); diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 3bedd1eca..24e350330 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -93,7 +93,7 @@ public class JarMount implements IMount new MountReference( this ); // Read in all the entries - root = new FileEntry( "" ); + root = new FileEntry(); Enumeration zipEntries = zip.entries(); while( zipEntries.hasMoreElements() ) { @@ -140,7 +140,7 @@ public class JarMount implements IMount FileEntry nextEntry = lastEntry.children.get( part ); if( nextEntry == null || !nextEntry.isDirectory() ) { - lastEntry.children.put( part, nextEntry = new FileEntry( part ) ); + lastEntry.children.put( part, nextEntry = new FileEntry() ); } lastEntry = nextEntry; @@ -224,17 +224,10 @@ public class JarMount implements IMount private static class FileEntry { - final String name; - String path; long size; Map children; - FileEntry( String name ) - { - this.name = name; - } - void setup( ZipEntry entry ) { path = entry.getName(); diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index bc60d2f0e..fa039875e 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -51,7 +51,6 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider @Override @Deprecated - @SuppressWarnings( "deprecation" ) public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos ) { TileEntity tile = world.getTileEntity( pos ); diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 850bf844c..0634f0497 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -63,7 +63,6 @@ public abstract class TileGeneric extends TileEntity { } - @SuppressWarnings( "deprecation" ) public void onNeighbourChange( @Nonnull BlockPos neighbour ) { onNeighbourChange(); diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index f5799af28..e75b55fa3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -220,6 +220,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return m_instanceID; } + /* + * getID and getLabel are deprecated on IComputer, as they do not make sense in ClientComputer. + * However, for compatibility reasons, we still need these here, and have no choice but to override the IComputer methods. + * + * Hence, we suppress the deprecation warning. + */ + @Override @SuppressWarnings( "deprecation" ) public int getID() diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 6ec7aaddf..867b89947 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -90,6 +90,7 @@ public class JEIComputerCraft implements IModPlugin ingredients.addIngredientsAtRuntime( VanillaTypes.ITEM, upgradeItems ); // Hide all upgrade recipes + @SuppressWarnings( "unchecked" ) IRecipeCategory category = (IRecipeCategory) registry.getRecipeCategory( VanillaRecipeCategoryUid.CRAFTING ); if( category != null ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index dcc19ccd9..bda1fe4e0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -44,7 +44,7 @@ public abstract class SpeakerPeripheral implements IPeripheral { // FIXME: Should be abstract, but we need this for Plethora compat. We'll // be able to change this in a few versions as we implement both there. - @SuppressWarnings( "deprecation" ) BlockPos pos = getPos(); + BlockPos pos = getPos(); return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 16fd6e508..34ad51413 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -65,7 +65,6 @@ public class TurtlePlaceCommand implements ITurtleCommand // Remember old block EnumFacing direction = m_direction.toWorldDir( turtle ); - World world = turtle.getWorld(); BlockPos coordinates = turtle.getPosition().offset( direction ); // Create a fake player, and orient it appropriately diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index 8c92a25a4..d08f0f8ba 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -35,7 +35,6 @@ public final class StringUtil /** * Translates a Stat name */ - @SuppressWarnings( "deprecation" ) public static String translate( String key ) { return net.minecraft.util.text.translation.I18n.translateToLocal( key ); @@ -44,7 +43,6 @@ public final class StringUtil /** * Translates a Stat name with format args */ - @SuppressWarnings( "deprecation" ) public static String translateFormatted( String key, Object... format ) { return net.minecraft.util.text.translation.I18n.translateToLocalFormatted( key, format ); diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 6a44ccba4..24f121a2a 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -25,7 +25,6 @@ import net.minecraft.world.World; import org.apache.logging.log4j.LogManager; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import javax.annotation.Nonnull; @@ -440,20 +439,6 @@ public class NetworkTest this.box = (T[]) new Object[size * size * size]; } - public void set( BlockPos pos, T elem ) - { - int x = pos.getX(), y = pos.getY(), z = pos.getZ(); - - if( x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size ) - { - box[x * size * size + y * size + z] = elem; - } - else - { - throw new IndexOutOfBoundsException( pos.toString() ); - } - } - public T get( BlockPos pos ) { int x = pos.getX(), y = pos.getY(), z = pos.getZ(); From a0e7c4a74c24d8e1b3eb87d46ae0d4bea6de6197 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 8 Jun 2019 00:28:03 +0100 Subject: [PATCH 007/711] Add a little bit of source code checking to Gradle - Adds a CheckStyle configuration which is pretty similar to CC's existing one. - Add the Gradle license plugin. - Ensure the existing source code is compatible with these additional checks. See #239 --- build.gradle | 49 +++++- config/checkstyle/checkstyle.xml | 159 ++++++++++++++++++ config/checkstyle/suppressions.xml | 13 ++ .../idea/codeInspectionSettings.xml | 0 .../idea/codeStyleSettings.xml | 0 config/license/api.txt | 3 + config/license/main.txt | 3 + .../api/AbstractTurtleUpgrade.java | 7 +- .../computercraft/api/ComputerCraftAPI.java | 26 +-- .../filesystem/FileOperationException.java | 10 +- .../api/peripheral/IWorkMonitor.java | 7 +- .../api/pocket/AbstractPocketUpgrade.java | 7 +- .../turtle/event/TurtleInspectItemEvent.java | 7 +- .../api/turtle/event/TurtleRefuelEvent.java | 7 +- .../computercraft/client/gui/GuiTurtle.java | 2 +- .../client/render/ModelTransformer.java | 2 +- .../dan200/computercraft/core/apis/FSAPI.java | 4 +- .../computercraft/core/apis/HTTPAPI.java | 4 +- .../computercraft/core/apis/ILuaAPI.java | 1 + .../dan200/computercraft/core/apis/OSAPI.java | 18 +- .../core/apis/PeripheralAPI.java | 8 +- .../computercraft/core/apis/RedstoneAPI.java | 4 +- .../computercraft/core/apis/TermAPI.java | 8 +- .../core/apis/http/Resource.java | 6 +- .../core/computer/ComputerSide.java | 5 +- .../core/filesystem/FileSystem.java | 4 +- .../core/lua/CobaltLuaMachine.java | 2 +- .../core/terminal/TextBuffer.java | 2 +- .../shared/computer/apis/CommandAPI.java | 6 +- .../computer/core/ComputerRegistry.java | 10 +- .../charset/BundledCapabilityProvider.java | 3 +- .../charset/BundledRedstoneProvider.java | 3 +- .../charset/IntegrationCharset.java | 3 +- .../shared/peripheral/PeripheralType.java | 5 +- .../commandblock/CommandBlockPeripheral.java | 2 +- .../diskdrive/DiskDrivePeripheral.java | 2 +- .../peripheral/modem/ModemPeripheral.java | 4 +- .../modem/wired/WiredModemPeripheral.java | 2 +- .../peripheral/monitor/TileMonitor.java | 4 +- .../peripheral/speaker/SpeakerPeripheral.java | 4 +- .../shared/pocket/apis/PocketAPI.java | 6 +- .../shared/turtle/apis/TurtleAPI.java | 4 +- .../shared/turtle/core/TurtleBrain.java | 4 +- .../turtle/inventory/ContainerTurtle.java | 8 +- .../shared/turtle/items/ItemTurtleLegacy.java | 5 +- .../shared/turtle/upgrades/TurtleHoe.java | 2 +- .../shared/turtle/upgrades/TurtleShovel.java | 2 +- .../shared/turtle/upgrades/TurtleTool.java | 12 +- .../shared/util/ColourUtils.java | 2 +- .../computercraft/shared/util/Palette.java | 11 +- .../computercraft/shared/util/StringUtil.java | 2 + .../core/computer/BasicEnvironment.java | 4 +- .../core/computer/ComputerBootstrap.java | 2 +- .../shared/wired/NetworkTest.java | 12 +- 54 files changed, 349 insertions(+), 143 deletions(-) create mode 100644 config/checkstyle/checkstyle.xml create mode 100644 config/checkstyle/suppressions.xml rename codeInspectionSettings.xml => config/idea/codeInspectionSettings.xml (100%) rename codeStyleSettings.xml => config/idea/codeStyleSettings.xml (100%) create mode 100644 config/license/api.txt create mode 100644 config/license/main.txt diff --git a/build.gradle b/build.gradle index b4bf1056f..793175ac9 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,9 @@ buildscript { } plugins { - id 'com.matthewprenger.cursegradle' version '1.2.0' + id "checkstyle" + id "com.github.hierynomus.license" version "0.15.0" + id "com.matthewprenger.cursegradle" version "1.3.0" id "com.github.breadmoirai.github-release" version "2.2.4" } @@ -66,6 +68,8 @@ configurations { } dependencies { + checkstyle "com.puppycrawl.tools:checkstyle:8.21" + deobfProvided "mezz.jei:jei_1.12.2:4.15.0.269:api" deobfProvided "pl.asie:Charset-Lib:0.5.4.6" deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" @@ -104,6 +108,8 @@ import java.util.zip.* import com.google.gson.GsonBuilder import com.google.gson.JsonElement +import com.hierynomus.gradle.license.tasks.LicenseCheck +import com.hierynomus.gradle.license.tasks.LicenseFormat import org.ajoberstar.grgit.Grgit import proguard.gradle.ProGuardTask @@ -227,6 +233,42 @@ task compressJson(dependsOn: extractAnnotationsJar) { assemble.dependsOn compressJson +/* Check tasks */ + +license { + mapping("java", "SLASHSTAR_STYLE") + strictCheck true + + ext.year = Calendar.getInstance().get(Calendar.YEAR) +} + +[licenseMain, licenseFormatMain].forEach { + it.configure { + include("**/*.java") + exclude("dan200/computercraft/api/**") + header rootProject.file('config/license/main.txt') + } +} + +[licenseTest, licenseFormatTest].forEach { + it.configure { + include("**/*.java") + header rootProject.file('config/license/main.txt') + } +} + +task licenseAPI(type: LicenseCheck); +task licenseFormatAPI(type: LicenseFormat); +[licenseAPI, licenseFormatAPI].forEach { + it.configure { + source = sourceSets.main.java + include("dan200/computercraft/api/**") + header rootProject.file('config/license/api.txt') + } +} + +/* Upload tasks */ + task checkRelease { group "upload" description "Verifies that everything is ready for a release" @@ -266,7 +308,6 @@ task checkRelease { } } - curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { @@ -369,6 +410,10 @@ gradle.projectsEvaluated { tasks.withType(JavaCompile) { options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror" } + + tasks.withType(LicenseFormat) { + outputs.upToDateWhen { false } + } } runClient.outputs.upToDateWhen { false } diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 000000000..3dcaa94a2 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 000000000..a6dd2983d --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/codeInspectionSettings.xml b/config/idea/codeInspectionSettings.xml similarity index 100% rename from codeInspectionSettings.xml rename to config/idea/codeInspectionSettings.xml diff --git a/codeStyleSettings.xml b/config/idea/codeStyleSettings.xml similarity index 100% rename from codeStyleSettings.xml rename to config/idea/codeStyleSettings.xml diff --git a/config/license/api.txt b/config/license/api.txt new file mode 100644 index 000000000..5c1d391fe --- /dev/null +++ b/config/license/api.txt @@ -0,0 +1,3 @@ +This file is part of the public ComputerCraft API - http://www.computercraft.info +Copyright Daniel Ratcliffe, 2011-${year}. This API may be redistributed unmodified and in full only. +For help using the API, and posting your mods, visit the forums at computercraft.info. diff --git a/config/license/main.txt b/config/license/main.txt new file mode 100644 index 000000000..bab494b2e --- /dev/null +++ b/config/license/main.txt @@ -0,0 +1,3 @@ +This file is part of ComputerCraft - http://www.computercraft.info +Copyright Daniel Ratcliffe, 2011-${year}. Do not distribute without permission. +Send enquiries to dratcliffe@gmail.com diff --git a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java index ab9f86b50..3cbbfb339 100644 --- a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java @@ -1,9 +1,8 @@ /* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api; import dan200.computercraft.api.turtle.ITurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 6f9713808..76d9ad311 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -438,45 +438,45 @@ public final class ComputerCraftAPI computerCraft_getVersion = findCCMethod( "getVersion", new Class[] { } ); computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[] { - World.class, String.class + World.class, String.class, } ); computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] { - World.class, String.class, Long.TYPE + World.class, String.class, Long.TYPE, } ); computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] { - Class.class, String.class, String.class + Class.class, String.class, String.class, } ); computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class[] { - IPeripheralProvider.class + IPeripheralProvider.class, } ); computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class[] { - ITurtleUpgrade.class + ITurtleUpgrade.class, } ); computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class[] { - IBundledRedstoneProvider.class + IBundledRedstoneProvider.class, } ); computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class[] { - World.class, BlockPos.class, EnumFacing.class + World.class, BlockPos.class, EnumFacing.class, } ); computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class[] { - IMediaProvider.class + IMediaProvider.class, } ); computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class[] { - ITurtlePermissionProvider.class + ITurtlePermissionProvider.class, } ); computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class[] { - IPocketUpgrade.class + IPocketUpgrade.class, } ); computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class[] { } ); computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class[] { - ILuaAPIFactory.class + ILuaAPIFactory.class, } ); computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class[] { - IWiredElement.class + IWiredElement.class, } ); computerCraft_getWiredElementAt = findCCMethod( "getWiredElementAt", new Class[] { - IBlockAccess.class, BlockPos.class, EnumFacing.class + IBlockAccess.class, BlockPos.class, EnumFacing.class, } ); } catch( Exception e ) diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index 79c873051..eef6cf4f3 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -1,9 +1,8 @@ /* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import javax.annotation.Nonnull; @@ -20,7 +19,7 @@ public class FileOperationException extends IOException { private static final long serialVersionUID = -8809108200853029849L; - private String filename; + private final String filename; public FileOperationException( @Nullable String filename, @Nonnull String message ) { @@ -31,6 +30,7 @@ public class FileOperationException extends IOException public FileOperationException( String message ) { super( Objects.requireNonNull( message, "message cannot be null" ) ); + this.filename = null; } @Nullable diff --git a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java index 0c0783026..68da2d1d9 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java @@ -1,9 +1,8 @@ /* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index 5f345a894..7965a7c3e 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -1,9 +1,8 @@ /* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.pocket; import net.minecraft.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index 1bd2164d2..26abb36bb 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -1,9 +1,8 @@ /* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java index 33dbc3d2f..773de6ff0 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -1,9 +1,8 @@ /* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 80f283889..79798ec89 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -120,7 +120,7 @@ public class GuiTurtle extends GuiContainer int slotX = slot % 4; int slotY = slot / 4; mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - drawTexturedModalRect( guiLeft + m_container.m_turtleInvStartX - 2 + slotX * 18, guiTop + m_container.m_playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 ); + drawTexturedModalRect( guiLeft + m_container.turtleInvStartX - 2 + slotX * 18, guiTop + m_container.playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 ); } } diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index 7f67c3178..01cfd8e22 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -94,7 +94,7 @@ public final class ModelTransformer private final Point3f[] before = new Point3f[4]; private final Point3f[] after = new Point3f[4]; - public NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix ) + NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix ) { super( parent ); this.positionMatrix = positionMatrix; diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 2f1f92299..71178d1fe 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -43,9 +43,7 @@ public class FSAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "fs" - }; + return new String[] { "fs" }; } @Override diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index d1d808f6e..d7b36491c 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -42,9 +42,7 @@ public class HTTPAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "http" - }; + return new String[] { "http" }; } @Override diff --git a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java b/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java index 63d49879c..a4a34fa11 100644 --- a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java @@ -10,6 +10,7 @@ package dan200.computercraft.core.apis; * This exists purely to ensure binary compatibility. * * @see dan200.computercraft.api.lua.ILuaAPI + * @deprecated Use the version in the public API. Only exists for compatibility with CCEmuX. */ @Deprecated public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index d83559207..40f22d176 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -36,9 +36,9 @@ public class OSAPI implements ILuaAPI private static class Timer { - public int m_ticksLeft; + int m_ticksLeft; - public Timer( int ticksLeft ) + Timer( int ticksLeft ) { m_ticksLeft = ticksLeft; } @@ -46,10 +46,10 @@ public class OSAPI implements ILuaAPI private static class Alarm implements Comparable { - public final double m_time; - public final int m_day; + final double m_time; + final int m_day; - public Alarm( double time, int day ) + Alarm( double time, int day ) { m_time = time; m_day = day; @@ -78,9 +78,7 @@ public class OSAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "os" - }; + return new String[] { "os" }; } @Override @@ -385,9 +383,7 @@ public class OSAPI implements ILuaAPI // Get in-game epoch synchronized( m_alarms ) { - return new Object[] { - m_day * 86400000 + (int) (m_time * 3600000.0f) - }; + return new Object[] { m_day * 86400000 + (int) (m_time * 3600000.0f) }; } default: throw new LuaException( "Unsupported operation" ); diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 09025978c..cd27ca756 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -36,7 +36,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange private Map m_methodMap; private boolean m_attached; - public PeripheralWrapper( IPeripheral peripheral, String side ) + PeripheralWrapper( IPeripheral peripheral, String side ) { super( m_environment ); m_side = side; @@ -282,9 +282,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public String[] getNames() { - return new String[] { - "peripheral" - }; + return new String[] { "peripheral" }; } @Override @@ -326,7 +324,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange "isPresent", "getType", "getMethods", - "call" + "call", }; } diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index d36ba9186..1a0217c2f 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -29,9 +29,7 @@ public class RedstoneAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "rs", "redstone" - }; + return new String[] { "rs", "redstone" }; } @Nonnull diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 70460d3ed..382ae4069 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -33,9 +33,7 @@ public class TermAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "term" - }; + return new String[] { "term" }; } @Nonnull @@ -89,9 +87,7 @@ public class TermAPI implements ILuaAPI public static Object[] encodeColour( int colour ) throws LuaException { - return new Object[] { - 1 << colour - }; + return new Object[] { 1 << colour }; } public static void setColour( Terminal terminal, int colour, double r, double g, double b ) diff --git a/src/main/java/dan200/computercraft/core/apis/http/Resource.java b/src/main/java/dan200/computercraft/core/apis/http/Resource.java index 60a6c0590..f7bec3f28 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/Resource.java +++ b/src/main/java/dan200/computercraft/core/apis/http/Resource.java @@ -72,7 +72,8 @@ public abstract class Resource> implements Closeable */ protected void dispose() { - @SuppressWarnings( "unchecked" ) T thisT = (T) this; + @SuppressWarnings( "unchecked" ) + T thisT = (T) this; limiter.release( thisT ); } @@ -95,7 +96,8 @@ public abstract class Resource> implements Closeable public boolean queue( Consumer task ) { - @SuppressWarnings( "unchecked" ) T thisT = (T) this; + @SuppressWarnings( "unchecked" ) + T thisT = (T) this; return limiter.queue( thisT, () -> task.accept( thisT ) ); } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java index d2937fd3b..1cbbfa294 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -30,7 +30,10 @@ public enum ComputerSide private final String name; - ComputerSide( String name ) {this.name = name;} + ComputerSide( String name ) + { + this.name = name; + } @Nonnull public static ComputerSide valueOf( int side ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 98185cc96..c02d6def3 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -46,7 +46,7 @@ public class FileSystem m_writableMount = null; } - public MountWrapper( String label, String location, IWritableMount mount ) + MountWrapper( String label, String location, IWritableMount mount ) { this( label, location, (IMount) mount ); m_writableMount = mount; @@ -779,7 +779,7 @@ public class FileSystem // Clean the path or illegal characters. final char[] specialChars = new char[] { - '"', ':', '<', '>', '?', '|' // Sorted by ascii value (important) + '"', ':', '<', '>', '?', '|', // Sorted by ascii value (important) }; StringBuilder cleanName = new StringBuilder(); diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 55a986e16..64a34df5c 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -550,7 +550,7 @@ public class CobaltLuaMachine implements ILuaMachine { if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running task", t ); m_computer.queueEvent( "task_complete", new Object[] { - taskID, false, "Java Exception Thrown: " + t + taskID, false, "Java Exception Thrown: " + t, } ); } }; diff --git a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java index b7e0aa5ab..fa24e9d51 100644 --- a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java +++ b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java @@ -8,7 +8,7 @@ package dan200.computercraft.core.terminal; public class TextBuffer { - public char[] m_text; + private final char[] m_text; public TextBuffer( char c, int length ) { diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 5ebf305c9..08e4c4afa 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -47,9 +47,7 @@ public class CommandAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "commands" - }; + return new String[] { "commands" }; } @Nonnull @@ -62,7 +60,7 @@ public class CommandAPI implements ILuaAPI "list", "getBlockPosition", "getBlockInfos", - "getBlockInfo" + "getBlockInfo", }; } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java index ca9e8c567..9c795878c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java @@ -11,9 +11,9 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; -public class ComputerRegistry +public class ComputerRegistry { - private Map m_computers; + private Map m_computers; private int m_nextUnusedInstanceID; private int m_sessionID; @@ -33,12 +33,12 @@ public class ComputerRegistry return m_nextUnusedInstanceID++; } - public Collection getComputers() + public Collection getComputers() { return m_computers.values(); } - public TComputer get( int instanceID ) + public T get( int instanceID ) { if( instanceID >= 0 ) { @@ -55,7 +55,7 @@ public class ComputerRegistry return m_computers.containsKey( instanceID ); } - public void add( int instanceID, TComputer computer ) + public void add( int instanceID, T computer ) { if( m_computers.containsKey( instanceID ) ) { diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java index e5ceb8374..fe478f7c2 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.charset; import dan200.computercraft.shared.common.TileGeneric; diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java index 137835784..e7ac4768a 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.charset; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java index fec2e8959..32055fc92 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.charset; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java b/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java index 3bb4dfa2b..5fc318e28 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java @@ -39,5 +39,8 @@ public enum PeripheralType implements IStringSerializable } @Override - public String toString() { return name; } + public String toString() + { + return name; + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index 58fedd28b..f81a862b8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -52,7 +52,7 @@ public class CommandBlockPeripheral implements IPeripheral { case 0: // getCommand return context.executeMainThreadTask( () -> new Object[] { - m_commandBlock.getCommandBlockLogic().getCommand() + m_commandBlock.getCommandBlockLogic().getCommand(), } ); case 1: { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index f15dcaf44..048127ab0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -51,7 +51,7 @@ public class DiskDrivePeripheral implements IPeripheral "playAudio", "stopAudio", "ejectDisk", - "getDiskID" + "getDiskID", }; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 1f920432c..9009b4ec7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -87,7 +87,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa for( IComputerAccess computer : m_computers ) { computer.queueEvent( "modem_message", new Object[] { - computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance + computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance, } ); } } @@ -103,7 +103,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa for( IComputerAccess computer : m_computers ) { computer.queueEvent( "modem_message", new Object[] { - computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload() + computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), } ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 2c76c05d5..2cb992793 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -277,7 +277,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW private final String[] m_methods; private final Map m_methodMap; - public RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name ) + RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name ) { m_element = element; m_peripheral = peripheral; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 7e02de778..66307dd98 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -142,7 +142,7 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph for( IComputerAccess computer : monitor.m_computers ) { computer.queueEvent( "monitor_resize", new Object[] { - computer.getAttachmentName() + computer.getAttachmentName(), } ); } } @@ -660,7 +660,7 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph for( IComputerAccess computer : monitor.m_computers ) { computer.queueEvent( "monitor_touch", new Object[] { - computer.getAttachmentName(), xCharPos, yCharPos + computer.getAttachmentName(), xCharPos, yCharPos, } ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index bda1fe4e0..f92074f7e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -71,8 +71,8 @@ public abstract class SpeakerPeripheral implements IPeripheral public String[] getMethodNames() { return new String[] { - "playSound", // Plays sound at resourceLocator - "playNote" // Plays note + "playSound", + "playNote", }; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 906890b49..f5ef6f79e 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -35,9 +35,7 @@ public class PocketAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "pocket" - }; + return new String[] { "pocket" }; } @Nonnull @@ -46,7 +44,7 @@ public class PocketAPI implements ILuaAPI { return new String[] { "equipBack", - "unequipBack" + "unequipBack", }; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 2d5863e76..475400aaa 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -45,9 +45,7 @@ public class TurtleAPI implements ILuaAPI @Override public String[] getNames() { - return new String[] { - "turtle" - }; + return new String[] { "turtle" }; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 01df6fcdd..494b8750d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -908,14 +908,14 @@ public class TurtleBrain implements ITurtleAccess else { computer.queueEvent( "turtle_response", new Object[] { - callbackID, true + callbackID, true, } ); } } else { computer.queueEvent( "turtle_response", new Object[] { - callbackID, false, result != null ? result.getErrorMessage() : null + callbackID, false, result != null ? result.getErrorMessage() : null, } ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 3982e7770..26a00a3a0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -26,8 +26,8 @@ public class ContainerTurtle extends Container implements IContainerComputer { private static final int PROGRESS_ID_SELECTED_SLOT = 0; - public final int m_playerInvStartY; - public final int m_turtleInvStartX; + public final int playerInvStartY; + public final int turtleInvStartX; private final ITurtleAccess m_turtle; private IComputer m_computer; @@ -36,8 +36,8 @@ public class ContainerTurtle extends Container implements IContainerComputer protected ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle, int playerInvStartY, int turtleInvStartX ) { - m_playerInvStartY = playerInvStartY; - m_turtleInvStartX = turtleInvStartX; + this.playerInvStartY = playerInvStartY; + this.turtleInvStartX = turtleInvStartX; m_turtle = turtle; m_selectedSlot = m_turtle.getWorld().isRemote ? 0 : m_turtle.getSelectedSlot(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java index 75a31ac71..2d5b36ab0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java @@ -73,7 +73,10 @@ public class ItemTurtleLegacy extends ItemTurtleBase } @Override - public ResourceLocation getOverlay( @Nonnull ItemStack stack ) { return null; } + public ResourceLocation getOverlay( @Nonnull ItemStack stack ) + { + return null; + } @Override public int getFuelLevel( @Nonnull ItemStack stack ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index be57b1995..4e6a2de00 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -54,7 +54,7 @@ public class TurtleHoe extends TurtleTool { if( verb == TurtleVerb.Dig ) { - ItemStack hoe = m_item.copy(); + ItemStack hoe = item.copy(); ItemStack remainder = TurtlePlaceCommand.deploy( hoe, turtle, direction, null, null ); if( remainder != hoe ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index a8f287c23..4e1c44689 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -60,7 +60,7 @@ public class TurtleShovel extends TurtleTool { if( verb == TurtleVerb.Dig ) { - ItemStack shovel = m_item.copy(); + ItemStack shovel = item.copy(); ItemStack remainder = TurtlePlaceCommand.deploy( shovel, turtle, direction, null, null ); if( remainder != shovel ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index ce61cd1cb..d91c02a77 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -48,18 +48,18 @@ import java.util.function.Function; public class TurtleTool extends AbstractTurtleUpgrade { - protected ItemStack m_item; + protected final ItemStack item; public TurtleTool( ResourceLocation id, int legacyID, String adjective, Item item ) { super( id, legacyID, TurtleUpgradeType.Tool, adjective, item ); - m_item = new ItemStack( item, 1, 0 ); + this.item = new ItemStack( item, 1, 0 ); } public TurtleTool( ResourceLocation id, int legacyID, Item item ) { super( id, legacyID, TurtleUpgradeType.Tool, item ); - m_item = new ItemStack( item, 1, 0 ); + this.item = new ItemStack( item, 1, 0 ); } @Nonnull @@ -76,7 +76,7 @@ public class TurtleTool extends AbstractTurtleUpgrade ); Minecraft mc = Minecraft.getMinecraft(); return Pair.of( - mc.getRenderItem().getItemModelMesher().getItemModel( m_item ), + mc.getRenderItem().getItemModelMesher().getItemModel( item ), transform ); } @@ -124,7 +124,7 @@ public class TurtleTool extends AbstractTurtleUpgrade if( hit != null ) { // Load up the turtle's inventory - ItemStack stackCopy = m_item.copy(); + ItemStack stackCopy = item.copy(); turtlePlayer.loadInventory( stackCopy ); Entity hitEntity = hit.getKey(); @@ -202,7 +202,7 @@ public class TurtleTool extends AbstractTurtleUpgrade IBlockState state = world.getBlockState( blockPosition ); TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); - turtlePlayer.loadInventory( m_item.copy() ); + turtlePlayer.loadInventory( item.copy() ); if( ComputerCraft.turtlesObeyBlockProtection ) { diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 08c4ec6b1..d4dccc176 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -20,7 +20,7 @@ public final class ColourUtils "dyeBlack", "dyeRed", "dyeGreen", "dyeBrown", "dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray", "dyeGray", "dyePink", "dyeLime", "dyeYellow", - "dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite" + "dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite", }; private static int[] ids; diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index b332e8b5f..8d4a0649c 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -72,12 +72,11 @@ public class Palette public static double[] decodeRGB8( int rgb ) { - return new double[] - { - ((rgb >> 16) & 0xFF) / 255.0f, - ((rgb >> 8) & 0xFF) / 255.0f, - (rgb & 0xFF) / 255.0f - }; + return new double[] { + ((rgb >> 16) & 0xFF) / 255.0f, + ((rgb >> 8) & 0xFF) / 255.0f, + (rgb & 0xFF) / 255.0f, + }; } public NBTTagCompound writeToNBT( NBTTagCompound nbt ) diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index d08f0f8ba..8c92a25a4 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -35,6 +35,7 @@ public final class StringUtil /** * Translates a Stat name */ + @SuppressWarnings( "deprecation" ) public static String translate( String key ) { return net.minecraft.util.text.translation.I18n.translateToLocal( key ); @@ -43,6 +44,7 @@ public final class StringUtil /** * Translates a Stat name with format args */ + @SuppressWarnings( "deprecation" ) public static String translateFormatted( String key, Object... format ) { return net.minecraft.util.text.translation.I18n.translateToLocalFormatted( key, format ); diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index dbd3ccf35..b43ef3bda 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -96,7 +96,7 @@ public class BasicEnvironment implements IComputerEnvironment public static IMount createMount( Class klass, String path, String fallback ) { - File file = getContainingFile(klass); + File file = getContainingFile( klass ); if( file.isFile() ) { @@ -128,7 +128,7 @@ public class BasicEnvironment implements IComputerEnvironment } - private static File getContainingFile(Class klass) + private static File getContainingFile( Class klass ) { String path = klass.getProtectionDomain().getCodeSource().getLocation().getPath(); int bangIndex = path.indexOf( "!" ); diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 1f4151244..926596d90 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -42,7 +42,7 @@ public class ComputerBootstrap .addFile( "test.lua", program ) .addFile( "startup", "assertion.assert(pcall(loadfile('test.lua', _ENV))) os.shutdown()" ); - run( mount, x -> {} ); + run( mount, x -> { } ); } public static void run( IWritableMount mount, Consumer setup ) diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 24f121a2a..614b3b6b7 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -253,14 +253,14 @@ public class NetworkTest assertEquals( Sets.newHashSet(), cE.allPeripherals().keySet(), "C's peripheral set should be empty" ); } + private static final int BRUTE_SIZE = 16; + private static final int TOGGLE_CONNECTION_TIMES = 5; + private static final int TOGGLE_NODE_TIMES = 5; + @Test @Disabled( "Takes a long time to run, mostly for stress testing" ) public void testLarge() { - final int BRUTE_SIZE = 16; - final int TOGGLE_CONNECTION_TIMES = 5; - final int TOGGLE_NODE_TIMES = 5; - Grid grid = new Grid<>( BRUTE_SIZE ); grid.map( ( existing, pos ) -> new NetworkElement( null, null, "n_" + pos ).getNode() ); @@ -324,7 +324,7 @@ public class NetworkTest } } - private static class NetworkElement implements IWiredElement + private static final class NetworkElement implements IWiredElement { private final World world; private final Vec3d position; @@ -433,7 +433,7 @@ public class NetworkTest private final T[] box; @SuppressWarnings( "unchecked" ) - public Grid( int size ) + Grid( int size ) { this.size = size; this.box = (T[]) new Object[size * size * size]; From 39a9ad0ce79db8c476fc8a38515e671fad7a3f2c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 8 Jun 2019 13:36:31 +0100 Subject: [PATCH 008/711] Initial update to 1.14 So very little works, but it compiles and runs. Things to resolve over the next few days: - Horrible mappings (should largely be resolved by tomorrow). - Cannot send extra data over containers - we'll have to see what Forge does here. - Turtle models are broken - No block drops yet - this will largely be cherry-picking whatever I did on Fabric. - Weird inventory desyncs (items don't show up initially when interacting with a CC inventory). - Probably lots of other things. --- build.gradle | 10 +- gradle.properties | 6 +- .../computercraft/ComputerCraftAPIImpl.java | 6 +- .../computercraft/api/ComputerCraftAPI.java | 10 +- .../api/peripheral/IPeripheralProvider.java | 4 +- .../api/peripheral/IPeripheralTile.java | 6 +- .../api/pocket/IPocketAccess.java | 4 +- .../redstone/IBundledRedstoneProvider.java | 4 +- .../api/turtle/ITurtleAccess.java | 12 +- .../api/turtle/ITurtleUpgrade.java | 4 +- .../api/turtle/TurtleCommandResult.java | 4 +- .../computercraft/api/turtle/TurtleVerb.java | 4 +- .../api/turtle/event/TurtleAttackEvent.java | 4 +- .../api/turtle/event/TurtleBlockEvent.java | 18 +-- .../computercraft/client/ClientRegistry.java | 8 +- .../client/ClientTableFormatter.java | 10 +- .../client/gui/FixedWidthFontRenderer.java | 8 +- .../computercraft/client/gui/GuiComputer.java | 62 ++++----- .../client/gui/GuiDiskDrive.java | 28 ++--- .../client/gui/GuiPocketComputer.java | 8 +- .../computercraft/client/gui/GuiPrinter.java | 29 +++-- .../computercraft/client/gui/GuiPrintout.java | 24 ++-- .../computercraft/client/gui/GuiTurtle.java | 35 +++--- .../client/gui/widgets/WidgetTerminal.java | 27 ++-- .../client/gui/widgets/WidgetWrapper.java | 14 +-- .../proxy/ComputerCraftProxyClient.java | 56 +++------ .../client/render/CableHighlightRenderer.java | 39 +++--- .../client/render/ItemMapLikeRenderer.java | 22 ++-- .../client/render/ItemPocketRenderer.java | 6 +- .../client/render/ItemPrintoutRenderer.java | 2 +- .../client/render/ModelTransformer.java | 8 +- .../render/MonitorHighlightRenderer.java | 36 +++--- .../client/render/PrintoutRenderer.java | 10 +- .../render/TileEntityCableRenderer.java | 19 +-- .../render/TileEntityMonitorRenderer.java | 18 +-- .../render/TileEntityTurtleRenderer.java | 30 +++-- .../client/render/TurtleModelLoader.java | 12 +- .../client/render/TurtleMultiModel.java | 12 +- .../client/render/TurtleSmartItemModel.java | 12 +- .../core/computer/ComputerSide.java | 4 +- .../core/filesystem/ResourceMount.java | 4 +- .../computercraft/core/terminal/Terminal.java | 6 +- .../computercraft/shared/BundledRedstone.java | 8 +- .../computercraft/shared/Peripherals.java | 6 +- .../dan200/computercraft/shared/Registry.java | 24 ++-- .../shared/TurtlePermissions.java | 6 +- .../shared/command/CommandComputerCraft.java | 33 ++--- .../shared/command/CommandCopy.java | 8 +- .../shared/command/CommandUtils.java | 6 +- .../shared/command/Exceptions.java | 8 +- .../shared/command/UserLevel.java | 6 +- .../arguments/ArgumentSerializers.java | 4 +- .../command/arguments/RepeatArgumentType.java | 4 +- .../builder/HelpingArgumentBuilder.java | 4 +- .../shared/command/text/ChatHelpers.java | 10 +- .../command/text/ServerTableFormatter.java | 4 +- .../shared/command/text/TableBuilder.java | 4 +- .../shared/command/text/TableFormatter.java | 6 +- .../shared/common/BlockGeneric.java | 28 +++-- .../shared/common/ClientTerminal.java | 6 +- .../shared/common/ColourableRecipe.java | 23 ++-- .../shared/common/ContainerHeldItem.java | 21 ++-- .../DefaultBundledRedstoneProvider.java | 6 +- .../shared/common/IBundledRedstoneBlock.java | 6 +- .../shared/common/IColouredItem.java | 6 +- .../shared/common/ServerTerminal.java | 6 +- .../shared/common/TileGeneric.java | 40 +++--- .../shared/computer/apis/CommandAPI.java | 8 +- .../shared/computer/blocks/BlockComputer.java | 14 +-- .../computer/blocks/BlockComputerBase.java | 41 +++--- .../computer/blocks/TileCommandComputer.java | 22 ++-- .../shared/computer/blocks/TileComputer.java | 23 ++-- .../computer/blocks/TileComputerBase.java | 68 +++++----- .../shared/computer/core/ClientComputer.java | 10 +- .../computer/core/IContainerComputer.java | 4 +- .../shared/computer/core/ServerComputer.java | 24 ++-- .../computer/inventory/ContainerComputer.java | 11 +- .../inventory/ContainerViewComputer.java | 24 ++-- .../shared/computer/items/IComputerItem.java | 4 +- .../shared/computer/items/ItemComputer.java | 4 +- .../computer/items/ItemComputerBase.java | 12 +- .../recipe/ComputerConvertRecipe.java | 6 +- .../computer/recipe/ComputerFamilyRecipe.java | 6 +- .../recipe/ComputerUpgradeRecipe.java | 9 -- .../charset/BundledCapabilityProvider.java | 8 +- .../charset/BundledRedstoneProvider.java | 4 +- .../shared/integration/mcmp/MCMPHooks.java | 18 ++- .../integration/mcmp/MCMPIntegration.java | 6 +- .../integration/mcmp/PartAdvancedModem.java | 10 +- .../integration/mcmp/PartPeripheral.java | 12 +- .../shared/media/items/ItemDisk.java | 16 +-- .../shared/media/items/ItemPrintout.java | 30 ++--- .../shared/media/items/ItemTreasureDisk.java | 18 +-- .../shared/media/items/RecordMedia.java | 4 +- .../shared/media/recipes/DiskRecipe.java | 23 ++-- .../shared/media/recipes/PrintoutRecipe.java | 23 ++-- .../shared/network/Containers.java | 96 -------------- .../shared/network/NetworkHandler.java | 12 +- .../client/ComputerDataClientMessage.java | 4 +- .../client/ComputerTerminalClientMessage.java | 6 +- .../client/PlayRecordClientMessage.java | 4 +- .../network/container/ContainerData.java | 41 ++++++ .../network/container/ContainerType.java | 104 --------------- .../PocketComputerContainerData.java | 57 +++++++++ .../PocketComputerContainerType.java | 55 -------- .../container/PrintoutContainerData.java | 57 +++++++++ .../container/PrintoutContainerType.java | 55 -------- .../container/TileEntityContainerType.java | 114 ----------------- ...pe.java => ViewComputerContainerData.java} | 50 +++++--- .../server/QueueEventServerMessage.java | 4 +- .../commandblock/CommandBlockPeripheral.java | 6 +- .../peripheral/diskdrive/BlockDiskDrive.java | 22 ++-- .../diskdrive/ContainerDiskDrive.java | 36 +++--- .../peripheral/diskdrive/TileDiskDrive.java | 73 ++++++----- .../shared/peripheral/modem/ModemShapes.java | 4 +- .../peripheral/modem/wired/BlockCable.java | 117 ++++++++--------- .../modem/wired/BlockWiredModemFull.java | 4 +- .../modem/wired/CableModemVariant.java | 60 ++++----- .../peripheral/modem/wired/CableShapes.java | 36 +++--- .../modem/wired/ItemBlockCable.java | 36 +++--- .../peripheral/modem/wired/TileCable.java | 57 +++++---- .../modem/wired/TileWiredModemFull.java | 45 +++---- .../wired/WiredModemLocalPeripheral.java | 12 +- .../modem/wireless/BlockWirelessModem.java | 53 +++----- .../modem/wireless/TileWirelessModem.java | 16 +-- .../wireless/WirelessModemPeripheral.java | 2 +- .../peripheral/monitor/BlockMonitor.java | 30 ++--- .../peripheral/monitor/ClientMonitor.java | 2 +- .../peripheral/monitor/TileMonitor.java | 62 +++++---- .../shared/peripheral/monitor/XYPair.java | 4 +- .../peripheral/printer/BlockPrinter.java | 22 ++-- .../peripheral/printer/ContainerPrinter.java | 104 +++++++-------- .../peripheral/printer/TilePrinter.java | 74 ++++++----- .../peripheral/speaker/BlockSpeaker.java | 10 +- .../peripheral/speaker/SpeakerPeripheral.java | 4 +- .../peripheral/speaker/TileSpeaker.java | 12 +- .../shared/pocket/apis/PocketAPI.java | 16 +-- .../pocket/core/PocketServerComputer.java | 32 ++--- .../inventory/ContainerPocketComputer.java | 15 ++- .../pocket/items/ItemPocketComputer.java | 40 +++--- .../recipes/PocketComputerUpgradeRecipe.java | 18 ++- .../proxy/ComputerCraftProxyCommon.java | 45 ++++--- .../shared/turtle/FurnaceRefuelHandler.java | 4 +- .../shared/turtle/blocks/BlockTurtle.java | 66 ++++------ .../shared/turtle/blocks/TileTurtle.java | 68 +++++----- .../shared/turtle/core/InteractDirection.java | 8 +- .../shared/turtle/core/MoveDirection.java | 8 +- .../shared/turtle/core/TurtleBrain.java | 74 +++++------ .../turtle/core/TurtleCompareCommand.java | 16 +-- .../turtle/core/TurtleDetectCommand.java | 4 +- .../shared/turtle/core/TurtleDropCommand.java | 6 +- .../turtle/core/TurtleInspectCommand.java | 8 +- .../shared/turtle/core/TurtleMoveCommand.java | 24 ++-- .../turtle/core/TurtlePlaceCommand.java | 94 +++++++------- .../shared/turtle/core/TurtlePlayer.java | 118 +++--------------- .../shared/turtle/core/TurtleSuckCommand.java | 14 +-- .../turtle/inventory/ContainerTurtle.java | 91 ++++---------- .../shared/turtle/items/ItemTurtle.java | 30 ++--- .../shared/turtle/recipes/TurtleRecipe.java | 9 -- .../turtle/recipes/TurtleUpgradeRecipe.java | 17 ++- .../turtle/upgrades/TurtleCraftingTable.java | 2 +- .../shared/turtle/upgrades/TurtleHoe.java | 10 +- .../upgrades/TurtleInventoryCrafting.java | 35 ++---- .../shared/turtle/upgrades/TurtleModem.java | 8 +- .../shared/turtle/upgrades/TurtleShovel.java | 15 ++- .../shared/turtle/upgrades/TurtleSword.java | 8 +- .../shared/turtle/upgrades/TurtleTool.java | 20 +-- .../shared/util/AbstractRecipe.java | 43 ------- .../shared/util/ColourTracker.java | 4 +- .../shared/util/ColourUtils.java | 6 +- .../shared/util/DefaultInteractionObject.java | 32 ----- .../shared/util/DefaultInventory.java | 38 +----- .../shared/util/DefaultSidedInventory.java | 6 +- .../shared/util/DirectionUtil.java | 12 +- .../shared/util/DropConsumer.java | 14 +-- .../computercraft/shared/util/IDAssigner.java | 2 +- .../shared/util/ImpostorRecipe.java | 24 ++-- .../shared/util/ImpostorShapelessRecipe.java | 24 ++-- .../shared/util/InventoryUtil.java | 12 +- .../computercraft/shared/util/NBTUtil.java | 44 +++---- ...tityType.java => NamedTileEntityType.java} | 37 ++++-- .../computercraft/shared/util/Palette.java | 6 +- .../computercraft/shared/util/RecipeUtil.java | 12 +- .../computercraft/shared/util/RecordUtil.java | 8 +- .../shared/util/RedstoneUtil.java | 8 +- .../shared/util/SingleIntArray.java | 33 +++++ .../shared/util/ValidatingSlot.java | 2 +- .../shared/util/WaterloggableBlock.java | 99 --------------- .../shared/util/WaterloggableHelpers.java | 62 +++++++++ .../computercraft/shared/util/WorldUtil.java | 74 ++++++----- .../shared/wired/CapabilityWiredElement.java | 8 +- .../resources/META-INF/accesstransformer.cfg | 7 +- src/main/resources/META-INF/mods.toml | 4 +- .../recipes/generated/disk/disk_1.json | 2 +- .../recipes/generated/disk/disk_12.json | 2 +- .../recipes/generated/disk/disk_16.json | 2 +- .../recipes/generated/disk/disk_2.json | 2 +- .../recipes/generated/disk/disk_3.json | 2 +- .../recipes/generated/disk/disk_4.json | 2 +- .../recipes/generated/disk/disk_5.json | 2 +- .../shared/wired/NetworkTest.java | 4 +- tools/recipes.lua | 14 +-- 202 files changed, 2006 insertions(+), 2522 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/shared/network/Containers.java create mode 100644 src/main/java/dan200/computercraft/shared/network/container/ContainerData.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/container/ContainerType.java create mode 100644 src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java create mode 100644 src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java rename src/main/java/dan200/computercraft/shared/network/container/{ViewComputerContainerType.java => ViewComputerContainerData.java} (54%) delete mode 100644 src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java delete mode 100644 src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java rename src/main/java/dan200/computercraft/shared/util/{NamedBlockEntityType.java => NamedTileEntityType.java} (58%) create mode 100644 src/main/java/dan200/computercraft/shared/util/SingleIntArray.java delete mode 100644 src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java create mode 100644 src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java diff --git a/build.gradle b/build.gradle index b91b7b776..7f8f4cc7c 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.117' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.128' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } @@ -98,7 +98,7 @@ dependencies { // deobfProvided "pl.asie:Charset-Lib:0.5.4.6" // deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" - runtimeOnly fg.deobf("mezz.jei:jei-1.13.2:5.0.0.20") + // runtimeOnly fg.deobf("mezz.jei:jei-1.13.2:5.0.0.20") shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' @@ -127,7 +127,7 @@ jar { manifest { attributes(["Specification-Title": "computercraft", "Specification-Vendor": "SquidDev", - "Specification-Version": "25.0", + "Specification-Version": "26.0", "Implementation-Title": "CC: Tweaked", "Implementation-Version": "${mod_version}", "Implementation-Vendor" :"SquidDev", @@ -355,7 +355,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'release' + releaseType = 'beta' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { @@ -431,7 +431,7 @@ githubRelease { .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() } - prerelease false + prerelease true } def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] diff --git a/gradle.properties b/gradle.properties index ba8ad0fed..75c81b3d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.83.1 # Minecraft properties -mc_version=1.13.2 -forge_version=25.0.219 -mappings_version=20190530-1.13.2 +mc_version=1.14.2 +forge_version=26.0.5 +mappings_version=20190608-1.14.2 diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 14ac6ea84..938c63cd9 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -26,7 +26,7 @@ import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.wired.CapabilityWiredElement; import dan200.computercraft.shared.wired.WiredNode; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; @@ -94,7 +94,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI } @Override - public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return BundledRedstone.getDefaultOutput( world, pos, side ); } @@ -133,7 +133,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI @Nonnull @Override - public LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side ) { TileEntity tile = world.getTileEntity( pos ); return tile == null ? LazyOptional.empty() : tile.getCapability( CapabilityWiredElement.CAPABILITY, side ); diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 8570d676e..65ea0aaae 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -20,7 +20,7 @@ import dan200.computercraft.api.peripheral.IPeripheralProvider; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; @@ -183,7 +183,7 @@ public final class ComputerCraftAPI * If there is no block capable of emitting bundled redstone at the location, -1 will be returned. * @see IBundledRedstoneProvider */ - public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public static int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return getInstance().getBundledRedstoneOutput( world, pos, side ); } @@ -242,7 +242,7 @@ public final class ComputerCraftAPI * @see IWiredElement#getNode() */ @Nonnull - public static LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public static LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return getInstance().getWiredElementAt( world, pos, side ); } @@ -284,7 +284,7 @@ public final class ComputerCraftAPI void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider ); - int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ); + int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); void registerMediaProvider( @Nonnull IMediaProvider provider ); @@ -299,6 +299,6 @@ public final class ComputerCraftAPI IWiredNode createWiredNodeForElement( @Nonnull IWiredElement element ); @Nonnull - LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ); + LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side ); } } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index 0c39e83cf..aef586157 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -7,7 +7,7 @@ package dan200.computercraft.api.peripheral; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -34,5 +34,5 @@ public interface IPeripheralProvider * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ @Nullable - IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ); + IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java index 55e5a5c3f..accc87bef 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.api.peripheral; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -25,8 +25,8 @@ public interface IPeripheralTile * * @param side The side to get the peripheral from. * @return A peripheral, or {@code null} if there is not a peripheral here. - * @see IPeripheralProvider#getPeripheral(World, BlockPos, EnumFacing) + * @see IPeripheralProvider#getPeripheral(World, BlockPos, Direction) */ @Nullable - IPeripheral getPeripheral( @Nonnull EnumFacing side ); + IPeripheral getPeripheral( @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index beeda54fe..5ee079342 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -8,7 +8,7 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.entity.Entity; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; @@ -75,7 +75,7 @@ public interface IPocketAccess * @see #updateUpgradeNBTData() */ @Nonnull - NBTTagCompound getUpgradeNBTData(); + CompoundNBT getUpgradeNBTData(); /** * Mark the upgrade-specific NBT as dirty. diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index ee98f9958..2b29fd695 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -6,7 +6,7 @@ package dan200.computercraft.api.redstone; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -30,5 +30,5 @@ public interface IBundledRedstoneProvider * handle this block. * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) */ - int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ); + int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 1c29fd097..7d9b80721 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -11,8 +11,8 @@ import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.inventory.IInventory; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -83,10 +83,10 @@ public interface ITurtleAccess * Returns the world direction the turtle is currently facing. * * @return The world direction the turtle is currently facing. - * @see #setDirection(EnumFacing) + * @see #setDirection(Direction) */ @Nonnull - EnumFacing getDirection(); + Direction getDirection(); /** * Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to @@ -95,7 +95,7 @@ public interface ITurtleAccess * @param dir The new direction to set. This should be on either the x or z axis (so north, south, east or west). * @see #getDirection() */ - void setDirection( @Nonnull EnumFacing dir ); + void setDirection( @Nonnull Direction dir ); /** * Get the currently selected slot in the turtle's inventory. @@ -290,7 +290,7 @@ public interface ITurtleAccess * @see #updateUpgradeNBTData(TurtleSide) */ @Nonnull - NBTTagCompound getUpgradeNBTData( @Nullable TurtleSide side ); + CompoundNBT getUpgradeNBTData( @Nullable TurtleSide side ); /** * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index bfbe36a45..e36f9230a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -13,7 +13,7 @@ import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -113,7 +113,7 @@ public interface ITurtleUpgrade * to be called. */ @Nonnull - default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing direction ) + default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) { return TurtleCommandResult.failure(); } diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java index 795513cc9..f9263e09d 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -6,7 +6,7 @@ package dan200.computercraft.api.turtle; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -15,7 +15,7 @@ import javax.annotation.Nullable; * Used to indicate the result of executing a turtle command. * * @see ITurtleCommand#execute(ITurtleAccess) - * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing) + * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction) */ public final class TurtleCommandResult { diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index cf8e6b086..9110a5155 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -6,14 +6,14 @@ package dan200.computercraft.api.turtle; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; /** * An enum representing the different actions that an {@link ITurtleUpgrade} of type Tool may be called on to perform by * a turtle. * * @see ITurtleUpgrade#getType() - * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing) + * @see ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction) */ public enum TurtleVerb { diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java index de95a7d8f..65cb27793 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java @@ -11,7 +11,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import net.minecraft.entity.Entity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraftforge.common.util.FakePlayer; import net.minecraftforge.event.entity.player.AttackEntityEvent; @@ -21,7 +21,7 @@ import java.util.Objects; /** * Fired when a turtle attempts to attack an entity. * - * This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)}, + * This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)}, * as the base {@code turtle.attack()} command does not fire it. * * Note that such commands should also fire {@link AttackEntityEvent}, so you do not need to listen to both. diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index 036075795..930c90325 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -12,9 +12,9 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.util.FakePlayer; @@ -75,7 +75,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent /** * Fired when a turtle attempts to dig a block. * - * This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, EnumFacing)}, + * This must be fired by {@link ITurtleUpgrade#useTool(ITurtleAccess, TurtleSide, TurtleVerb, Direction)}, * as the base {@code turtle.dig()} command does not fire it. * * Note that such commands should also fire {@link BlockEvent.BreakEvent}, so you do not need to listen to both. @@ -84,11 +84,11 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent */ public static class Dig extends TurtleBlockEvent { - private final IBlockState block; + private final BlockState block; private final ITurtleUpgrade upgrade; private final TurtleSide side; - public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState block, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side ) + public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState block, @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side ) { super( turtle, TurtleAction.DIG, player, world, pos ); @@ -106,7 +106,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent * @return The block which is going to be broken. */ @Nonnull - public IBlockState getBlock() + public BlockState getBlock() { return block; } @@ -185,10 +185,10 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent */ public static class Inspect extends TurtleBlockEvent { - private final IBlockState state; + private final BlockState state; private final Map data; - public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Map data ) + public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull Map data ) { super( turtle, TurtleAction.INSPECT, player, world, pos ); @@ -204,7 +204,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent * @return The inspected block state. */ @Nonnull - public IBlockState getState() + public BlockState getState() { return state; } diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 48bd06443..d32af07ff 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -16,7 +16,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.client.renderer.model.ModelRotation; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; @@ -25,6 +24,7 @@ import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.client.model.BasicState; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -82,7 +82,7 @@ public final class ClientRegistry IResourceManager manager = Minecraft.getInstance().getResourceManager(); for( String extra : EXTRA_TEXTURES ) { - event.getMap().registerSprite( manager, new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); + // TODO: event.getMap().registerSprite( manager, new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); } } @@ -160,9 +160,9 @@ public final class ClientRegistry model.getTextures( loader::getUnbakedModel, new HashSet<>() ); return model.bake( - loader::getUnbakedModel, + loader, ModelLoader.defaultTextureGetter(), - ModelRotation.X0_Y0, false, DefaultVertexFormats.BLOCK + new BasicState( model.getDefaultState(), false ), DefaultVertexFormats.BLOCK ); } } diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 1445cd87d..888bf6ad3 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -12,8 +12,8 @@ import dan200.computercraft.shared.command.text.TableFormatter; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; -import net.minecraft.client.gui.GuiNewChat; -import net.minecraft.client.gui.GuiUtilRenderComponents; +import net.minecraft.client.gui.NewChatGui; +import net.minecraft.client.gui.RenderComponentsUtil; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextFormatting; @@ -65,18 +65,18 @@ public class ClientTableFormatter implements TableFormatter public void writeLine( int id, ITextComponent component ) { Minecraft mc = Minecraft.getInstance(); - GuiNewChat chat = mc.ingameGUI.getChatGUI(); + NewChatGui chat = mc.field_71456_v.getChatGUI(); // ingameGUI // Trim the text if it goes over the allowed length int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); - List list = GuiUtilRenderComponents.splitText( component, maxWidth, mc.fontRenderer, false, false ); + List list = RenderComponentsUtil.splitText( component, maxWidth, mc.fontRenderer, false, false ); if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); } @Override public int display( TableBuilder table ) { - GuiNewChat chat = Minecraft.getInstance().ingameGUI.getChatGUI(); + NewChatGui chat = Minecraft.getInstance().field_71456_v.getChatGUI(); int lastHeight = lastHeights.get( table.getId() ); diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index b2e22db05..3903d1e32 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -6,11 +6,11 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -129,9 +129,9 @@ public final class FixedWidthFontRenderer } drawQuad( renderer, x + i * FONT_WIDTH, y, colour, FONT_WIDTH, p, greyScale ); } - GlStateManager.disableTexture2D(); + GlStateManager.disableTexture(); tessellator.draw(); - GlStateManager.enableTexture2D(); + GlStateManager.enableTexture(); } public void drawStringTextPart( int x, int y, TextBuffer s, TextBuffer textColour, boolean greyScale, Palette p ) @@ -195,6 +195,6 @@ public final class FixedWidthFontRenderer public void bindFont() { m_textureManager.bindTexture( FONT ); - GlStateManager.texParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + GlStateManager.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 097c4c28e..f23162d81 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -6,19 +6,22 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.inventory.Container; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; -public class GuiComputer extends GuiContainer +public class GuiComputer extends ContainerScreen { public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); @@ -33,9 +36,12 @@ public class GuiComputer extends GuiContainer private WidgetTerminal terminal; private WidgetWrapper terminalWrapper; - public GuiComputer( Container container, ComputerFamily family, ClientComputer computer, int termWidth, int termHeight ) + public GuiComputer( + T container, PlayerInventory player, ITextComponent title, + ComputerFamily family, ClientComputer computer, int termWidth, int termHeight + ) { - super( container ); + super( container, player, title ); m_family = family; m_computer = computer; m_termWidth = termWidth; @@ -43,10 +49,10 @@ public class GuiComputer extends GuiContainer terminal = null; } - public GuiComputer( TileComputer computer ) + public static GuiComputer create( int id, TileComputer computer, PlayerInventory inventory, ITextComponent component ) { - this( - new ContainerComputer( computer ), + return new GuiComputer<>( + new ContainerComputer( id, computer ), inventory, component, computer.getFamily(), computer.createClientComputer(), ComputerCraft.terminalWidth_computer, @@ -55,9 +61,9 @@ public class GuiComputer extends GuiContainer } @Override - protected void initGui() + protected void init() { - mc.keyboardListener.enableRepeatEvents( true ); + minecraft.keyboardListener.enableRepeatEvents( true ); int termPxWidth = m_termWidth * FixedWidthFontRenderer.FONT_WIDTH; int termPxHeight = m_termHeight * FixedWidthFontRenderer.FONT_HEIGHT; @@ -65,9 +71,9 @@ public class GuiComputer extends GuiContainer xSize = termPxWidth + 4 + 24; ySize = termPxHeight + 4 + 24; - super.initGui(); + super.init(); - terminal = new WidgetTerminal( mc, () -> m_computer, m_termWidth, m_termHeight, 2, 2, 2, 2 ); + terminal = new WidgetTerminal( minecraft, () -> m_computer, m_termWidth, m_termHeight, 2, 2, 2, 2 ); terminalWrapper = new WidgetWrapper( terminal, 2 + 12 + guiLeft, 2 + 12 + guiTop, termPxWidth, termPxHeight ); children.add( terminalWrapper ); @@ -75,12 +81,12 @@ public class GuiComputer extends GuiContainer } @Override - public void onGuiClosed() + public void removed() { - super.onGuiClosed(); + super.removed(); children.remove( terminal ); terminal = null; - mc.keyboardListener.enableRepeatEvents( false ); + minecraft.keyboardListener.enableRepeatEvents( false ); } @Override @@ -108,32 +114,32 @@ public class GuiComputer extends GuiContainer { case Normal: default: - mc.getTextureManager().bindTexture( BACKGROUND_NORMAL ); + minecraft.getTextureManager().bindTexture( BACKGROUND_NORMAL ); break; case Advanced: - mc.getTextureManager().bindTexture( BACKGROUND_ADVANCED ); + minecraft.getTextureManager().bindTexture( BACKGROUND_ADVANCED ); break; case Command: - mc.getTextureManager().bindTexture( BACKGROUND_COMMAND ); + minecraft.getTextureManager().bindTexture( BACKGROUND_COMMAND ); break; } - drawTexturedModalRect( startX - 12, startY - 12, 12, 28, 12, 12 ); - drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 12 ); - drawTexturedModalRect( endX, startY - 12, 24, 28, 12, 12 ); - drawTexturedModalRect( endX, endY, 24, 40, 12, 12 ); + blit( startX - 12, startY - 12, 12, 28, 12, 12 ); + blit( startX - 12, endY, 12, 40, 12, 12 ); + blit( endX, startY - 12, 24, 28, 12, 12 ); + blit( endX, endY, 24, 40, 12, 12 ); - drawTexturedModalRect( startX, startY - 12, 0, 0, endX - startX, 12 ); - drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 12 ); + blit( startX, startY - 12, 0, 0, endX - startX, 12 ); + blit( startX, endY, 0, 12, endX - startX, 12 ); - drawTexturedModalRect( startX - 12, startY, 0, 28, 12, endY - startY ); - drawTexturedModalRect( endX, startY, 36, 28, 12, endY - startY ); + blit( startX - 12, startY, 0, 28, 12, endY - startY ); + blit( endX, startY, 36, 28, 12, endY - startY ); } @Override public void render( int mouseX, int mouseY, float partialTicks ) { - drawDefaultBackground(); + renderBackground(); super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index ab4284839..c3cc55347 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -6,44 +6,42 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.resources.I18n; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; -public class GuiDiskDrive extends GuiContainer +public class GuiDiskDrive extends ContainerScreen { private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" ); - private final ContainerDiskDrive m_container; - - public GuiDiskDrive( ContainerDiskDrive container ) + public GuiDiskDrive( ContainerDiskDrive container, PlayerInventory player, ITextComponent title ) { - super( container ); - m_container = container; + super( container, player, title ); } @Override protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY ) { - String title = m_container.getDiskDrive().getDisplayName().getString(); - fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2.0f, 6, 0x404040 ); - fontRenderer.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 ); + String title = this.title.getFormattedText(); + font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 ); + font.drawString( title, 8, ySize - 96 + 2, 0x404040 ); } @Override protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); - mc.getTextureManager().bindTexture( BACKGROUND ); - drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize ); + minecraft.getTextureManager().bindTexture( BACKGROUND ); + blit( guiLeft, guiTop, 0, 0, xSize, ySize ); } @Override public void render( int mouseX, int mouseY, float partialTicks ) { - drawDefaultBackground(); + renderBackground(); super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java index e3781ae96..a075e1d5f 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java @@ -10,15 +10,17 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; -public class GuiPocketComputer extends GuiComputer +public class GuiPocketComputer extends GuiComputer { - public GuiPocketComputer( ContainerPocketComputer container ) + public GuiPocketComputer( ContainerPocketComputer container, PlayerInventory player, ITextComponent title ) { super( - container, + container, player, title, getFamily( container.getStack() ), ItemPocketComputer.createClientComputer( container.getStack() ), ComputerCraft.terminalWidth_pocketComputer, diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index 80e146f52..e00387d4d 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -6,46 +6,45 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.resources.I18n; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; -public class GuiPrinter extends GuiContainer +public class GuiPrinter extends ContainerScreen { private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printer.png" ); - private final ContainerPrinter container; - - public GuiPrinter( ContainerPrinter container ) + public GuiPrinter( ContainerPrinter container, PlayerInventory player, ITextComponent title ) { - super( container ); - this.container = container; + super( container, player, title ); } @Override protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY ) { - String title = container.getPrinter().getDisplayName().getString(); - fontRenderer.drawString( title, (xSize - fontRenderer.getStringWidth( title )) / 2.0f, 6, 0x404040 ); - fontRenderer.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 ); + String title = getTitle().getFormattedText(); + font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 ); + font.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 ); } @Override protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); - mc.getTextureManager().bindTexture( BACKGROUND ); - drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize ); + minecraft.getTextureManager().bindTexture( BACKGROUND ); + blit( guiLeft, guiTop, 0, 0, xSize, ySize ); - if( container.isPrinting() ) drawTexturedModalRect( guiLeft + 34, guiTop + 21, 176, 0, 25, 45 ); + if( getContainer().isPrinting() ) blit( guiLeft + 34, guiTop + 21, 176, 0, 25, 45 ); } @Override public void render( int mouseX, int mouseY, float partialTicks ) { - drawDefaultBackground(); + renderBackground(); super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index f1349bc74..c4dd204f7 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -6,16 +6,18 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; import static dan200.computercraft.client.render.PrintoutRenderer.*; -public class GuiPrintout extends GuiContainer +public class GuiPrintout extends ContainerScreen { private final boolean m_book; private final int m_pages; @@ -23,9 +25,9 @@ public class GuiPrintout extends GuiContainer private final TextBuffer[] m_colours; private int m_page; - public GuiPrintout( ContainerHeldItem container ) + public GuiPrintout( ContainerHeldItem container, PlayerInventory player, ITextComponent title ) { - super( container ); + super( container, player, title ); ySize = Y_SIZE; @@ -63,9 +65,9 @@ public class GuiPrintout extends GuiContainer } @Override - public boolean mouseScrolled( double delta ) + public boolean mouseScrolled( double x, double y, double delta ) { - if( super.mouseScrolled( delta ) ) return true; + if( super.mouseScrolled( x, y, delta ) ) return true; if( delta < 0 ) { // Scroll up goes to the next page @@ -90,7 +92,7 @@ public class GuiPrintout extends GuiContainer GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.enableDepthTest(); - drawBorder( guiLeft, guiTop, zLevel, m_page, m_pages, m_book ); + drawBorder( guiLeft, guiTop, blitOffset, m_page, m_pages, m_book ); drawText( guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); } @@ -98,9 +100,9 @@ public class GuiPrintout extends GuiContainer public void render( int mouseX, int mouseY, float partialTicks ) { // We must take the background further back in order to not overlap with our printed pages. - zLevel--; - drawDefaultBackground(); - zLevel++; + blitOffset--; + renderBackground(); + blitOffset++; super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 496d8b576..cdbdd28b9 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; @@ -13,11 +14,12 @@ import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; -public class GuiTurtle extends GuiContainer +public class GuiTurtle extends ContainerScreen { private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" ); private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" ); @@ -30,9 +32,9 @@ public class GuiTurtle extends GuiContainer private WidgetTerminal terminal; private WidgetWrapper terminalWrapper; - public GuiTurtle( TileTurtle turtle, ContainerTurtle container ) + public GuiTurtle( TileTurtle turtle, ContainerTurtle container, PlayerInventory player, ITextComponent title ) { - super( container ); + super( container, player, title ); m_container = container; m_family = turtle.getFamily(); @@ -43,16 +45,16 @@ public class GuiTurtle extends GuiContainer } @Override - protected void initGui() + protected void init() { - super.initGui(); - mc.keyboardListener.enableRepeatEvents( true ); + super.init(); + minecraft.keyboardListener.enableRepeatEvents( true ); int termPxWidth = ComputerCraft.terminalWidth_turtle * FixedWidthFontRenderer.FONT_WIDTH; int termPxHeight = ComputerCraft.terminalHeight_turtle * FixedWidthFontRenderer.FONT_HEIGHT; terminal = new WidgetTerminal( - mc, () -> m_computer, + minecraft, () -> m_computer, ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle, 2, 2, 2, 2 @@ -64,11 +66,12 @@ public class GuiTurtle extends GuiContainer } @Override - public void onGuiClosed() + public void removed() { + super.removed(); children.remove( terminal ); terminal = null; - mc.keyboardListener.enableRepeatEvents( false ); + minecraft.keyboardListener.enableRepeatEvents( false ); } @Override @@ -87,8 +90,8 @@ public class GuiTurtle extends GuiContainer GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); int slotX = slot % 4; int slotY = slot / 4; - mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - drawTexturedModalRect( guiLeft + m_container.turtleInvStartX - 2 + slotX * 18, guiTop + m_container.playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 ); + minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); + blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 ); } } @@ -101,8 +104,8 @@ public class GuiTurtle extends GuiContainer // Draw border/inventory GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); - mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - drawTexturedModalRect( guiLeft, guiTop, 0, 0, xSize, ySize ); + minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); + blit( guiLeft, guiTop, 0, 0, xSize, ySize ); drawSelectionSlot( advanced ); } @@ -110,7 +113,7 @@ public class GuiTurtle extends GuiContainer @Override public void render( int mouseX, int mouseY, float partialTicks ) { - drawDefaultBackground(); + renderBackground(); super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 3f75ccbe3..72640661e 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.gui.widgets; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; @@ -17,7 +18,6 @@ import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.IGuiEventListener; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.SharedConstants; @@ -35,6 +35,8 @@ public class WidgetTerminal implements IGuiEventListener private final Minecraft client; + private boolean focused; + private final Supplier computer; private final int termWidth; private final int termHeight; @@ -250,14 +252,23 @@ public class WidgetTerminal implements IGuiEventListener } @Override - public boolean mouseScrolled( double delta ) + public boolean mouseScrolled( double mouseX, double mouseY, double delta ) { ClientComputer computer = this.computer.get(); - if( computer == null || !computer.isColour() ) return false; + if( computer == null || !computer.isColour() || delta == 0 ) return false; - if( lastMouseX >= 0 && lastMouseY >= 0 && delta != 0 ) + Terminal term = computer.getTerminal(); + if( term != null ) { - queueEvent( "mouse_scroll", delta < 0 ? 1 : -1, lastMouseX + 1, lastMouseY + 1 ); + int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); + int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); + + computer.mouseScroll( delta < 0 ? 1 : -1, charX + 1, charY + 1 ); + + lastMouseX = charX; + lastMouseY = charY; } return true; @@ -284,9 +295,9 @@ public class WidgetTerminal implements IGuiEventListener } @Override - public void focusChanged( boolean focused ) + public boolean changeFocus( boolean reversed ) { - if( !focused ) + if( focused ) { // When blurring, we should make all keys go up for( int key = 0; key < keysDown.size(); key++ ) @@ -305,6 +316,8 @@ public class WidgetTerminal implements IGuiEventListener shutdownTimer = terminateTimer = rebootTimer = -1; } + focused = !focused; + return true; } public void draw( int originX, int originY ) diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java index b657983a0..fed1e086b 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java @@ -26,15 +26,9 @@ public class WidgetWrapper implements IGuiEventListener } @Override - public void focusChanged( boolean b ) + public boolean changeFocus( boolean b ) { - listener.focusChanged( b ); - } - - @Override - public boolean canFocus() - { - return listener.canFocus(); + return listener.changeFocus( b ); } @Override @@ -59,9 +53,9 @@ public class WidgetWrapper implements IGuiEventListener } @Override - public boolean mouseScrolled( double delta ) + public boolean mouseScrolled( double x, double y, double delta ) { - return listener.mouseScrolled( delta ); + return listener.mouseScrolled( x, y, delta ); } @Override diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 39a6ccbb8..28f2affbc 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -7,33 +7,29 @@ package dan200.computercraft.client.proxy; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.client.gui.*; +import dan200.computercraft.client.gui.GuiDiskDrive; +import dan200.computercraft.client.gui.GuiPocketComputer; +import dan200.computercraft.client.gui.GuiPrinter; +import dan200.computercraft.client.gui.GuiPrintout; import dan200.computercraft.client.render.TileEntityCableRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; -import dan200.computercraft.shared.computer.blocks.TileComputer; -import dan200.computercraft.shared.computer.core.ClientComputer; -import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import dan200.computercraft.shared.network.container.*; +import dan200.computercraft.shared.common.ContainerHeldItem; +import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.modem.wired.TileCable; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; +import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.client.gui.ScreenManager; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ExtensionPoint; -import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import java.util.function.BiFunction; - @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class ComputerCraftProxyClient { @@ -50,35 +46,11 @@ public final class ComputerCraftProxyClient private static void registerContainers() { - ContainerType.registerGui( TileEntityContainerType::computer, ( packet, player ) -> - new GuiComputer( (TileComputer) packet.getTileEntity( player ) ) ); - ContainerType.registerGui( TileEntityContainerType::diskDrive, GuiDiskDrive::new ); - ContainerType.registerGui( TileEntityContainerType::printer, GuiPrinter::new ); - ContainerType.registerGui( TileEntityContainerType::turtle, ( packet, player ) -> { - TileTurtle turtle = (TileTurtle) packet.getTileEntity( player ); - return new GuiTurtle( turtle, new ContainerTurtle( player.inventory, turtle.getAccess(), turtle.getClientComputer() ) ); - } ); - - ContainerType.registerGui( PocketComputerContainerType::new, GuiPocketComputer::new ); - ContainerType.registerGui( PrintoutContainerType::new, GuiPrintout::new ); - ContainerType.registerGui( ViewComputerContainerType::new, ( packet, player ) -> { - ClientComputer computer = ComputerCraft.clientComputerRegistry.get( packet.instanceId ); - if( computer == null ) - { - ComputerCraft.clientComputerRegistry.add( packet.instanceId, computer = new ClientComputer( packet.instanceId ) ); - } - - ContainerViewComputer container = new ContainerViewComputer( computer ); - return new GuiComputer( container, packet.family, computer, packet.width, packet.height ); - } ); - - ModLoadingContext.get().registerExtensionPoint( ExtensionPoint.GUIFACTORY, () -> packet -> { - ContainerType type = ContainerType.factories.get( packet.getId() ).get(); - if( packet.getAdditionalData() != null ) type.fromBytes( packet.getAdditionalData() ); - @SuppressWarnings( "unchecked" ) - BiFunction, EntityPlayer, GuiContainer> factory = (BiFunction, EntityPlayer, GuiContainer>) ContainerType.guiFactories.get( packet.getId() ); - return factory.apply( type, Minecraft.getInstance().player ); - } ); + ScreenManager.registerFactory( ContainerPrinter.TYPE, GuiPrinter::new ); + ScreenManager.registerFactory( ContainerDiskDrive.TYPE, GuiDiskDrive::new ); + ScreenManager.registerFactory( ContainerPocketComputer.TYPE, GuiPocketComputer::new ); + ScreenManager.registerFactory( ContainerHeldItem.PRINTOUT_TYPE, GuiPrintout::new ); + // TODO: ScreenManager.registerFactory( ContainerViewComputer.TYPE, GuiComputer::new ); } @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index b6f06fd35..f298a722b 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -6,17 +6,20 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; @@ -36,17 +39,19 @@ public final class CableHighlightRenderer * Draw an outline for a specific part of a cable "Multipart". * * @param event The event to observe - * @see WorldRenderer#drawSelectionBox(EntityPlayer, RayTraceResult, int, float) + * @see WorldRenderer#drawSelectionBox(PlayerEntity, RayTraceResult, int, float) */ @SubscribeEvent public static void drawHighlight( DrawBlockHighlightEvent event ) { - if( event.getTarget().type != RayTraceResult.Type.BLOCK ) return; + if( event.getTarget().getType() != RayTraceResult.Type.BLOCK ) return; - BlockPos pos = event.getTarget().getBlockPos(); - World world = event.getPlayer().getEntityWorld(); + BlockRayTraceResult hit = (BlockRayTraceResult) event.getTarget(); + BlockPos pos = hit.getPos(); + World world = event.getInfo().func_216773_g().getEntityWorld(); + ActiveRenderInfo info = event.getInfo(); - IBlockState state = world.getBlockState( pos ); + BlockState state = world.getBlockState( pos ); // We only care about instances with both cable and modem. if( state.getBlock() != ComputerCraft.Blocks.cable || state.get( BlockCable.MODEM ).getFacing() == null || !state.get( BlockCable.CABLE ) ) @@ -56,33 +61,31 @@ public final class CableHighlightRenderer event.setCanceled( true ); - EntityPlayer player = event.getPlayer(); Minecraft mc = Minecraft.getInstance(); - float partialTicks = event.getPartialTicks(); GlStateManager.enableBlend(); GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); GlStateManager.lineWidth( Math.max( 2.5F, mc.mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) ); - GlStateManager.disableTexture2D(); + GlStateManager.disableTexture(); GlStateManager.depthMask( false ); GlStateManager.matrixMode( GL11.GL_PROJECTION ); GlStateManager.pushMatrix(); GlStateManager.scalef( 1.0F, 1.0F, 0.999F ); - double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks; - double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks; - double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks; - - VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), event.getTarget().hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); - WorldRenderer.drawShape( shape, pos.getX() - x, pos.getY() - y, pos.getZ() - z, 0.0F, 0.0F, 0.0F, 0.4F ); + Vec3d cameraPos = info.func_216785_c(); + WorldRenderer.drawShape( + shape, pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ(), + 0.0F, 0.0F, 0.0F, 0.4F + ); GlStateManager.popMatrix(); GlStateManager.matrixMode( GL11.GL_MODELVIEW ); GlStateManager.depthMask( true ); - GlStateManager.enableTexture2D(); + GlStateManager.enableTexture(); GlStateManager.disableBlend(); } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index a9226a71e..7d30dac00 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -6,13 +6,13 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.FirstPersonRenderer; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; -import net.minecraft.util.EnumHandSide; +import net.minecraft.util.Hand; +import net.minecraft.util.HandSide; import net.minecraft.util.math.MathHelper; public abstract class ItemMapLikeRenderer @@ -25,19 +25,19 @@ public abstract class ItemMapLikeRenderer */ protected abstract void renderItem( ItemStack stack ); - protected void renderItemFirstPerson( EnumHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) + protected void renderItemFirstPerson( Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) { - EntityPlayer player = Minecraft.getInstance().player; + PlayerEntity player = Minecraft.getInstance().player; GlStateManager.pushMatrix(); - if( hand == EnumHand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) + if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) { renderItemFirstPersonCenter( pitch, equipProgress, swingProgress, stack ); } else { renderItemFirstPersonSide( - hand == EnumHand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(), + hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(), equipProgress, swingProgress, stack ); } @@ -51,12 +51,12 @@ public abstract class ItemMapLikeRenderer * @param equipProgress The equip progress of this item * @param swingProgress The swing progress of this item * @param stack The stack to render - * @see FirstPersonRenderer#renderMapFirstPersonSide(float, EnumHandSide, float, ItemStack) + * @see FirstPersonRenderer#renderMapFirstPersonSide(float, HandSide, float, ItemStack) */ - private void renderItemFirstPersonSide( EnumHandSide side, float equipProgress, float swingProgress, ItemStack stack ) + private void renderItemFirstPersonSide( HandSide side, float equipProgress, float swingProgress, ItemStack stack ) { Minecraft minecraft = Minecraft.getInstance(); - float offset = side == EnumHandSide.RIGHT ? 1f : -1f; + float offset = side == HandSide.RIGHT ? 1f : -1f; GlStateManager.translatef( offset * 0.125f, -0.125f, 0f ); // If the player is not invisible then render a single arm diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index de244a726..6c4e57597 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; @@ -18,7 +19,6 @@ import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; @@ -173,7 +173,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer private static void renderLight( int colour, int width, int height ) { GlStateManager.enableBlend(); - GlStateManager.disableTexture2D(); + GlStateManager.disableTexture(); float r = ((colour >>> 16) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f; @@ -188,7 +188,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); tessellator.draw(); - GlStateManager.enableTexture2D(); + GlStateManager.enableTexture(); } private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height ) diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index ab8eb2670..35bd7e047 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -6,9 +6,9 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemPrintout; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.RenderItemInFrameEvent; diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index 539af8cfb..1a794d64f 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -9,7 +9,7 @@ package dan200.computercraft.client.render; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraftforge.client.model.pipeline.IVertexConsumer; import net.minecraftforge.client.model.pipeline.LightUtil; import net.minecraftforge.client.model.pipeline.VertexTransformer; @@ -102,7 +102,7 @@ public final class ModelTransformer } @Override - public void setQuadOrientation( @Nonnull EnumFacing orientation ) + public void setQuadOrientation( @Nonnull Direction orientation ) { super.setQuadOrientation( orientation == null ? orientation : TRSRTransformation.rotate( positionMatrix, orientation ) ); } @@ -187,7 +187,7 @@ public final class ModelTransformer private final int[] vertexData; private int vertexIndex = 0, elementIndex = 0; - private EnumFacing orientation; + private Direction orientation; private int quadTint; private boolean diffuse; private TextureAtlasSprite texture; @@ -212,7 +212,7 @@ public final class ModelTransformer } @Override - public void setQuadOrientation( @Nonnull EnumFacing orientation ) + public void setQuadOrientation( @Nonnull Direction orientation ) { this.orientation = orientation; } diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index f5eee7ba8..8e313bb5a 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -6,18 +6,19 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.DrawBlockHighlightEvent; @@ -27,7 +28,7 @@ import org.lwjgl.opengl.GL11; import java.util.EnumSet; -import static net.minecraft.util.EnumFacing.*; +import static net.minecraft.util.Direction.*; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class MonitorHighlightRenderer @@ -41,10 +42,13 @@ public final class MonitorHighlightRenderer @SubscribeEvent public static void drawHighlight( DrawBlockHighlightEvent event ) { - if( event.getTarget().type != RayTraceResult.Type.BLOCK || event.getPlayer().isSneaking() ) return; + if( event.getTarget().getType() != RayTraceResult.Type.BLOCK || event.getInfo().func_216773_g().isSneaking() ) + { + return; + } - World world = event.getPlayer().getEntityWorld(); - BlockPos pos = event.getTarget().getBlockPos(); + World world = event.getInfo().func_216773_g().getEntityWorld(); + BlockPos pos = ((BlockRayTraceResult) event.getTarget()).getPos(); TileEntity tile = world.getTileEntity( pos ); if( !(tile instanceof TileMonitor) ) return; @@ -53,8 +57,8 @@ public final class MonitorHighlightRenderer event.setCanceled( true ); // Determine which sides are part of the external faces of the monitor, and so which need to be rendered. - EnumSet faces = EnumSet.allOf( EnumFacing.class ); - EnumFacing front = monitor.getFront(); + EnumSet faces = EnumSet.allOf( Direction.class ); + Direction front = monitor.getFront(); faces.remove( front ); if( monitor.getXIndex() != 0 ) faces.remove( monitor.getRight().getOpposite() ); if( monitor.getXIndex() != monitor.getWidth() - 1 ) faces.remove( monitor.getRight() ); @@ -64,16 +68,12 @@ public final class MonitorHighlightRenderer GlStateManager.enableBlend(); GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); GlStateManager.lineWidth( Math.max( 2.5F, (float) Minecraft.getInstance().mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) ); - GlStateManager.disableTexture2D(); + GlStateManager.disableTexture(); GlStateManager.depthMask( false ); GlStateManager.pushMatrix(); - EntityPlayer player = event.getPlayer(); - double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks(); - double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks(); - double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks(); - - GlStateManager.translated( -x + pos.getX(), -y + pos.getY(), -z + pos.getZ() ); + Vec3d cameraPos = event.getInfo().func_216785_c(); + GlStateManager.translated( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); @@ -97,11 +97,11 @@ public final class MonitorHighlightRenderer GlStateManager.popMatrix(); GlStateManager.depthMask( true ); - GlStateManager.enableTexture2D(); + GlStateManager.enableTexture(); GlStateManager.disableBlend(); } - private static void line( BufferBuilder buffer, int x, int y, int z, EnumFacing direction ) + private static void line( BufferBuilder buffer, int x, int y, int z, Direction direction ) { double minX = x == 0 ? -EXPAND : 1 + EXPAND; double minY = y == 0 ? -EXPAND : 1 + EXPAND; diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 07e9af310..404a7f9b5 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -6,14 +6,14 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.platform.GlStateManager.DestFactor; +import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.GlStateManager.DestFactor; -import net.minecraft.client.renderer.GlStateManager.SourceFactor; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; @@ -76,7 +76,7 @@ public final class PrintoutRenderer { GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.enableBlend(); - GlStateManager.enableTexture2D(); + GlStateManager.enableTexture(); GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); @@ -91,7 +91,7 @@ public final class PrintoutRenderer { GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.enableBlend(); - GlStateManager.enableTexture2D(); + GlStateManager.enableTexture(); GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); Minecraft.getInstance().getTextureManager().bindTexture( BG ); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java index efc46e40e..a6d7e6027 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; @@ -13,10 +14,9 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.peripheral.modem.wired.TileCable; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.model.IBakedModel; @@ -25,10 +25,10 @@ import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.MinecraftForgeClient; import net.minecraftforge.client.model.data.EmptyModelData; import org.lwjgl.opengl.GL11; @@ -52,16 +52,19 @@ public class TileEntityCableRenderer extends TileEntityRenderer Minecraft mc = Minecraft.getInstance(); RayTraceResult hit = mc.objectMouseOver; - if( hit == null || !hit.getBlockPos().equals( pos ) ) return; + if( hit == null || hit.getType() != RayTraceResult.Type.BLOCK || !((BlockRayTraceResult) hit).getPos().equals( pos ) ) + { + return; + } - if( MinecraftForgeClient.getRenderPass() != 0 ) return; + if( ForgeHooksClient.getWorldRenderPass() != 0 ) return; World world = te.getWorld(); - IBlockState state = world.getBlockState( pos ); + BlockState state = world.getBlockState( pos ); Block block = state.getBlock(); if( block != ComputerCraft.Blocks.cable ) return; - state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) ) : state.with( BlockCable.MODEM, CableModemVariant.None ); @@ -80,7 +83,7 @@ public class TileEntityCableRenderer extends TileEntityRenderer TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] ); mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel( world, - ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos ), + ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos, 0 ), state, pos, buffer, true, random, state.getPositionRandom( pos ), EmptyModelData.INSTANCE ); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 3ac9ce6fa..211324e5f 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -6,6 +6,8 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GLX; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; @@ -17,12 +19,10 @@ import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import org.lwjgl.opengl.GL11; @@ -64,8 +64,8 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer posZ += originPos.getZ() - monitorPos.getZ(); // Determine orientation - EnumFacing dir = origin.getDirection(); - EnumFacing front = origin.getFront(); + Direction dir = origin.getDirection(); + Direction front = origin.getFront(); float yaw = dir.getHorizontalAngle(); float pitch = DirectionUtil.toPitchAngle( front ); @@ -94,7 +94,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer // Draw the contents GlStateManager.depthMask( false ); - OpenGlHelper.glMultiTexCoord2f( OpenGlHelper.GL_TEXTURE1, 0xFFFF, 0xFFFF ); + GLX.glMultiTexCoord2f( GLX.GL_TEXTURE1, 0xFFFF, 0xFFFF ); GlStateManager.disableLighting(); mc.gameRenderer.disableLightmap(); try @@ -171,7 +171,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer } } GlStateManager.callList( originTerminal.renderDisplayLists[0] ); - GlStateManager.resetColor(); + GlStateManager.clearCurrentColor(); // Draw text fontRenderer.bindFont(); @@ -199,7 +199,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer } } GlStateManager.callList( originTerminal.renderDisplayLists[1] ); - GlStateManager.resetColor(); + GlStateManager.clearCurrentColor(); // Draw cursor fontRenderer.bindFont(); @@ -233,7 +233,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer if( FrameInfo.getGlobalCursorBlink() ) { GlStateManager.callList( originTerminal.renderDisplayLists[2] ); - GlStateManager.resetColor(); + GlStateManager.clearCurrentColor(); } } finally diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 9460e0e88..f7f77076b 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.render; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -13,22 +14,23 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; @@ -85,13 +87,15 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer { // Render the label String label = turtle.createProxy().getLabel(); - if( label != null && rendererDispatcher.cameraHitResult != null && turtle.getPos().equals( rendererDispatcher.cameraHitResult.getBlockPos() ) ) + RayTraceResult hit = rendererDispatcher.cameraHitResult; + if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) ) { setLightmapDisabled( true ); - GameRenderer.drawNameplate( + GameRenderer.func_215307_a( getFontRenderer(), label, (float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, - rendererDispatcher.entityYaw, rendererDispatcher.entityPitch, false, false + rendererDispatcher.field_217666_g.func_216778_f(), rendererDispatcher.field_217666_g.func_216777_e(), false + // yaw, pitch ); setLightmapDisabled( false ); } @@ -99,7 +103,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer GlStateManager.pushMatrix(); try { - IBlockState state = turtle.getBlockState(); + BlockState state = turtle.getBlockState(); // Setup the transform Vec3d offset = turtle.getRenderOffset( partialTicks ); float yaw = turtle.getRenderYaw( partialTicks ); @@ -153,7 +157,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer } } - private void renderUpgrade( IBlockState state, TileTurtle turtle, TurtleSide side, float f ) + private void renderUpgrade( BlockState state, TileTurtle turtle, TurtleSide side, float f ) { ITurtleUpgrade upgrade = turtle.getUpgrade( side ); if( upgrade != null ) @@ -186,20 +190,20 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer } } - private void renderModel( IBlockState state, ModelResourceLocation modelLocation, int[] tints ) + private void renderModel( BlockState state, ModelResourceLocation modelLocation, int[] tints ) { Minecraft mc = Minecraft.getInstance(); ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager(); renderModel( state, modelManager.getModel( modelLocation ), tints ); } - private void renderModel( IBlockState state, IBakedModel model, int[] tints ) + private void renderModel( BlockState state, IBakedModel model, int[] tints ) { Random random = new Random( 0 ); Tessellator tessellator = Tessellator.getInstance(); - rendererDispatcher.textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); + rendererDispatcher.textureManager.bindTexture( AtlasTexture.LOCATION_BLOCKS_TEXTURE ); renderQuads( tessellator, model.getQuads( state, null, random, EmptyModelData.INSTANCE ), tints ); - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { renderQuads( tessellator, model.getQuads( state, facing, random, EmptyModelData.INSTANCE ), tints ); } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index 42ea8eedf..20a027348 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -9,15 +9,15 @@ package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IUnbakedModel; +import net.minecraft.client.renderer.model.ModelBakery; +import net.minecraft.client.renderer.texture.ISprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.ICustomModelLoader; -import net.minecraftforge.common.model.IModelState; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.Arrays; import java.util.Collection; import java.util.Set; @@ -91,13 +91,13 @@ public final class TurtleModelLoader implements ICustomModelLoader .collect( Collectors.toSet() ); } - @Nullable + @Nonnull @Override - public IBakedModel bake( @Nonnull Function modelGetter, @Nonnull Function spriteGetter, @Nonnull IModelState state, boolean uvlock, @Nonnull VertexFormat format ) + public IBakedModel bake( @Nonnull ModelBakery bakery, @Nonnull Function spriteGetter, @Nonnull ISprite sprite, @Nonnull VertexFormat format ) { return new TurtleSmartItemModel( - modelGetter.apply( family ).bake( modelGetter, spriteGetter, state, uvlock, format ), - modelGetter.apply( COLOUR_TURTLE_MODEL ).bake( modelGetter, spriteGetter, state, uvlock, format ) + bakery.getBakedModel( family, sprite, spriteGetter, format ), + bakery.getBakedModel( COLOUR_TURTLE_MODEL, sprite, spriteGetter, format ) ); } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 9834eb08c..7014b8368 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -6,12 +6,12 @@ package dan200.computercraft.client.render; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ItemOverrideList; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.IModelData; @@ -29,7 +29,7 @@ public class TurtleMultiModel implements IBakedModel private final IBakedModel m_rightUpgradeModel; private final Matrix4f m_rightUpgradeTransform; private List m_generalQuads = null; - private Map> m_faceQuads = new EnumMap<>( EnumFacing.class ); + private Map> m_faceQuads = new EnumMap<>( Direction.class ); public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, Matrix4f generalTransform, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform ) { @@ -46,14 +46,14 @@ public class TurtleMultiModel implements IBakedModel @Nonnull @Override @Deprecated - public List getQuads( IBlockState state, EnumFacing side, @Nonnull Random rand ) + public List getQuads( BlockState state, Direction side, @Nonnull Random rand ) { return getQuads( state, side, rand, EmptyModelData.INSTANCE ); } @Nonnull @Override - public List getQuads( IBlockState state, EnumFacing side, @Nonnull Random rand, @Nonnull IModelData data ) + public List getQuads( BlockState state, Direction side, @Nonnull Random rand, @Nonnull IModelData data ) { if( side != null ) { @@ -67,7 +67,7 @@ public class TurtleMultiModel implements IBakedModel } } - private List buildQuads( IBlockState state, EnumFacing side, Random rand ) + private List buildQuads( BlockState state, Direction side, Random rand ) { ArrayList quads = new ArrayList<>(); ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index ecd5dae7e..7c24c7f55 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -12,13 +12,13 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.client.model.data.IModelData; @@ -111,7 +111,7 @@ public class TurtleSmartItemModel implements IBakedModel { @Nonnull @Override - public IBakedModel getModelWithOverrides( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable EntityLivingBase entity ) + public IBakedModel getModelWithOverrides( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable LivingEntity entity ) { ItemTurtle turtle = (ItemTurtle) stack.getItem(); int colour = turtle.getColour( stack ); @@ -169,7 +169,7 @@ public class TurtleSmartItemModel implements IBakedModel @Nonnull @Override @Deprecated - public List getQuads( IBlockState state, EnumFacing facing, @Nonnull Random rand ) + public List getQuads( BlockState state, Direction facing, @Nonnull Random rand ) { return familyModel.getQuads( state, facing, rand ); } @@ -177,7 +177,7 @@ public class TurtleSmartItemModel implements IBakedModel @Nonnull @Override @Deprecated - public List getQuads( IBlockState state, EnumFacing facing, @Nonnull Random rand, @Nonnull IModelData data ) + public List getQuads( BlockState state, Direction facing, @Nonnull Random rand, @Nonnull IModelData data ) { return familyModel.getQuads( state, facing, rand, data ); } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java index 1cbbfa294..047608634 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -6,11 +6,13 @@ package dan200.computercraft.core.computer; +import net.minecraft.util.Direction; + import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * A side on a computer. Unlike {@link net.minecraft.util.EnumFacing}, this is relative to the direction the computer is + * A side on a computer. Unlike {@link Direction}, this is relative to the direction the computer is * facing.. */ public enum ComputerSide diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index 4f6eb2e28..433497ba2 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -170,7 +170,7 @@ public class ResourceMount implements IMount { total += read; read = s.read( TEMP_BUFFER ); - } while ( read > 0 ); + } while( read > 0 ); return file.size = total; } @@ -267,7 +267,7 @@ public class ResourceMount implements IMount synchronized void add( IReloadableResourceManager manager, ResourceMount mount ) { - if( managers.add( manager ) ) manager.addReloadListener( this ); + if( managers.add( manager ) ) manager.func_219534_a( this ); // addReloadListener mounts.add( mount ); } } diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index a0229f53a..d0a4c9f04 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -7,7 +7,7 @@ package dan200.computercraft.core.terminal; import dan200.computercraft.shared.util.Palette; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; public class Terminal { @@ -334,7 +334,7 @@ public class Terminal m_changed = false; } - public synchronized NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public synchronized CompoundNBT writeToNBT( CompoundNBT nbt ) { nbt.putInt( "term_cursorX", m_cursorX ); nbt.putInt( "term_cursorY", m_cursorY ); @@ -354,7 +354,7 @@ public class Terminal return nbt; } - public synchronized void readFromNBT( NBTTagCompound nbt ) + public synchronized void readFromNBT( CompoundNBT nbt ) { m_cursorX = nbt.getInt( "term_cursorX" ); m_cursorY = nbt.getInt( "term_cursorY" ); diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index 8c562c7a8..747355605 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -9,7 +9,7 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -30,12 +30,12 @@ public final class BundledRedstone providers.add( provider ); } - public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return World.isValid( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1; } - private static int getUnmaskedOutput( World world, BlockPos pos, EnumFacing side ) + private static int getUnmaskedOutput( World world, BlockPos pos, Direction side ) { if( !World.isValid( pos ) ) return -1; @@ -60,7 +60,7 @@ public final class BundledRedstone return combinedSignal; } - public static int getOutput( World world, BlockPos pos, EnumFacing side ) + public static int getOutput( World world, BlockPos pos, Direction side ) { int signal = getUnmaskedOutput( world, pos, side ); return signal >= 0 ? signal : 0; diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 960ae0c0a..684bec613 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -9,7 +9,7 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -30,12 +30,12 @@ public final class Peripherals providers.add( provider ); } - public static IPeripheral getPeripheral( World world, BlockPos pos, EnumFacing side ) + public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side ) { return World.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side ) : null; } - private static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side ) + private static IPeripheral getPeripheralAt( World world, BlockPos pos, Direction side ) { // Try the handlers in order: for( IPeripheralProvider peripheralProvider : providers ) diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index 5c36d45e4..5786a543b 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -39,10 +39,10 @@ import dan200.computercraft.shared.util.CreativeTabMain; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityType; -import net.minecraft.init.Items; +import net.minecraft.item.BlockItem; import net.minecraft.item.Item; -import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemGroup; +import net.minecraft.item.Items; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; @@ -181,7 +181,7 @@ public final class Registry ); } - private static T setupItemBlock( T item ) + private static T setupItemBlock( T item ) { item.setRegistryName( item.getBlock().getRegistryName() ); return item; @@ -247,14 +247,14 @@ public final class Registry // Peripherals registry.registerAll( - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.speaker, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.diskDrive, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.printer, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.monitorNormal, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.monitorAdvanced, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.wirelessModemNormal, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.wirelessModemAdvanced, defaultItem() ) ), - setupItemBlock( new ItemBlock( ComputerCraft.Blocks.wiredModemFull, defaultItem() ) ) + setupItemBlock( new BlockItem( ComputerCraft.Blocks.speaker, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.diskDrive, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.printer, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.monitorNormal, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.monitorAdvanced, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.wirelessModemNormal, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.wirelessModemAdvanced, defaultItem() ) ), + setupItemBlock( new BlockItem( ComputerCraft.Blocks.wiredModemFull, defaultItem() ) ) ); ComputerCraft.Items.cable = new ItemBlockCable.Cable( ComputerCraft.Blocks.cable, defaultItem() ); @@ -286,7 +286,7 @@ public final class Registry ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD ); ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondSword ); - ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL ); + ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), net.minecraft.item.Items.DIAMOND_SHOVEL ); ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondShovel ); ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE ); diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index f28c421cf..2dbe4b725 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -18,13 +18,13 @@ import net.minecraftforge.fml.common.Mod; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) public final class TurtlePermissions { - public static boolean isBlockEnterable( World world, BlockPos pos, EntityPlayer player ) + public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player ) { MinecraftServer server = world.getServer(); return server == null || world.isRemote || !server.isBlockProtected( world, pos, player ); } - public static boolean isBlockEditable( World world, BlockPos pos, EntityPlayer player ) + public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player ) { MinecraftServer server = world.getServer(); return server == null || world.isRemote || !server.isBlockProtected( world, pos, player ); diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index ce63d9a78..03314d6fd 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -20,17 +20,17 @@ import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.Containers; +import dan200.computercraft.shared.network.container.ViewComputerContainerData; import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.network.play.server.SPacketPlayerPosLook; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.play.server.SPlayerPositionLookPacket; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.ServerWorld; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; import javax.annotation.Nonnull; import java.util.*; @@ -170,16 +170,21 @@ public final class CommandComputerCraft if( world == null || pos == null ) throw TP_NOT_THERE.create(); Entity entity = context.getSource().assertIsEntity(); - if( !(entity instanceof EntityPlayerMP) ) throw TP_NOT_PLAYER.create(); + if( !(entity instanceof ServerPlayerEntity) ) throw TP_NOT_PLAYER.create(); - EntityPlayerMP player = (EntityPlayerMP) entity; + ServerPlayerEntity player = (ServerPlayerEntity) entity; if( player.getEntityWorld() == world ) { - player.connection.setPlayerLocation( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0, EnumSet.noneOf( SPacketPlayerPosLook.EnumFlags.class ) ); + player.connection.setPlayerLocation( + pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0, + EnumSet.noneOf( SPlayerPositionLookPacket.Flags.class ) + ); } else { - player.teleport( (WorldServer) world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0 ); + player.teleport( (ServerWorld) world, + pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0 + ); } return 1; @@ -210,9 +215,9 @@ public final class CommandComputerCraft .requires( UserLevel.OP ) .arg( "computer", oneComputer() ) .executes( context -> { - EntityPlayerMP player = context.getSource().asPlayer(); + ServerPlayerEntity player = context.getSource().asPlayer(); ServerComputer computer = getComputerArgument( context, "computer" ); - Containers.openComputerGUI( player, computer ); + new ViewComputerContainerData( computer ).open( player ); return 1; } ) ) @@ -259,7 +264,7 @@ public final class CommandComputerCraft private static ITextComponent linkComputer( CommandSource source, ServerComputer serverComputer, int computerId ) { - ITextComponent out = new TextComponentString( "" ); + ITextComponent out = new StringTextComponent( "" ); // Append the computer instance if( serverComputer == null ) @@ -319,7 +324,7 @@ public final class CommandComputerCraft private static TrackingContext getTimingContext( CommandSource source ) { Entity entity = source.getEntity(); - return entity instanceof EntityPlayer ? Tracking.getContext( entity.getUniqueID() ) : Tracking.getContext( SYSTEM_UUID ); + return entity instanceof PlayerEntity ? Tracking.getContext( entity.getUniqueID() ) : Tracking.getContext( SYSTEM_UUID ); } private static final List DEFAULT_FIELDS = Arrays.asList( TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME ); diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java index 47ede7da2..a35b69cdd 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java @@ -12,8 +12,8 @@ import dan200.computercraft.ComputerCraft; import net.minecraft.client.Minecraft; import net.minecraft.command.CommandSource; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.event.ClickEvent; import net.minecraft.util.text.event.HoverEvent; import net.minecraftforge.api.distmarker.Dist; @@ -58,10 +58,10 @@ public final class CommandCopy public static ITextComponent createCopyText( String text ) { - TextComponentString name = new TextComponentString( text ); + StringTextComponent name = new StringTextComponent( text ); name.getStyle() .setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) ) - .setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TextComponentTranslation( "gui.computercraft.tooltip.copy" ) ) ); + .setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) ); return name; } } diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index 378c4d623..a837b770c 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -12,7 +12,7 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder; import net.minecraft.command.CommandSource; import net.minecraft.command.ISuggestionProvider; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraftforge.common.util.FakePlayer; import java.util.Arrays; @@ -27,9 +27,9 @@ public final class CommandUtils public static boolean isPlayer( CommandSource output ) { Entity sender = output.getEntity(); - return sender instanceof EntityPlayerMP + return sender instanceof ServerPlayerEntity && !(sender instanceof FakePlayer) - && ((EntityPlayerMP) sender).connection != null; + && ((ServerPlayerEntity) sender).connection != null; } @SuppressWarnings( "unchecked" ) diff --git a/src/main/java/dan200/computercraft/shared/command/Exceptions.java b/src/main/java/dan200/computercraft/shared/command/Exceptions.java index 6773e39ea..e4a6b0a44 100644 --- a/src/main/java/dan200/computercraft/shared/command/Exceptions.java +++ b/src/main/java/dan200/computercraft/shared/command/Exceptions.java @@ -9,7 +9,7 @@ package dan200.computercraft.shared.command; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TranslationTextComponent; public final class Exceptions { @@ -28,16 +28,16 @@ public final class Exceptions private static SimpleCommandExceptionType translated( String key ) { - return new SimpleCommandExceptionType( new TextComponentTranslation( key ) ); + return new SimpleCommandExceptionType( new TranslationTextComponent( key ) ); } private static DynamicCommandExceptionType translated1( String key ) { - return new DynamicCommandExceptionType( x -> new TextComponentTranslation( key, x ) ); + return new DynamicCommandExceptionType( x -> new TranslationTextComponent( key, x ) ); } private static Dynamic2CommandExceptionType translated2( String key ) { - return new Dynamic2CommandExceptionType( ( x, y ) -> new TextComponentTranslation( key, x, y ) ); + return new Dynamic2CommandExceptionType( ( x, y ) -> new TranslationTextComponent( key, x, y ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java index 7a24bc1fe..6177c30a8 100644 --- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java +++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.command; import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import java.util.function.Predicate; @@ -62,8 +62,8 @@ public enum UserLevel implements Predicate MinecraftServer server = source.getServer(); Entity sender = source.getEntity(); - if( server.isSinglePlayer() && sender instanceof EntityPlayer && - ((EntityPlayer) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) ) + if( server.isSinglePlayer() && sender instanceof PlayerEntity && + ((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) ) { if( this == OWNER || this == OWNER_OP ) return true; } diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java index ad8837024..20af81c37 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java @@ -18,12 +18,12 @@ public final class ArgumentSerializers @SuppressWarnings( "unchecked" ) private static > void registerUnsafe( ResourceLocation id, Class type, IArgumentSerializer serializer ) { - ArgumentTypes.register( id, type, (IArgumentSerializer) serializer ); + ArgumentTypes.func_218136_a( id.toString(), type, (IArgumentSerializer) serializer ); } private static > void register( ResourceLocation id, Class type, IArgumentSerializer serializer ) { - ArgumentTypes.register( id, type, serializer ); + ArgumentTypes.func_218136_a( id.toString(), type, serializer ); } private static > void register( ResourceLocation id, T instance ) diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java index 6311ffd07..a7c957865 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java @@ -19,7 +19,7 @@ import net.minecraft.command.arguments.ArgumentTypes; import net.minecraft.command.arguments.IArgumentSerializer; import net.minecraft.network.PacketBuffer; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import javax.annotation.Nonnull; import java.util.ArrayList; @@ -160,7 +160,7 @@ public final class RepeatArgumentType implements ArgumentType> { Message message = arg.some.create().getRawMessage(); if( message instanceof ITextComponent ) return (ITextComponent) message; - return new TextComponentString( message.getString() ); + return new StringTextComponent( message.getString() ); } } } diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index 6fa685443..ca3c3db79 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -15,7 +15,7 @@ import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.command.CommandSource; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.event.ClickEvent; @@ -174,7 +174,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder type; - public BlockGeneric( Properties settings, TileEntityType type ) + public BlockGeneric( Properties settings, NamedTileEntityType type ) { super( settings ); this.type = type; + type.setBlock( this ); } @Override @Deprecated - public final void onReplaced( @Nonnull IBlockState block, @Nonnull World world, @Nonnull BlockPos pos, IBlockState replace, boolean bool ) + public final void onReplaced( @Nonnull BlockState block, @Nonnull World world, @Nonnull BlockPos pos, BlockState replace, boolean bool ) { if( block.getBlock() == replace.getBlock() ) return; @@ -46,22 +48,22 @@ public abstract class BlockGeneric extends Block @Override @Deprecated - public final boolean onBlockActivated( IBlockState state, World world, BlockPos pos, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public final boolean onBlockActivated( BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, side, hitX, hitY, hitZ ); + return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, hit ); } @Override @Deprecated - public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos ) + public final void neighborChanged( BlockState state, World world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourChange( neighbourPos ); } @Override - public final void onNeighborChange( IBlockState state, IWorldReader world, BlockPos pos, BlockPos neighbour ) + public final void onNeighborChange( BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbour ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourTileEntityChange( neighbour ); @@ -69,21 +71,21 @@ public abstract class BlockGeneric extends Block @Override @Deprecated - public void tick( IBlockState state, World world, BlockPos pos, Random rand ) + public void tick( BlockState state, World world, BlockPos pos, Random rand ) { TileEntity te = world.getTileEntity( pos ); if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick(); } @Override - public boolean hasTileEntity( IBlockState state ) + public boolean hasTileEntity( BlockState state ) { return true; } @Nullable @Override - public TileEntity createTileEntity( @Nonnull IBlockState state, @Nonnull IBlockReader world ) + public TileEntity createTileEntity( @Nonnull BlockState state, @Nonnull IBlockReader world ) { return type.create(); } diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 4e7ad3791..85f79d085 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; public class ClientTerminal implements ITerminal { @@ -47,12 +47,12 @@ public class ClientTerminal implements ITerminal return m_colour; } - public void readDescription( NBTTagCompound nbt ) + public void readDescription( CompoundNBT nbt ) { m_colour = nbt.getBoolean( "colour" ); if( nbt.contains( "terminal" ) ) { - NBTTagCompound terminal = nbt.getCompound( "terminal" ); + CompoundNBT terminal = nbt.getCompound( "terminal" ); resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) ); m_terminal.readFromNBT( terminal ); } diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index d17d95e25..738ff499a 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -6,30 +6,29 @@ package dan200.computercraft.shared.common; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.util.AbstractRecipe; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.EnumDyeColor; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.DyeColor; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.crafting.SpecialRecipe; +import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import javax.annotation.Nonnull; -public class ColourableRecipe extends AbstractRecipe +public class ColourableRecipe extends SpecialRecipe { - public ColourableRecipe( ResourceLocation id ) + private ColourableRecipe( ResourceLocation id ) { super( id ); } @Override - public boolean matches( @Nonnull IInventory inv, @Nonnull World world ) + public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) { boolean hasColourable = false; boolean hasDye = false; @@ -58,7 +57,7 @@ public class ColourableRecipe extends AbstractRecipe @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inv ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inv ) { ItemStack colourable = ItemStack.EMPTY; @@ -76,7 +75,7 @@ public class ColourableRecipe extends AbstractRecipe } else { - EnumDyeColor dye = ColourUtils.getStackColour( stack ); + DyeColor dye = ColourUtils.getStackColour( stack ); if( dye == null ) continue; Colour colour = Colour.fromInt( 15 - dye.getId() ); @@ -101,7 +100,5 @@ public class ColourableRecipe extends AbstractRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( - ComputerCraft.MOD_ID + ":colour", ColourableRecipe::new - ); + public static final IRecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( ColourableRecipe::new ); } diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index af4f46983..d6dec3d36 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -6,21 +6,28 @@ package dan200.computercraft.shared.common; +import dan200.computercraft.shared.network.container.ContainerData; +import dan200.computercraft.shared.network.container.PrintoutContainerData; import dan200.computercraft.shared.util.InventoryUtil; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Hand; import javax.annotation.Nonnull; public class ContainerHeldItem extends Container { - private final ItemStack m_stack; - private final EnumHand m_hand; + public static final ContainerType PRINTOUT_TYPE = ContainerData.create( PrintoutContainerData::new ); - public ContainerHeldItem( EntityPlayer player, EnumHand hand ) + private final ItemStack m_stack; + private final Hand m_hand; + + public ContainerHeldItem( ContainerType type, int id, PlayerEntity player, Hand hand ) { + super( type, id ); + m_hand = hand; m_stack = InventoryUtil.copyItem( player.getHeldItem( hand ) ); } @@ -32,7 +39,7 @@ public class ContainerHeldItem extends Container } @Override - public boolean canInteractWith( @Nonnull EntityPlayer player ) + public boolean canInteractWith( @Nonnull PlayerEntity player ) { if( !player.isAlive() ) return false; diff --git a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java index 5b0a26148..3f57d81f0 100644 --- a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.common; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import net.minecraft.block.Block; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -17,12 +17,12 @@ import javax.annotation.Nonnull; public class DefaultBundledRedstoneProvider implements IBundledRedstoneProvider { @Override - public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) { return getDefaultBundledRedstoneOutput( world, pos, side ); } - public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) + public static int getDefaultBundledRedstoneOutput( World world, BlockPos pos, Direction side ) { Block block = world.getBlockState( pos ).getBlock(); if( block instanceof IBundledRedstoneBlock ) diff --git a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java index d6212dbed..4d4b2d28c 100644 --- a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java +++ b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java @@ -6,13 +6,13 @@ package dan200.computercraft.shared.common; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; public interface IBundledRedstoneBlock { - boolean getBundledRedstoneConnectivity( World world, BlockPos pos, EnumFacing side ); + boolean getBundledRedstoneConnectivity( World world, BlockPos pos, Direction side ); - int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ); + int getBundledRedstoneOutput( World world, BlockPos pos, Direction side ); } diff --git a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java index 9fe5ca6cf..b87bc0779 100644 --- a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java +++ b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.common; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; public interface IColouredItem { @@ -27,7 +27,7 @@ public interface IColouredItem static int getColourBasic( ItemStack stack ) { - NBTTagCompound tag = stack.getTag(); + CompoundNBT tag = stack.getTag(); return tag != null && tag.contains( NBT_COLOUR ) ? tag.getInt( NBT_COLOUR ) : -1; } @@ -35,7 +35,7 @@ public interface IColouredItem { if( colour == -1 ) { - NBTTagCompound tag = stack.getTag(); + CompoundNBT tag = stack.getTag(); if( tag != null ) tag.remove( NBT_COLOUR ); } else diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 0898a3844..6ab51aec3 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import java.util.concurrent.atomic.AtomicBoolean; @@ -86,12 +86,12 @@ public class ServerTerminal implements ITerminal // Networking stuff - public void writeDescription( NBTTagCompound nbt ) + public void writeDescription( CompoundNBT nbt ) { nbt.putBoolean( "colour", m_colour ); if( m_terminal != null ) { - NBTTagCompound terminal = new NBTTagCompound(); + CompoundNBT terminal = new CompoundNBT(); terminal.putInt( "term_width", m_terminal.getWidth() ); terminal.putInt( "term_height", m_terminal.getHeight() ); m_terminal.writeToNBT( terminal ); diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 2b01a2be1..9efbd3e56 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -6,16 +6,16 @@ package dan200.computercraft.shared.common; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.NetworkManager; -import net.minecraft.network.play.server.SPacketUpdateTileEntity; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import javax.annotation.Nonnull; @@ -34,12 +34,12 @@ public abstract class TileGeneric extends TileEntity { markDirty(); BlockPos pos = getPos(); - IBlockState state = getBlockState(); - getWorld().markBlockRangeForRenderUpdate( pos, pos ); + BlockState state = getBlockState(); + getWorld().markForRerender( pos ); getWorld().notifyBlockUpdate( pos, state, state, 3 ); } - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { return false; } @@ -56,12 +56,12 @@ public abstract class TileGeneric extends TileEntity { } - protected double getInteractRange( EntityPlayer player ) + protected double getInteractRange( PlayerEntity player ) { return 8.0; } - public boolean isUsable( EntityPlayer player, boolean ignoreRange ) + public boolean isUsable( PlayerEntity player, boolean ignoreRange ) { if( player == null || !player.isAlive() || getWorld().getTileEntity( getPos() ) != this ) return false; if( ignoreRange ) return true; @@ -72,40 +72,40 @@ public abstract class TileGeneric extends TileEntity player.getDistanceSq( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range; } - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull CompoundNBT nbt ) { } - protected void readDescription( @Nonnull NBTTagCompound nbt ) + protected void readDescription( @Nonnull CompoundNBT nbt ) { } @Nonnull @Override - public final SPacketUpdateTileEntity getUpdatePacket() + public final SUpdateTileEntityPacket getUpdatePacket() { - NBTTagCompound nbt = new NBTTagCompound(); + CompoundNBT nbt = new CompoundNBT(); writeDescription( nbt ); - return new SPacketUpdateTileEntity( pos, 0, nbt ); + return new SUpdateTileEntityPacket( pos, 0, nbt ); } @Override - public final void onDataPacket( NetworkManager net, SPacketUpdateTileEntity packet ) + public final void onDataPacket( NetworkManager net, SUpdateTileEntityPacket packet ) { if( packet.getTileEntityType() == 0 ) readDescription( packet.getNbtCompound() ); } @Nonnull @Override - public NBTTagCompound getUpdateTag() + public CompoundNBT getUpdateTag() { - NBTTagCompound tag = super.getUpdateTag(); + CompoundNBT tag = super.getUpdateTag(); writeDescription( tag ); return tag; } @Override - public void handleUpdateTag( @Nonnull NBTTagCompound tag ) + public void handleUpdateTag( @Nonnull CompoundNBT tag ) { super.handleUpdateTag( tag ); readDescription( tag ); diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 136188323..de52751fc 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -16,10 +16,10 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.server.MinecraftServer; import net.minecraft.state.IProperty; import net.minecraft.tileentity.TileEntity; @@ -97,7 +97,7 @@ public class CommandAPI implements ILuaAPI private static Object getBlockInfo( World world, BlockPos pos ) { // Get the details of the block - IBlockState state = world.getBlockState( pos ); + BlockState state = world.getBlockState( pos ); Block block = state.getBlock(); Map table = new HashMap<>(); @@ -112,7 +112,7 @@ public class CommandAPI implements ILuaAPI table.put( "state", stateTable ); TileEntity tile = world.getTileEntity( pos ); - if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.write( new NBTTagCompound() ) ) ); + if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.write( new CompoundNBT() ) ) ); return table; } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index 41b68cd8c..034693764 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -9,16 +9,16 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.items.ComputerItemFactory; +import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.DirectionProperty; import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -28,24 +28,24 @@ public class BlockComputer extends BlockComputerBase public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class ); public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public BlockComputer( Properties settings, ComputerFamily family, TileEntityType type ) + public BlockComputer( Properties settings, ComputerFamily family, NamedTileEntityType type ) { super( settings, family, type ); setDefaultState( getDefaultState() - .with( FACING, EnumFacing.NORTH ) + .with( FACING, Direction.NORTH ) .with( STATE, ComputerState.OFF ) ); } @Override - protected void fillStateContainer( StateContainer.Builder builder ) + protected void fillStateContainer( StateContainer.Builder builder ) { builder.add( FACING, STATE ); } @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext placement ) + public BlockState getStateForPlacement( BlockItemUseContext placement ) { return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 2ff6df99b..0050377bd 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -12,15 +12,14 @@ import dan200.computercraft.shared.common.IBundledRedstoneBlock; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +import dan200.computercraft.shared.util.NamedTileEntityType; +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.IBlockReader; @@ -32,7 +31,7 @@ public abstract class BlockComputerBase extends Bloc { private final ComputerFamily family; - protected BlockComputerBase( Properties settings, ComputerFamily family, TileEntityType type ) + protected BlockComputerBase( Properties settings, ComputerFamily family, NamedTileEntityType type ) { super( settings, type ); this.family = family; @@ -40,9 +39,9 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public void onBlockAdded( IBlockState state, World world, BlockPos pos, IBlockState oldState ) + public void onBlockAdded( BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving ) { - super.onBlockAdded( state, world, pos, oldState ); + super.onBlockAdded( state, world, pos, oldState, isMoving ); TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) ((TileComputerBase) tile).updateInput(); @@ -50,14 +49,14 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public boolean canProvidePower( IBlockState state ) + public boolean canProvidePower( BlockState state ) { return true; } @Override @Deprecated - public int getStrongPower( IBlockState state, IBlockReader world, BlockPos pos, EnumFacing incomingSide ) + public int getStrongPower( BlockState state, IBlockReader world, BlockPos pos, Direction incomingSide ) { TileEntity entity = world.getTileEntity( pos ); if( !(entity instanceof TileComputerBase) ) return 0; @@ -80,19 +79,19 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public int getWeakPower( IBlockState state, IBlockReader world, BlockPos pos, EnumFacing incomingSide ) + public int getWeakPower( BlockState state, IBlockReader world, BlockPos pos, Direction incomingSide ) { return getStrongPower( state, world, pos, incomingSide ); } @Override - public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, EnumFacing side ) + public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, Direction side ) { return true; } @Override - public int getBundledRedstoneOutput( World world, BlockPos pos, EnumFacing side ) + public int getBundledRedstoneOutput( World world, BlockPos pos, Direction side ) { TileEntity entity = world.getTileEntity( pos ); if( !(entity instanceof TileComputerBase) ) return 0; @@ -107,7 +106,7 @@ public abstract class BlockComputerBase extends Bloc @Nonnull @Override - public ItemStack getPickBlock( IBlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, EntityPlayer player ) + public ItemStack getPickBlock( BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, PlayerEntity player ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) @@ -119,14 +118,15 @@ public abstract class BlockComputerBase extends Bloc return super.getPickBlock( state, target, world, pos, player ); } + /* TODO: THIS!! @Override @Deprecated - public final void dropBlockAsItemWithChance( @Nonnull IBlockState state, World world, @Nonnull BlockPos pos, float change, int fortune ) + public final void dropBlockAsItemWithChance( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, float change, int fortune ) { } @Override - public final void getDrops( IBlockState state, NonNullList drops, World world, BlockPos pos, int fortune ) + public final void getDrops( BlockState state, NonNullList drops, World world, BlockPos pos, int fortune ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) @@ -135,9 +135,10 @@ public abstract class BlockComputerBase extends Bloc if( !stack.isEmpty() ) drops.add( stack ); } } + */ @Override - public boolean removedByPlayer( IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest, IFluidState fluid ) + public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid ) { if( !world.isRemote ) { @@ -147,7 +148,7 @@ public abstract class BlockComputerBase extends Bloc if( tile instanceof TileComputerBase ) { TileComputerBase computer = (TileComputerBase) tile; - if( !player.abilities.isCreativeMode || computer.getLabel() != null ) + if( !player.playerAbilities.isCreativeMode || computer.getLabel() != null ) { spawnAsEntity( world, pos, getItem( computer ) ); } @@ -158,7 +159,7 @@ public abstract class BlockComputerBase extends Bloc } @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack ) + public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) { super.onBlockPlacedBy( world, pos, state, placer, stack ); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 8a203ce45..dcd476592 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -10,19 +10,19 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.apis.CommandAPI; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.command.CommandSource; import net.minecraft.command.ICommandSource; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.WorldServer; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.ServerWorld; import javax.annotation.Nonnull; import java.util.HashMap; @@ -30,7 +30,7 @@ import java.util.Map; public class TileCommandComputer extends TileComputer { - public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ), f -> new TileCommandComputer( ComputerFamily.Command, f ) ); @@ -104,8 +104,8 @@ public class TileCommandComputer extends TileComputer return new CommandSource( receiver, new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ), Vec2f.ZERO, - (WorldServer) getWorld(), 2, - name, new TextComponentString( name ), + (ServerWorld) getWorld(), 2, + name, new StringTextComponent( name ), getWorld().getServer(), null ); } @@ -119,17 +119,17 @@ public class TileCommandComputer extends TileComputer } @Override - public boolean isUsable( EntityPlayer player, boolean ignoreRange ) + public boolean isUsable( PlayerEntity player, boolean ignoreRange ) { MinecraftServer server = player.getServer(); if( server == null || !server.isCommandBlockEnabled() ) { - player.sendStatusMessage( new TextComponentTranslation( "advMode.notEnabled" ), true ); + player.sendStatusMessage( new TranslationTextComponent( "advMode.notEnabled" ), true ); return false; } else if( !player.canUseCommandBlock() ) { - player.sendStatusMessage( new TextComponentTranslation( "advMode.notAllowed" ), true ); + player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), true ); return false; } else diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 4af198b10..ab1826888 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -11,22 +11,21 @@ import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.Containers; -import dan200.computercraft.shared.util.NamedBlockEntityType; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; +import dan200.computercraft.shared.util.NamedTileEntityType; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; public class TileComputer extends TileComputerBase { - public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ), f -> new TileComputer( ComputerFamily.Normal, f ) ); - public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ), f -> new TileComputer( ComputerFamily.Advanced, f ) ); @@ -69,18 +68,18 @@ public class TileComputer extends TileComputerBase } @Override - public void openGUI( EntityPlayer player ) + public void openGUI( PlayerEntity player ) { - Containers.openComputerGUI( player, this ); + // TODO: Containers.openComputerGUI( player, this ); } - public boolean isUsableByPlayer( EntityPlayer player ) + public boolean isUsableByPlayer( PlayerEntity player ) { return isUsable( player, false ); } @Override - public EnumFacing getDirection() + public Direction getDirection() { return getBlockState().get( BlockComputer.FACING ); } @@ -88,7 +87,7 @@ public class TileComputer extends TileComputerBase @Override protected void updateBlockState( ComputerState newState ) { - IBlockState existing = getBlockState(); + BlockState existing = getBlockState(); if( existing.get( BlockComputer.STATE ) != newState ) { getWorld().setBlockState( getPos(), existing.with( BlockComputer.STATE, newState ), 3 ); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index a79a53f21..b54c99551 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -20,28 +20,30 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.RedstoneUtil; import joptsimple.internal.Strings; -import net.minecraft.block.BlockRedstoneWire; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Blocks; -import net.minecraft.init.Items; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.RedstoneDiodeBlock; +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.INameable; -import net.minecraft.util.ITickable; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; -public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickable, IPeripheralTile, INameable +public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickableTileEntity, IPeripheralTile, INameable { private static final String NBT_ID = "ComputerId"; private static final String NBT_LABEL = "Label"; @@ -76,7 +78,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT public void destroy() { unload(); - for( EnumFacing dir : DirectionUtil.FACINGS ) + for( Direction dir : DirectionUtil.FACINGS ) { RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); } @@ -95,15 +97,15 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT super.remove(); } - public abstract void openGUI( EntityPlayer player ); + public abstract void openGUI( PlayerEntity player ); - protected boolean canNameWithTag( EntityPlayer player ) + protected boolean canNameWithTag( PlayerEntity player ) { return false; } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { ItemStack currentItem = player.getHeldItem( hand ); if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasDisplayName() ) @@ -182,7 +184,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nonnull @Override - public NBTTagCompound write( NBTTagCompound nbt ) + public CompoundNBT write( CompoundNBT nbt ) { // Save ID, label and power state if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); @@ -193,7 +195,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } @Override - public void read( NBTTagCompound nbt ) + public void read( CompoundNBT nbt ) { super.read( nbt ); @@ -208,9 +210,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT return false; } - protected abstract EnumFacing getDirection(); + protected abstract Direction getDirection(); - protected ComputerSide remapToLocalSide( EnumFacing globalSide ) + protected ComputerSide remapToLocalSide( Direction globalSide ) { return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) ); } @@ -220,9 +222,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT return localSide; } - private void updateSideInput( ServerComputer computer, EnumFacing dir, BlockPos offset ) + private void updateSideInput( ServerComputer computer, Direction dir, BlockPos offset ) { - EnumFacing offsetSide = dir.getOpposite(); + Direction offsetSide = dir.getOpposite(); ComputerSide localDir = remapToLocalSide( dir ); computer.setRedstoneInput( localDir, getRedstoneInput( world, offset, dir ) ); @@ -240,16 +242,16 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT * @param pos The position of the neighbour * @param side The side we are reading from * @return The effective redstone power - * @see net.minecraft.block.BlockRedstoneDiode#calculateInputStrength(World, BlockPos, IBlockState) + * @see RedstoneDiodeBlock#calculateInputStrength(World, BlockPos, BlockState) */ - protected static int getRedstoneInput( World world, BlockPos pos, EnumFacing side ) + protected static int getRedstoneInput( World world, BlockPos pos, Direction side ) { int power = world.getRedstonePower( pos, side ); if( power >= 15 ) return power; - IBlockState neighbour = world.getBlockState( pos ); + BlockState neighbour = world.getBlockState( pos ); return neighbour.getBlock() == Blocks.REDSTONE_WIRE - ? Math.max( power, neighbour.get( BlockRedstoneWire.POWER ) ) + ? Math.max( power, neighbour.get( RedstoneWireBlock.POWER ) ) : power; } @@ -262,7 +264,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( computer == null ) return; BlockPos pos = computer.getPosition(); - for( EnumFacing dir : DirectionUtil.FACINGS ) + for( Direction dir : DirectionUtil.FACINGS ) { updateSideInput( computer, dir, pos.offset( dir ) ); } @@ -276,7 +278,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( computer == null ) return; BlockPos pos = computer.getPosition(); - for( EnumFacing dir : DirectionUtil.FACINGS ) + for( Direction dir : DirectionUtil.FACINGS ) { BlockPos offset = pos.offset( dir ); if( offset.equals( neighbour ) ) @@ -294,7 +296,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { // Update redstone updateBlock(); - for( EnumFacing dir : DirectionUtil.FACINGS ) + for( Direction dir : DirectionUtil.FACINGS ) { RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); } @@ -394,7 +396,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT // Networking stuff @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); @@ -404,7 +406,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } @Override - protected void readDescription( @Nonnull NBTTagCompound nbt ) + protected void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); m_instanceID = nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; @@ -429,7 +431,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nullable @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { return new ComputerPeripheral( "computer", createProxy() ); } @@ -438,7 +440,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public ITextComponent getName() { - return hasCustomName() ? new TextComponentString( m_label ) : getBlockState().getBlock().getNameTextComponent(); + return hasCustomName() ? new StringTextComponent( m_label ) : getBlockState().getBlock().getNameTextComponent(); } @Override @@ -451,6 +453,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public ITextComponent getCustomName() { - return hasCustomName() ? new TextComponentString( m_label ) : null; + return hasCustomName() ? new StringTextComponent( m_label ) : null; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index 7c029380d..6675f6b4d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -10,7 +10,7 @@ import com.google.common.base.Objects; import dan200.computercraft.shared.common.ClientTerminal; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.server.*; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; public class ClientComputer extends ClientTerminal implements IComputer { @@ -19,7 +19,7 @@ public class ClientComputer extends ClientTerminal implements IComputer private boolean m_on = false; private boolean m_blinking = false; private boolean m_changed = true; - private NBTTagCompound m_userData = null; + private CompoundNBT m_userData = null; private boolean m_changedLastFrame = false; @@ -40,7 +40,7 @@ public class ClientComputer extends ClientTerminal implements IComputer return m_changedLastFrame; } - public NBTTagCompound getUserData() + public CompoundNBT getUserData() { return m_userData; } @@ -135,11 +135,11 @@ public class ClientComputer extends ClientTerminal implements IComputer NetworkHandler.sendToServer( new MouseEventServerMessage( m_instanceID, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) ); } - public void setState( ComputerState state, NBTTagCompound userData ) + public void setState( ComputerState state, CompoundNBT userData ) { boolean oldOn = m_on; boolean oldBlinking = m_blinking; - NBTTagCompound oldUserData = m_userData; + CompoundNBT oldUserData = m_userData; m_on = state != ComputerState.OFF; m_blinking = state == ComputerState.BLINKING; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java index 85acfbae0..a6cdebcf1 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java @@ -6,11 +6,13 @@ package dan200.computercraft.shared.computer.core; +import net.minecraft.inventory.container.Container; + import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * An instance of {@link net.minecraft.inventory.Container} which provides a computer. You should implement this + * An instance of {@link Container} which provides a computer. You should implement this * if you provide custom computers/GUIs to interact with them. */ @FunctionalInterface diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 9b02735a8..2edcc9c7c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -22,9 +22,9 @@ import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.ComputerDataClientMessage; import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage; import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -43,7 +43,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput private final ComputerFamily m_family; private final Computer m_computer; - private NBTTagCompound m_userData; + private CompoundNBT m_userData; private boolean m_changed; private boolean m_changedLastFrame; @@ -134,11 +134,11 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput m_computer.unload(); } - public NBTTagCompound getUserData() + public CompoundNBT getUserData() { if( m_userData == null ) { - m_userData = new NBTTagCompound(); + m_userData = new CompoundNBT(); } return m_userData; } @@ -155,7 +155,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput protected NetworkMessage createTerminalPacket() { - NBTTagCompound tagCompound = new NBTTagCompound(); + CompoundNBT tagCompound = new CompoundNBT(); writeDescription( tagCompound ); return new ComputerTerminalClientMessage( getInstanceID(), tagCompound ); } @@ -174,7 +174,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); NetworkMessage packet = null; - for( EntityPlayer player : server.getPlayerList().getPlayers() ) + for( PlayerEntity player : server.getPlayerList().getPlayers() ) { if( isInteracting( player ) ) { @@ -185,13 +185,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput } } - public void sendComputerState( EntityPlayer player ) + public void sendComputerState( PlayerEntity player ) { // Send state to client NetworkHandler.sendToPlayer( player, createComputerPacket() ); } - public void sendTerminalState( EntityPlayer player ) + public void sendTerminalState( PlayerEntity player ) { // Send terminal state to client NetworkHandler.sendToPlayer( player, createTerminalPacket() ); @@ -357,7 +357,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput } @Nullable - public IContainerComputer getContainer( EntityPlayer player ) + public IContainerComputer getContainer( PlayerEntity player ) { if( player == null ) return null; @@ -368,7 +368,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return computerContainer.getComputer() != this ? null : computerContainer; } - protected boolean isInteracting( EntityPlayer player ) + protected boolean isInteracting( PlayerEntity player ) { return getContainer( player ) != null; } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java index deb1f596f..28faa109d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java @@ -10,8 +10,8 @@ import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Container; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -21,13 +21,14 @@ public class ContainerComputer extends Container implements IContainerComputer private final TileComputer computer; private final InputState input = new InputState( this ); - public ContainerComputer( TileComputer computer ) + public ContainerComputer( int id, TileComputer computer ) { + super( null, id ); this.computer = computer; } @Override - public boolean canInteractWith( @Nonnull EntityPlayer player ) + public boolean canInteractWith( @Nonnull PlayerEntity player ) { return computer.isUsableByPlayer( player ); } @@ -47,7 +48,7 @@ public class ContainerComputer extends Container implements IContainerComputer } @Override - public void onContainerClosed( EntityPlayer player ) + public void onContainerClosed( PlayerEntity player ) { super.onContainerClosed( player ); input.close(); diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 098fc2959..c6f7d8576 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -8,21 +8,27 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.*; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; +import dan200.computercraft.shared.network.container.ContainerData; +import dan200.computercraft.shared.network.container.ViewComputerContainerData; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TranslationTextComponent; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ContainerViewComputer extends Container implements IContainerComputer { + public static final ContainerType TYPE = ContainerData.create( ViewComputerContainerData::new ); + private final IComputer computer; private final InputState input = new InputState( this ); - public ContainerViewComputer( IComputer computer ) + public ContainerViewComputer( int id, IComputer computer ) { + super( TYPE, id ); this.computer = computer; } @@ -34,7 +40,7 @@ public class ContainerViewComputer extends Container implements IContainerComput } @Override - public boolean canInteractWith( @Nonnull EntityPlayer player ) + public boolean canInteractWith( @Nonnull PlayerEntity player ) { if( computer instanceof ServerComputer ) { @@ -52,18 +58,18 @@ public class ContainerViewComputer extends Container implements IContainerComput MinecraftServer server = player.getServer(); if( server == null || !server.isCommandBlockEnabled() ) { - player.sendStatusMessage( new TextComponentTranslation( "advMode.notEnabled" ), false ); + player.sendStatusMessage( new TranslationTextComponent( "advMode.notEnabled" ), false ); return false; } else if( !player.canUseCommandBlock() ) { - player.sendStatusMessage( new TextComponentTranslation( "advMode.notAllowed" ), false ); + player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), false ); return false; } } } - return true; + return computer != null; } @Nonnull @@ -74,7 +80,7 @@ public class ContainerViewComputer extends Container implements IContainerComput } @Override - public void onContainerClosed( EntityPlayer player ) + public void onContainerClosed( PlayerEntity player ) { super.onContainerClosed( player ); input.close(); diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java index d243dc50a..72a9e54cd 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import javax.annotation.Nonnull; @@ -18,7 +18,7 @@ public interface IComputerItem default int getComputerID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java index 6c36c8ae5..3c113bd9e 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java @@ -9,7 +9,7 @@ package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.item.ItemStack; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import javax.annotation.Nonnull; @@ -24,7 +24,7 @@ public class ItemComputer extends ItemComputerBase { ItemStack result = new ItemStack( this ); if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id ); - if( label != null ) result.setDisplayName( new TextComponentString( label ) ); + if( label != null ) result.setDisplayName( new StringTextComponent( label ) ); return result; } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 377e41959..c082cc443 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -13,19 +13,19 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.computer.blocks.BlockComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.item.ItemBlock; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; -public abstract class ItemComputerBase extends ItemBlock implements IComputerItem, IMedia +public abstract class ItemComputerBase extends BlockItem implements IComputerItem, IMedia { private final ComputerFamily family; @@ -43,7 +43,7 @@ public abstract class ItemComputerBase extends ItemBlock implements IComputerIte int id = getComputerID( stack ); if( id >= 0 ) { - list.add( new TextComponentTranslation( "gui.computercraft.tooltip.computer_id", id ) + list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id ) .applyTextStyle( TextFormatting.GRAY ) ); } } @@ -68,7 +68,7 @@ public abstract class ItemComputerBase extends ItemBlock implements IComputerIte { if( label != null ) { - stack.setDisplayName( new TextComponentString( label ) ); + stack.setDisplayName( new StringTextComponent( label ) ); } else { diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index e93f77260..fe319d162 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.items.IComputerItem; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.ShapedRecipe; @@ -34,7 +34,7 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe protected abstract ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack stack ); @Override - public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) { if( !super.matches( inventory, world ) ) return false; @@ -48,7 +48,7 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inventory ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory ) { // Find our computer item and convert it. for( int i = 0; i < inventory.getSizeInventory(); i++ ) diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index 3911c3534..fee97cd68 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -13,7 +13,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.JsonUtils; +import net.minecraft.util.JSONUtils; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; @@ -42,11 +42,11 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe @Override public T read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { - String group = JsonUtils.getString( json, "group", "" ); + String group = JSONUtils.getString( json, "group", "" ); ComputerFamily family = RecipeUtil.getFamily( json, "family" ); RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json ); - ItemStack result = deserializeItem( JsonUtils.getJsonObject( json, "result" ) ); + ItemStack result = deserializeItem( JSONUtils.getJsonObject( json, "result" ) ); return create( identifier, group, template.width, template.height, template.ingredients, result, family ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java index e7604f2df..6799bc784 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.computer.recipe; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; import net.minecraft.item.ItemStack; @@ -38,7 +37,6 @@ public class ComputerUpgradeRecipe extends ComputerFamilyRecipe return SERIALIZER; } - private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ); public static final IRecipeSerializer SERIALIZER = new Serializer() { @Override @@ -46,12 +44,5 @@ public class ComputerUpgradeRecipe extends ComputerFamilyRecipe { return new ComputerUpgradeRecipe( identifier, group, width, height, ingredients, result, family ); } - - @Nonnull - @Override - public ResourceLocation getName() - { - return ID; - } }; } diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java index fe478f7c2..6fab2ce31 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.integration.charset; import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.ICapabilityProvider; import pl.asie.charset.api.wires.IBundledEmitter; @@ -30,14 +30,14 @@ final class BundledCapabilityProvider implements ICapabilityProvider } @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing side ) + public boolean hasCapability( @Nonnull Capability capability, @Nullable Direction side ) { return capability == CAPABILITY_EMITTER || capability == CAPABILITY_RECEIVER; } @Nullable @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing side ) + public T getCapability( @Nonnull Capability capability, @Nullable Direction side ) { if( capability == CAPABILITY_RECEIVER ) { @@ -62,7 +62,7 @@ final class BundledCapabilityProvider implements ICapabilityProvider { emitter = emitters[index] = () -> { int flags = 0; - for( EnumFacing facing : EnumFacing.VALUES ) flags |= tile.getBundledRedstoneOutput( facing ); + for( Direction facing : Direction.VALUES ) flags |= tile.getBundledRedstoneOutput( facing ); return toBytes( flags ); }; } diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java index e7ac4768a..a2a857025 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.integration.charset; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -18,7 +18,7 @@ import static dan200.computercraft.shared.integration.charset.IntegrationCharset public class BundledRedstoneProvider implements IBundledRedstoneProvider { @Override - public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull EnumFacing side ) + public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) { TileEntity tile = world.getTileEntity( pos ); if( tile == null || !tile.hasCapability( CAPABILITY_EMITTER, side ) ) return -1; diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java index 35c0b47fe..f659971fa 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java @@ -8,13 +8,11 @@ package dan200.computercraft.shared.integration.mcmp; import mcmultipart.MCMultiPart; import mcmultipart.api.item.ItemBlockMultipart; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.ItemBlock; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.ActionResultType; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.fml.common.Loader; @@ -27,9 +25,9 @@ public final class MCMPHooks { } - public static EnumActionResult onItemUse( ItemBlock itemBlock, EntityPlayer player, World world, @Nonnull BlockPos pos, @Nonnull EnumHand hand, @Nonnull EnumFacing facing, float hitX, float hitY, float hitZ ) + public static ActionResultType onItemUse( BlockItem itemBlock, PlayerEntity player, World world, @Nonnull BlockPos pos, @Nonnull Hand hand, @Nonnull Direction facing, float hitX, float hitY, float hitZ ) { - if( !Loader.isModLoaded( MCMultiPart.MODID ) ) return EnumActionResult.PASS; + if( !Loader.isModLoaded( MCMultiPart.MODID ) ) return ActionResultType.PASS; return ItemBlockMultipart.place( player, world, pos, hand, facing, hitX, hitY, hitZ, itemBlock, @@ -37,8 +35,8 @@ public final class MCMPHooks MCMPIntegration.multipartMap.get( itemBlock.getBlock() ), ( - ItemStack stack, EntityPlayer thisPlayer, World thisWorld, BlockPos thisPos, EnumFacing thisFacing, - float thisX, float thisY, float thisZ, IBlockState thisState + ItemStack stack, PlayerEntity thisPlayer, World thisWorld, BlockPos thisPos, Direction thisFacing, + float thisX, float thisY, float thisZ, BlockState thisState ) -> thisPlayer.canPlayerEdit( thisPos, thisFacing, stack ) && thisWorld.getBlockState( thisPos ).getBlock().isReplaceable( thisWorld, thisPos ) && diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java index 358fcda92..d3031c695 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java @@ -24,7 +24,7 @@ import mcmultipart.api.ref.MCMPCapabilities; import mcmultipart.api.slot.EnumFaceSlot; import net.minecraft.block.Block; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.capabilities.Capability; @@ -105,14 +105,14 @@ public class MCMPIntegration implements IMCMPAddon } @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public boolean hasCapability( @Nonnull Capability capability, @Nullable Direction facing ) { return capability == MCMPCapabilities.MULTIPART_TILE; } @Nullable @Override - public T getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public T getCapability( @Nonnull Capability capability, @Nullable Direction facing ) { if( capability == MCMPCapabilities.MULTIPART_TILE ) { diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java index 603ab9575..b220d33e9 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java @@ -12,9 +12,9 @@ import mcmultipart.api.multipart.IMultipart; import mcmultipart.api.slot.EnumFaceSlot; import mcmultipart.api.slot.IPartSlot; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.EnumFacing; +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; @@ -22,13 +22,13 @@ import net.minecraft.world.World; public class PartAdvancedModem implements IMultipart { @Override - public IPartSlot getSlotForPlacement( World world, BlockPos pos, IBlockState state, EnumFacing facing, float hitX, float hitY, float hitZ, EntityLivingBase placer ) + public IPartSlot getSlotForPlacement( World world, BlockPos pos, BlockState state, Direction facing, float hitX, float hitY, float hitZ, LivingEntity placer ) { return EnumFaceSlot.fromFace( state.getValue( BlockAdvancedModem.FACING ) ); } @Override - public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, IBlockState state ) + public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, BlockState state ) { return EnumFaceSlot.fromFace( state.getValue( BlockAdvancedModem.FACING ) ); } diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java index daf25450b..f96572caa 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java @@ -14,9 +14,9 @@ import mcmultipart.api.slot.EnumCenterSlot; import mcmultipart.api.slot.EnumFaceSlot; import mcmultipart.api.slot.IPartSlot; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.util.EnumFacing; +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; @@ -26,19 +26,19 @@ import javax.annotation.Nonnull; public class PartPeripheral implements IMultipart { @Override - public IPartSlot getSlotForPlacement( World world, BlockPos pos, IBlockState state, EnumFacing facing, float hitX, float hitY, float hitZ, EntityLivingBase placer ) + public IPartSlot getSlotForPlacement( World world, BlockPos pos, BlockState state, Direction facing, float hitX, float hitY, float hitZ, LivingEntity placer ) { return getSlot( state ); } @Override - public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, IBlockState state ) + public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, BlockState state ) { return getSlot( state ); } @Nonnull - private static IPartSlot getSlot( IBlockState state ) + private static IPartSlot getSlot( BlockState state ) { BlockPeripheralVariant type = state.getValue( BlockPeripheral.VARIANT ); if( type == BlockPeripheralVariant.WirelessModemUpOn || type == BlockPeripheralVariant.WirelessModemUpOff ) diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 93ff17333..9dce5d77d 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -13,17 +13,17 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; @@ -68,14 +68,14 @@ public class ItemDisk extends Item implements IMedia, IColouredItem int id = getDiskID( stack ); if( id >= 0 ) { - list.add( new TextComponentTranslation( "gui.computercraft.tooltip.disk_id", id ) + list.add( new TranslationTextComponent( "gui.computercraft.tooltip.disk_id", id ) .applyTextStyle( TextFormatting.GRAY ) ); } } } @Override - public boolean doesSneakBypassUse( ItemStack stack, IWorldReader world, BlockPos pos, EntityPlayer player ) + public boolean doesSneakBypassUse( ItemStack stack, IWorldReader world, BlockPos pos, PlayerEntity player ) { return true; } @@ -91,7 +91,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem { if( label != null ) { - stack.setDisplayName( new TextComponentString( label ) ); + stack.setDisplayName( new StringTextComponent( label ) ); } else { @@ -114,7 +114,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem public static int getDiskID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index 5c12e84d2..b0a38d1a6 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -7,17 +7,17 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.network.Containers; +import dan200.computercraft.shared.network.container.PrintoutContainerData; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.ActionResult; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumHand; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -53,15 +53,15 @@ public class ItemPrintout extends Item public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag options ) { String title = getTitle( stack ); - if( title != null && !title.isEmpty() ) list.add( new TextComponentString( title ) ); + if( title != null && !title.isEmpty() ) list.add( new StringTextComponent( title ) ); } @Nonnull @Override - public ActionResult onItemRightClick( World world, EntityPlayer player, @Nonnull EnumHand hand ) + public ActionResult onItemRightClick( World world, PlayerEntity player, @Nonnull Hand hand ) { - if( !world.isRemote ) Containers.openPrintoutGUI( player, hand ); - return new ActionResult<>( EnumActionResult.SUCCESS, player.getHeldItem( hand ) ); + if( !world.isRemote ) new PrintoutContainerData( hand ).open( player ); + return new ActionResult<>( ActionResultType.SUCCESS, player.getHeldItem( hand ) ); } @Nonnull @@ -73,7 +73,7 @@ public class ItemPrintout extends Item if( title != null ) stack.getOrCreateTag().putString( NBT_TITLE, title ); if( text != null ) { - NBTTagCompound tag = stack.getOrCreateTag(); + CompoundNBT tag = stack.getOrCreateTag(); tag.putInt( NBT_PAGES, text.length / LINES_PER_PAGE ); for( int i = 0; i < text.length; i++ ) { @@ -82,7 +82,7 @@ public class ItemPrintout extends Item } if( colours != null ) { - NBTTagCompound tag = stack.getOrCreateTag(); + CompoundNBT tag = stack.getOrCreateTag(); for( int i = 0; i < colours.length; i++ ) { if( colours[i] != null ) tag.putString( NBT_LINE_COLOUR + i, colours[i] ); @@ -118,13 +118,13 @@ public class ItemPrintout extends Item public static String getTitle( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : null; } public static int getPageCount( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_PAGES ) ? nbt.getInt( NBT_PAGES ) : 1; } @@ -140,7 +140,7 @@ public class ItemPrintout extends Item private static String[] getLines( @Nonnull ItemStack stack, String prefix ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); int numLines = getPageCount( stack ) * LINES_PER_PAGE; String[] lines = new String[numLines]; for( int i = 0; i < lines.length; i++ ) diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index 106d8968e..66251a061 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -13,15 +13,15 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.core.filesystem.SubMount; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.util.ITooltipFlag; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; @@ -50,11 +50,11 @@ public class ItemTreasureDisk extends Item implements IMedia public void addInformation( ItemStack stack, @Nullable World world, List list, ITooltipFlag tooltipOptions ) { String label = getTitle( stack ); - if( !label.isEmpty() ) list.add( new TextComponentString( label ) ); + if( !label.isEmpty() ) list.add( new StringTextComponent( label ) ); } @Override - public boolean doesSneakBypassUse( @Nonnull ItemStack stack, IWorldReader world, BlockPos pos, EntityPlayer player ) + public boolean doesSneakBypassUse( @Nonnull ItemStack stack, IWorldReader world, BlockPos pos, PlayerEntity player ) { return true; } @@ -94,7 +94,7 @@ public class ItemTreasureDisk extends Item implements IMedia public static ItemStack create( String subPath, int colourIndex ) { ItemStack result = new ItemStack( ComputerCraft.Items.treasureDisk ); - NBTTagCompound nbt = result.getOrCreateTag(); + CompoundNBT nbt = result.getOrCreateTag(); nbt.putString( NBT_SUB_PATH, subPath ); int slash = subPath.indexOf( '/' ); @@ -121,20 +121,20 @@ public class ItemTreasureDisk extends Item implements IMedia @Nonnull private static String getTitle( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_TITLE ) ? nbt.getString( NBT_TITLE ) : "'alongtimeago' by dan200"; } @Nonnull private static String getSubPath( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_SUB_PATH ) ? nbt.getString( NBT_SUB_PATH ) : "dan200/alongtimeago"; } public static int getColour( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.Blue.getHex(); } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index c6341bc61..243f57625 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -8,8 +8,8 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.shared.util.RecordUtil; -import net.minecraft.item.ItemRecord; import net.minecraft.item.ItemStack; +import net.minecraft.item.MusicDiscItem; import net.minecraft.util.SoundEvent; import javax.annotation.Nonnull; @@ -40,6 +40,6 @@ public final class RecordMedia implements IMedia @Override public SoundEvent getAudio( @Nonnull ItemStack stack ) { - return ((ItemRecord) stack.getItem()).getSound(); + return ((MusicDiscItem) stack.getItem()).getSound(); } } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index f28bb8f2f..21e8de7d7 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -6,26 +6,25 @@ package dan200.computercraft.shared.media.recipes; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemDisk; -import dan200.computercraft.shared.util.AbstractRecipe; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ColourTracker; import dan200.computercraft.shared.util.ColourUtils; -import net.minecraft.init.Items; -import net.minecraft.inventory.IInventory; -import net.minecraft.item.EnumDyeColor; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.DyeColor; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.crafting.SpecialRecipe; +import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.Tags; import javax.annotation.Nonnull; -public class DiskRecipe extends AbstractRecipe +public class DiskRecipe extends SpecialRecipe { private final Ingredient paper = Ingredient.fromItems( Items.PAPER ); private final Ingredient redstone = Ingredient.fromTag( Tags.Items.DUSTS_REDSTONE ); @@ -36,7 +35,7 @@ public class DiskRecipe extends AbstractRecipe } @Override - public boolean matches( @Nonnull IInventory inv, @Nonnull World world ) + public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) { boolean paperFound = false; boolean redstoneFound = false; @@ -69,7 +68,7 @@ public class DiskRecipe extends AbstractRecipe @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inv ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inv ) { ColourTracker tracker = new ColourTracker(); @@ -81,7 +80,7 @@ public class DiskRecipe extends AbstractRecipe if( !paper.test( stack ) && !redstone.test( stack ) ) { - EnumDyeColor dye = ColourUtils.getStackColour( stack ); + DyeColor dye = ColourUtils.getStackColour( stack ); if( dye == null ) continue; Colour colour = Colour.VALUES[dye.getId()]; @@ -112,7 +111,5 @@ public class DiskRecipe extends AbstractRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( - ComputerCraft.MOD_ID + ":disk", DiskRecipe::new - ); + public static final IRecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( DiskRecipe::new ); } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index 12c7c3a16..1bd0ddf52 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -6,24 +6,23 @@ package dan200.computercraft.shared.media.recipes; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.util.AbstractRecipe; -import net.minecraft.init.Items; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.crafting.SpecialRecipe; +import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import javax.annotation.Nonnull; -public final class PrintoutRecipe extends AbstractRecipe +public final class PrintoutRecipe extends SpecialRecipe { - private final Ingredient paper = Ingredient.fromItems( Items.PAPER ); - private final Ingredient leather = Ingredient.fromItems( Items.LEATHER ); + private final Ingredient paper = Ingredient.fromItems( net.minecraft.item.Items.PAPER ); + private final Ingredient leather = Ingredient.fromItems( net.minecraft.item.Items.LEATHER ); private final Ingredient string = Ingredient.fromItems( Items.STRING ); private PrintoutRecipe( ResourceLocation id ) @@ -45,14 +44,14 @@ public final class PrintoutRecipe extends AbstractRecipe } @Override - public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) { return !getCraftingResult( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inventory ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory ) { // See if we match the recipe, and extract the input disk ID and dye colour int numPages = 0; @@ -165,7 +164,5 @@ public final class PrintoutRecipe extends AbstractRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( - ComputerCraft.MOD_ID + ":printout", PrintoutRecipe::new - ); + public static final IRecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( PrintoutRecipe::new ); } diff --git a/src/main/java/dan200/computercraft/shared/network/Containers.java b/src/main/java/dan200/computercraft/shared/network/Containers.java deleted file mode 100644 index b59b45d16..000000000 --- a/src/main/java/dan200/computercraft/shared/network/Containers.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.network; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.common.ContainerHeldItem; -import dan200.computercraft.shared.computer.blocks.TileComputer; -import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.computer.inventory.ContainerComputer; -import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.network.container.*; -import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; -import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; -import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; -import dan200.computercraft.shared.peripheral.printer.TilePrinter; -import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; -import dan200.computercraft.shared.pocket.items.ItemPocketComputer; -import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; - -public final class Containers -{ - private Containers() - { - } - - public static void openDiskDriveGUI( EntityPlayer player, TileDiskDrive drive ) - { - TileEntityContainerType.diskDrive( drive.getPos() ).open( player ); - } - - public static void openComputerGUI( EntityPlayer player, TileComputer computer ) - { - TileEntityContainerType.computer( computer.getPos() ).open( player ); - } - - public static void openPrinterGUI( EntityPlayer player, TilePrinter printer ) - { - TileEntityContainerType.printer( printer.getPos() ).open( player ); - } - - public static void openTurtleGUI( EntityPlayer player, TileTurtle turtle ) - { - TileEntityContainerType.turtle( turtle.getPos() ).open( player ); - } - - public static void openPrintoutGUI( EntityPlayer player, EnumHand hand ) - { - ItemStack stack = player.getHeldItem( hand ); - Item item = stack.getItem(); - if( !(item instanceof ItemPrintout) ) return; - - new PrintoutContainerType( hand ).open( player ); - } - - public static void openPocketComputerGUI( EntityPlayer player, EnumHand hand ) - { - ItemStack stack = player.getHeldItem( hand ); - Item item = stack.getItem(); - if( !(item instanceof ItemPocketComputer) ) return; - - new PocketComputerContainerType( hand ).open( player ); - } - - public static void openComputerGUI( EntityPlayer player, ServerComputer computer ) - { - new ViewComputerContainerType( computer ).open( player ); - } - - public static void setup() - { - ContainerType.register( TileEntityContainerType::computer, ( packet, player ) -> - new ContainerComputer( (TileComputer) packet.getTileEntity( player ) ) ); - ContainerType.register( TileEntityContainerType::turtle, ( packet, player ) -> { - TileTurtle turtle = (TileTurtle) packet.getTileEntity( player ); - return new ContainerTurtle( player.inventory, turtle.getAccess(), turtle.getServerComputer() ); - } ); - ContainerType.register( TileEntityContainerType::diskDrive, ( packet, player ) -> - new ContainerDiskDrive( player.inventory, (TileDiskDrive) packet.getTileEntity( player ) ) ); - ContainerType.register( TileEntityContainerType::printer, ( packet, player ) -> - new ContainerPrinter( player.inventory, (TilePrinter) packet.getTileEntity( player ) ) ); - - ContainerType.register( PocketComputerContainerType::new, ( packet, player ) -> new ContainerPocketComputer( player, packet.hand ) ); - ContainerType.register( PrintoutContainerType::new, ( packet, player ) -> new ContainerHeldItem( player, packet.hand ) ); - ContainerType.register( ViewComputerContainerType::new, ( packet, player ) -> new ContainerViewComputer( ComputerCraft.serverComputerRegistry.get( packet.instanceId ) ) ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 4afe60ce5..fb628b11c 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -9,8 +9,8 @@ package dan200.computercraft.shared.network; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.network.client.*; import dan200.computercraft.shared.network.server.*; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.Vec3d; @@ -55,14 +55,14 @@ public final class NetworkHandler registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); } - public static void sendToPlayer( EntityPlayer player, NetworkMessage packet ) + public static void sendToPlayer( PlayerEntity player, NetworkMessage packet ) { - network.sendTo( packet, ((EntityPlayerMP) player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT ); + network.sendTo( packet, ((ServerPlayerEntity) player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT ); } public static void sendToAllPlayers( NetworkMessage packet ) { - for( EntityPlayerMP player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) + for( ServerPlayerEntity player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) { sendToPlayer( player, packet ); } @@ -75,7 +75,7 @@ public final class NetworkHandler public static void sendToAllAround( NetworkMessage packet, World world, Vec3d pos, double range ) { - for( EntityPlayerMP player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) + for( ServerPlayerEntity player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) { if( player.getEntityWorld() != world ) continue; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java index 77cf5605e..bc0420947 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -20,7 +20,7 @@ import javax.annotation.Nonnull; public class ComputerDataClientMessage extends ComputerClientMessage { private ComputerState state; - private NBTTagCompound userData; + private CompoundNBT userData; public ComputerDataClientMessage( ServerComputer computer ) { diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index 914101143..ac3d0495a 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.network.client; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -14,9 +14,9 @@ import javax.annotation.Nonnull; public class ComputerTerminalClientMessage extends ComputerClientMessage { - private NBTTagCompound tag; + private CompoundNBT tag; - public ComputerTerminalClientMessage( int instanceId, NBTTagCompound tag ) + public ComputerTerminalClientMessage( int instanceId, CompoundNBT tag ) { super( instanceId ); this.tag = tag; diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 737468d09..822d6fe29 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -82,7 +82,7 @@ public class PlayRecordClientMessage implements NetworkMessage public void handle( NetworkEvent.Context context ) { Minecraft mc = Minecraft.getInstance(); - mc.world.playRecord( pos, soundEvent ); - if( name != null ) mc.ingameGUI.setRecordPlayingMessage( name ); + mc.worldRenderer.playRecord( soundEvent, pos ); + if( name != null ) mc.field_71456_v.setRecordPlayingMessage( name ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java new file mode 100644 index 000000000..edfa91965 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -0,0 +1,41 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.container; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkHooks; + +import javax.annotation.Nonnull; +import java.util.function.Function; + +/** + * A horrible hack to allow opening GUIs until Forge adds a built-in system. + */ +public interface ContainerData extends INamedContainerProvider +{ + void toBytes( PacketBuffer buf ); + + default void open( PlayerEntity player ) + { + NetworkHooks.openGui( (ServerPlayerEntity) player, this, this::toBytes ); + } + + @Nonnull + T createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ); + + static > net.minecraft.inventory.container.ContainerType create( Function reader ) + { + return new net.minecraft.inventory.container.ContainerType<>( + ( id, player ) -> reader.apply( null ).createMenu( id, player, player.player ) + ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerType.java deleted file mode 100644 index 27ca78681..000000000 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerType.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.network.container; - -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.world.IInteractionObject; -import net.minecraftforge.fml.network.NetworkHooks; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.function.Supplier; - -/** - * A horrible hack to allow opening GUIs until Forge adds a built-in system. - */ -public interface ContainerType extends IInteractionObject -{ - @Nonnull - ResourceLocation getId(); - - void toBytes( PacketBuffer buf ); - - void fromBytes( PacketBuffer buf ); - - @Nonnull - @Override - @SuppressWarnings( "unchecked" ) - default T createContainer( @Nonnull InventoryPlayer inventoryPlayer, @Nonnull EntityPlayer entityPlayer ) - { - return ((BiFunction, EntityPlayer, T>) containerFactories.get( getId() )).apply( this, entityPlayer ); - } - - @Nonnull - @Override - default String getGuiID() - { - return getId().toString(); - } - - @Nonnull - @Override - default ITextComponent getName() - { - return new TextComponentString( "" ); - } - - @Override - default boolean hasCustomName() - { - return false; - } - - @Nullable - @Override - default ITextComponent getCustomName() - { - return null; - } - - default void open( EntityPlayer player ) - { - NetworkHooks.openGui( (EntityPlayerMP) player, this, this::toBytes ); - } - - static > void register( Supplier containerType, BiFunction factory ) - { - factories.put( containerType.get().getId(), containerType ); - containerFactories.put( containerType.get().getId(), factory ); - } - - static > void registerGui( Supplier containerType, BiFunction factory ) - { - guiFactories.put( containerType.get().getId(), factory ); - } - - static > void registerGui( Supplier containerType, Function factory ) - { - registerGui( containerType, ( type, player ) -> { - @SuppressWarnings( "unchecked" ) - C container = ((BiFunction) containerFactories.get( type.getId() )).apply( type, player ); - return container == null ? null : factory.apply( container ); - } ); - } - - Map>> factories = new HashMap<>(); - Map, EntityPlayer, GuiContainer>> guiFactories = new HashMap<>(); - Map, EntityPlayer, ? extends Container>> containerFactories = new HashMap<>(); -} diff --git a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java new file mode 100644 index 000000000..b1cc11093 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java @@ -0,0 +1,57 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.container; + +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.Hand; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; + +import javax.annotation.Nonnull; + +/** + * Opens a pocket computer GUI based on the held item + * + * @see dan200.computercraft.shared.pocket.items.ItemPocketComputer + */ +public class PocketComputerContainerData implements ContainerData +{ + private final Hand hand; + + public PocketComputerContainerData( Hand hand ) + { + this.hand = hand; + } + + public PocketComputerContainerData( PacketBuffer buffer ) + { + hand = buffer.readEnumValue( Hand.class ); + } + + @Override + public void toBytes( @Nonnull PacketBuffer buf ) + { + buf.writeEnumValue( hand ); + } + + @Nonnull + @Override + public ITextComponent getDisplayName() + { + return new TranslationTextComponent( "gui.computercraft.pocket" ); + } + + @Nonnull + @Override + public ContainerPocketComputer createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerPocketComputer( id, player, hand ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java deleted file mode 100644 index 859b369aa..000000000 --- a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerType.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.network.container; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumHand; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; - -/** - * Opens a pocket computer GUI based on the held item - * - * @see dan200.computercraft.shared.pocket.items.ItemPocketComputer - */ -public class PocketComputerContainerType implements ContainerType -{ - public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_gui" ); - - public EnumHand hand; - - public PocketComputerContainerType( EnumHand hand ) - { - this.hand = hand; - } - - public PocketComputerContainerType() - { - } - - @Nonnull - @Override - public ResourceLocation getId() - { - return ID; - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - buf.writeEnumValue( hand ); - } - - @Override - public void fromBytes( @Nonnull PacketBuffer buf ) - { - hand = buf.readEnumValue( EnumHand.class ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java new file mode 100644 index 000000000..48d58c74d --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java @@ -0,0 +1,57 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.container; + +import dan200.computercraft.shared.common.ContainerHeldItem; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.Hand; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; + +import javax.annotation.Nonnull; + +/** + * Opens a printout GUI based on the currently held item + * + * @see dan200.computercraft.shared.media.items.ItemPrintout + */ +public class PrintoutContainerData implements ContainerData +{ + private final Hand hand; + + public PrintoutContainerData( Hand hand ) + { + this.hand = hand; + } + + public PrintoutContainerData( PacketBuffer buffer ) + { + hand = buffer.readEnumValue( Hand.class ); + } + + @Override + public void toBytes( PacketBuffer buf ) + { + buf.writeEnumValue( hand ); + } + + @Nonnull + @Override + public ITextComponent getDisplayName() + { + return new TranslationTextComponent( "gui.computercraft.printout" ); + } + + @Nonnull + @Override + public ContainerHeldItem createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerHeldItem( ContainerHeldItem.PRINTOUT_TYPE, id, player, hand ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java deleted file mode 100644 index b89244d75..000000000 --- a/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerType.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.network.container; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.common.ContainerHeldItem; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.EnumHand; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; - -/** - * Opens a printout GUI based on the currently held item - * - * @see dan200.computercraft.shared.media.items.ItemPrintout - */ -public class PrintoutContainerType implements ContainerType -{ - public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "printout_gui" ); - - public EnumHand hand; - - public PrintoutContainerType( EnumHand hand ) - { - this.hand = hand; - } - - public PrintoutContainerType() - { - } - - @Nonnull - @Override - public ResourceLocation getId() - { - return ID; - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - buf.writeEnumValue( hand ); - } - - @Override - public void fromBytes( @Nonnull PacketBuffer buf ) - { - hand = buf.readEnumValue( EnumHand.class ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java deleted file mode 100644 index 48185e1b5..000000000 --- a/src/main/java/dan200/computercraft/shared/network/container/TileEntityContainerType.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.network.container; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.inventory.ContainerComputer; -import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; -import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; -import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.network.PacketBuffer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; - -import javax.annotation.Nonnull; - -/** - * Opens a GUI on a specific ComputerCraft TileEntity - * - * @see dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive - * @see dan200.computercraft.shared.peripheral.printer.TilePrinter - * @see dan200.computercraft.shared.computer.blocks.TileComputer - */ -public final class TileEntityContainerType implements ContainerType -{ - private static final ResourceLocation DISK_DRIVE = new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ); - private static final ResourceLocation PRINTER = new ResourceLocation( ComputerCraft.MOD_ID, "printer" ); - private static final ResourceLocation COMPUTER = new ResourceLocation( ComputerCraft.MOD_ID, "computer" ); - private static final ResourceLocation TURTLE = new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ); - - public BlockPos pos; - private final ResourceLocation id; - - private TileEntityContainerType( ResourceLocation id, BlockPos pos ) - { - this.id = id; - this.pos = pos; - } - - private TileEntityContainerType( ResourceLocation id ) - { - this.id = id; - } - - @Nonnull - @Override - public ResourceLocation getId() - { - return id; - } - - @Override - public void toBytes( PacketBuffer buf ) - { - buf.writeBlockPos( pos ); - } - - @Override - public void fromBytes( PacketBuffer buf ) - { - pos = buf.readBlockPos(); - } - - public TileEntity getTileEntity( EntityPlayer entity ) - { - return entity.world.getTileEntity( pos ); - } - - public static TileEntityContainerType diskDrive() - { - return new TileEntityContainerType<>( DISK_DRIVE ); - } - - public static TileEntityContainerType diskDrive( BlockPos pos ) - { - return new TileEntityContainerType<>( DISK_DRIVE, pos ); - } - - public static TileEntityContainerType printer() - { - return new TileEntityContainerType<>( PRINTER ); - } - - public static TileEntityContainerType printer( BlockPos pos ) - { - return new TileEntityContainerType<>( PRINTER, pos ); - } - - public static TileEntityContainerType computer() - { - return new TileEntityContainerType<>( COMPUTER ); - } - - public static TileEntityContainerType computer( BlockPos pos ) - { - return new TileEntityContainerType<>( COMPUTER, pos ); - } - - public static TileEntityContainerType turtle() - { - return new TileEntityContainerType<>( TURTLE ); - } - - public static TileEntityContainerType turtle( BlockPos pos ) - { - return new TileEntityContainerType<>( TURTLE, pos ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerType.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java similarity index 54% rename from src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerType.java rename to src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index ff541796a..adadcc8e7 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerType.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -9,10 +9,15 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; import javax.annotation.Nonnull; @@ -21,16 +26,16 @@ import javax.annotation.Nonnull; * * @see dan200.computercraft.shared.command.CommandComputerCraft */ -public class ViewComputerContainerType implements ContainerType +public class ViewComputerContainerData implements ContainerData { public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "view_computer_gui" ); - public int instanceId; - public int width; - public int height; - public ComputerFamily family; + private final int instanceId; + private final int width; + private final int height; + private final ComputerFamily family; - public ViewComputerContainerType( ServerComputer computer ) + public ViewComputerContainerData( ServerComputer computer ) { instanceId = computer.getInstanceID(); Terminal terminal = computer.getTerminal(); @@ -39,18 +44,19 @@ public class ViewComputerContainerType implements ContainerType properties ) + protected void fillStateContainer( StateContainer.Builder properties ) { properties.add( FACING, STATE ); } @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext placement ) + public BlockState getStateForPlacement( BlockItemUseContext placement ) { return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); } @Override - public void harvestBlock( @Nonnull World world, EntityPlayer player, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nullable TileEntity te, ItemStack stack ) + public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, ItemStack stack ) { if( te instanceof INameable && ((INameable) te).hasCustomName() ) { - player.addStat( StatList.BLOCK_MINED.get( this ) ); + player.addStat( Stats.BLOCK_MINED.get( this ) ); player.addExhaustion( 0.005F ); ItemStack result = new ItemStack( this ); @@ -73,7 +73,7 @@ public class BlockDiskDrive extends BlockGeneric } @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack ) + public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) { if( stack.hasDisplayName() ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index bde384e18..dcef9ae3d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -6,51 +6,59 @@ package dan200.computercraft.shared.peripheral.diskdrive; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; -import net.minecraft.inventory.Slot; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; public class ContainerDiskDrive extends Container { - private final TileDiskDrive m_diskDrive; + public static final ContainerType TYPE = new ContainerType<>( ContainerDiskDrive::new ); - public ContainerDiskDrive( IInventory playerInventory, TileDiskDrive diskDrive ) + private final IInventory inventory; + + public ContainerDiskDrive( int id, PlayerInventory player, IInventory inventory ) { - m_diskDrive = diskDrive; - addSlot( new Slot( m_diskDrive, 0, 8 + 4 * 18, 35 ) ); + super( TYPE, id ); + + this.inventory = inventory; + + addSlot( new Slot( this.inventory, 0, 8 + 4 * 18, 35 ) ); for( int y = 0; y < 3; y++ ) { for( int x = 0; x < 9; x++ ) { - addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); + addSlot( new Slot( player, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); } } for( int x = 0; x < 9; x++ ) { - addSlot( new Slot( playerInventory, x, 8 + x * 18, 142 ) ); + addSlot( new Slot( player, x, 8 + x * 18, 142 ) ); } } - public TileDiskDrive getDiskDrive() + private ContainerDiskDrive( int id, PlayerInventory player ) { - return m_diskDrive; + this( id, player, new Inventory( 1 ) ); } @Override - public boolean canInteractWith( @Nonnull EntityPlayer player ) + public boolean canInteractWith( @Nonnull PlayerEntity player ) { - return m_diskDrive.isUsableByPlayer( player ); + return inventory.isUsableByPlayer( player ); } @Nonnull @Override - public ItemStack transferStackInSlot( EntityPlayer player, int slotIndex ) + public ItemStack transferStackInSlot( PlayerEntity player, int slotIndex ) { Slot slot = inventorySlots.get( slotIndex ); if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 09f534730..2eb317d78 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -15,21 +15,27 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.util.DefaultInventory; import dan200.computercraft.shared.util.InventoryUtil; -import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.RecordUtil; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.block.BlockState; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.text.ITextComponent; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; @@ -41,12 +47,12 @@ import java.util.Set; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; -public final class TileDiskDrive extends TileGeneric implements DefaultInventory, ITickable, IPeripheralTile +public final class TileDiskDrive extends TileGeneric implements DefaultInventory, ITickableTileEntity, IPeripheralTile, INameable, INamedContainerProvider { private static final String NBT_NAME = "CustomName"; private static final String NBT_ITEM = "Item"; - public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ), TileDiskDrive::new ); @@ -94,7 +100,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { if( player.isSneaking() ) { @@ -111,24 +117,24 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory else { // Open the GUI - if( !getWorld().isRemote ) Containers.openDiskDriveGUI( player, this ); + if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this ); return true; } } - public EnumFacing getDirection() + public Direction getDirection() { return getBlockState().get( BlockDiskDrive.FACING ); } @Override - public void read( NBTTagCompound nbt ) + public void read( CompoundNBT nbt ) { super.read( nbt ); customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; if( nbt.contains( NBT_ITEM ) ) { - NBTTagCompound item = nbt.getCompound( NBT_ITEM ); + CompoundNBT item = nbt.getCompound( NBT_ITEM ); m_diskStack = ItemStack.read( item ); m_diskMount = null; } @@ -136,13 +142,13 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull @Override - public NBTTagCompound write( NBTTagCompound nbt ) + public CompoundNBT write( CompoundNBT nbt ) { if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); if( !m_diskStack.isEmpty() ) { - NBTTagCompound item = new NBTTagCompound(); + CompoundNBT item = new CompoundNBT(); m_diskStack.write( item ); nbt.put( NBT_ITEM, item ); } @@ -295,7 +301,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public boolean isUsableByPlayer( @Nonnull EntityPlayer player ) + public boolean isUsableByPlayer( @Nonnull PlayerEntity player ) { return isUsable( player, false ); } @@ -307,7 +313,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { return new DiskDrivePeripheral( this ); } @@ -467,7 +473,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private void updateBlockState( DiskDriveState state ) { - IBlockState blockState = getBlockState(); + BlockState blockState = getBlockState(); if( blockState.get( BlockDiskDrive.STATE ) == state ) return; getWorld().setBlockState( getPos(), blockState.with( BlockDiskDrive.STATE, state ) ); @@ -486,7 +492,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory int zOff = 0; if( !destroyed ) { - EnumFacing dir = getDirection(); + Direction dir = getDirection(); xOff = dir.getXOffset(); zOff = dir.getZOffset(); } @@ -495,17 +501,15 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory double x = pos.getX() + 0.5 + xOff * 0.5; double y = pos.getY() + 0.75; double z = pos.getZ() + 0.5 + zOff * 0.5; - EntityItem entityitem = new EntityItem( getWorld(), x, y, z, disks ); - entityitem.motionX = xOff * 0.15; - entityitem.motionY = 0.0; - entityitem.motionZ = zOff * 0.15; + ItemEntity entityitem = new ItemEntity( getWorld(), x, y, z, disks ); + entityitem.setVelocity( xOff * 0.15, 0, zOff * 0.15 ); - getWorld().spawnEntity( entityitem ); + getWorld().func_217376_c( entityitem ); if( !destroyed ) getWorld().playBroadcastSound( 1000, getPos(), 0 ); } @Override - protected void readDescription( @Nonnull NBTTagCompound nbt ) + protected void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; @@ -514,13 +518,13 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); if( !m_diskStack.isEmpty() ) { - NBTTagCompound item = new NBTTagCompound(); + CompoundNBT item = new CompoundNBT(); m_diskStack.write( item ); nbt.put( NBT_ITEM, item ); } @@ -549,7 +553,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability cap, @Nullable final EnumFacing side ) + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable final Direction side ) { if( cap == ITEM_HANDLER_CAPABILITY ) { @@ -578,4 +582,17 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { return customName != null ? customName : getBlockState().getBlock().getNameTextComponent(); } + + @Override + public ITextComponent getDisplayName() + { + return getName(); + } + + @Nonnull + @Override + public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerDiskDrive( id, inventory, this ); + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java index 697ab044c..4aab12684 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.peripheral.modem; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; @@ -24,7 +24,7 @@ public final class ModemShapes }; @Nonnull - public static VoxelShape getBounds( EnumFacing facing ) + public static VoxelShape getBounds( Direction facing ) { int direction = facing.ordinal(); return direction < BOXES.length ? BOXES[direction] : VoxelShapes.fullCube(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 3de458af3..e0f5d8e83 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -10,13 +10,12 @@ import com.google.common.collect.ImmutableMap; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.shared.common.BlockGeneric; -import dan200.computercraft.shared.util.WaterloggableBlock; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; -import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.block.BlockState; +import net.minecraft.block.IWaterLoggable; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.fluid.IFluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; @@ -24,21 +23,25 @@ import net.minecraft.state.BooleanProperty; import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; -import net.minecraft.world.IWorldReaderBase; +import net.minecraft.world.IWorldReader; import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.EnumMap; -public class BlockCable extends BlockGeneric implements WaterloggableBlock +import static dan200.computercraft.shared.util.WaterloggableHelpers.*; + +public class BlockCable extends BlockGeneric implements IWaterLoggable { public static final EnumProperty MODEM = EnumProperty.create( "modem", CableModemVariant.class ); public static final BooleanProperty CABLE = BooleanProperty.create( "cable" ); @@ -50,11 +53,11 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock private static final BooleanProperty UP = BooleanProperty.create( "up" ); private static final BooleanProperty DOWN = BooleanProperty.create( "down" ); - static final EnumMap CONNECTIONS = - new EnumMap<>( new ImmutableMap.Builder() - .put( EnumFacing.DOWN, DOWN ).put( EnumFacing.UP, UP ) - .put( EnumFacing.NORTH, NORTH ).put( EnumFacing.SOUTH, SOUTH ) - .put( EnumFacing.WEST, WEST ).put( EnumFacing.EAST, EAST ) + static final EnumMap CONNECTIONS = + new EnumMap<>( new ImmutableMap.Builder() + .put( Direction.DOWN, DOWN ).put( Direction.UP, UP ) + .put( Direction.NORTH, NORTH ).put( Direction.SOUTH, SOUTH ) + .put( Direction.WEST, WEST ).put( Direction.EAST, EAST ) .build() ); public BlockCable( Properties settings ) @@ -72,17 +75,17 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock } @Override - protected void fillStateContainer( StateContainer.Builder builder ) + protected void fillStateContainer( StateContainer.Builder builder ) { builder.add( MODEM, CABLE, NORTH, SOUTH, EAST, WEST, UP, DOWN, WATERLOGGED ); } - public static boolean canConnectIn( IBlockState state, EnumFacing direction ) + public static boolean canConnectIn( BlockState state, Direction direction ) { return state.get( BlockCable.CABLE ) && state.get( BlockCable.MODEM ).getFacing() != direction; } - public static boolean doesConnectVisually( IBlockState state, IBlockReader world, BlockPos pos, EnumFacing direction ) + public static boolean doesConnectVisually( BlockState state, IBlockReader world, BlockPos pos, Direction direction ) { if( !state.get( CABLE ) ) return false; if( state.get( MODEM ).getFacing() == direction ) return true; @@ -92,18 +95,21 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock @Nonnull @Override @Deprecated - public VoxelShape getShape( IBlockState state, IBlockReader world, BlockPos pos ) + public VoxelShape getShape( BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context ) { return CableShapes.getShape( state ); } @Override - public boolean removedByPlayer( IBlockState state, World world, BlockPos pos, EntityPlayer player, boolean willHarvest, IFluidState fluid ) + public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid ) { if( state.get( CABLE ) && state.get( MODEM ).getFacing() != null ) { - RayTraceResult hit = Block.collisionRayTrace( state, world, pos, WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ) ); - if( hit != null ) + BlockRayTraceResult hit = world.func_217299_a( new RayTraceContext( + WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ), + RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player + ) ); + if( hit.getType() == RayTraceResult.Type.BLOCK ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileCable && tile.hasWorld() ) @@ -111,9 +117,9 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock TileCable cable = (TileCable) tile; ItemStack item; - IBlockState newState; + BlockState newState; - if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) + if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) { newState = state.with( MODEM, CableModemVariant.None ); item = new ItemStack( ComputerCraft.Items.wiredModem ); @@ -128,7 +134,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock cable.modemChanged(); cable.connectionsChanged(); - if( !world.isRemote && !player.abilities.isCreativeMode ) + if( !world.isRemote && !player.playerAbilities.isCreativeMode ) { Block.spawnAsEntity( world, pos, item ); } @@ -141,18 +147,11 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock return super.removedByPlayer( state, world, pos, player, willHarvest, fluid ); } - @Override - public void getDrops( IBlockState state, NonNullList drops, World world, BlockPos pos, int fortune ) - { - if( state.get( CABLE ) ) drops.add( new ItemStack( ComputerCraft.Items.cable ) ); - if( state.get( MODEM ) != CableModemVariant.None ) drops.add( new ItemStack( ComputerCraft.Items.cable ) ); - } - @Nonnull @Override - public ItemStack getPickBlock( IBlockState state, RayTraceResult hit, IBlockReader world, BlockPos pos, EntityPlayer player ) + public ItemStack getPickBlock( BlockState state, RayTraceResult hit, IBlockReader world, BlockPos pos, PlayerEntity player ) { - EnumFacing modem = state.get( MODEM ).getFacing(); + Direction modem = state.get( MODEM ).getFacing(); boolean cable = state.get( CABLE ); // If we've only got one, just use that. @@ -160,14 +159,14 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock if( modem == null ) return new ItemStack( ComputerCraft.Items.cable ); // We've a modem and cable, so try to work out which one we're interacting with - return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.hitVec.subtract( pos.getX(), pos.getY(), pos.getZ() ) ) + return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? new ItemStack( ComputerCraft.Items.wiredModem ) : new ItemStack( ComputerCraft.Items.cable ); } @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack ) + public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileCable ) @@ -182,7 +181,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock @Nonnull @Override @Deprecated - public IFluidState getFluidState( IBlockState state ) + public IFluidState getFluidState( BlockState state ) { return getWaterloggedFluidState( state ); } @@ -190,7 +189,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock @Nonnull @Override @Deprecated - public IBlockState updatePostPlacement( @Nonnull IBlockState state, EnumFacing side, IBlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + public BlockState updatePostPlacement( @Nonnull BlockState state, Direction side, BlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); // Should never happen, but handle the case where we've no modem or cable. @@ -204,21 +203,21 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock @Override @Deprecated - public boolean isValidPosition( IBlockState state, IWorldReaderBase world, BlockPos pos ) + public boolean isValidPosition( BlockState state, IWorldReader world, BlockPos pos ) { - EnumFacing facing = state.get( MODEM ).getFacing(); + Direction facing = state.get( MODEM ).getFacing(); if( facing == null ) return true; BlockPos offsetPos = pos.offset( facing ); - IBlockState offsetState = world.getBlockState( offsetPos ); - return offsetState.getBlockFaceShape( world, offsetPos, facing.getOpposite() ) == BlockFaceShape.SOLID; + BlockState offsetState = world.getBlockState( offsetPos ); + return Block.func_220056_d( offsetState, world, offsetPos, facing.getOpposite() ); // hasSolidTop ?? } @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext context ) + public BlockState getStateForPlacement( BlockItemUseContext context ) { - IBlockState state = getDefaultState() + BlockState state = getDefaultState() .with( WATERLOGGED, getWaterloggedStateForPlacement( context ) ); if( context.getItem().getItem() instanceof ItemBlockCable.Cable ) @@ -233,17 +232,17 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock } } - public static IBlockState correctConnections( World world, BlockPos pos, IBlockState state ) + public static BlockState correctConnections( World world, BlockPos pos, BlockState state ) { if( state.get( CABLE ) ) { return state - .with( NORTH, doesConnectVisually( state, world, pos, EnumFacing.NORTH ) ) - .with( SOUTH, doesConnectVisually( state, world, pos, EnumFacing.SOUTH ) ) - .with( EAST, doesConnectVisually( state, world, pos, EnumFacing.EAST ) ) - .with( WEST, doesConnectVisually( state, world, pos, EnumFacing.WEST ) ) - .with( UP, doesConnectVisually( state, world, pos, EnumFacing.UP ) ) - .with( DOWN, doesConnectVisually( state, world, pos, EnumFacing.DOWN ) ); + .with( NORTH, doesConnectVisually( state, world, pos, Direction.NORTH ) ) + .with( SOUTH, doesConnectVisually( state, world, pos, Direction.SOUTH ) ) + .with( EAST, doesConnectVisually( state, world, pos, Direction.EAST ) ) + .with( WEST, doesConnectVisually( state, world, pos, Direction.WEST ) ) + .with( UP, doesConnectVisually( state, world, pos, Direction.UP ) ) + .with( DOWN, doesConnectVisually( state, world, pos, Direction.DOWN ) ); } else { @@ -255,23 +254,7 @@ public class BlockCable extends BlockGeneric implements WaterloggableBlock @Override @Deprecated - public final boolean isFullCube( IBlockState state ) - { - return false; - } - - - @Nonnull - @Override - @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockReader worldIn, IBlockState state, BlockPos pos, EnumFacing face ) - { - return BlockFaceShape.UNDEFINED; - } - - @Override - @Deprecated - public boolean hasCustomBreakingProgress( IBlockState state ) + public boolean hasCustomBreakingProgress( BlockState state ) { return true; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index 3cfc9e5b2..561f57f36 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.state.BooleanProperty; import net.minecraft.state.StateContainer; @@ -27,7 +27,7 @@ public class BlockWiredModemFull extends BlockGeneric } @Override - protected void fillStateContainer( StateContainer.Builder builder ) + protected void fillStateContainer( StateContainer.Builder builder ) { builder.add( MODEM_ON, PERIPHERAL_ON ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index de2ff52e7..a22148fe2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.peripheral.modem.wired; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.IStringSerializable; import javax.annotation.Nonnull; @@ -14,50 +14,50 @@ import javax.annotation.Nonnull; public enum CableModemVariant implements IStringSerializable { None( "none", null ), - DownOff( "down_off", EnumFacing.DOWN ), - UpOff( "up_off", EnumFacing.UP ), - NorthOff( "north_off", EnumFacing.NORTH ), - SouthOff( "south_off", EnumFacing.SOUTH ), - WestOff( "west_off", EnumFacing.WEST ), - EastOff( "east_off", EnumFacing.EAST ), - DownOn( "down_on", EnumFacing.DOWN ), - UpOn( "up_on", EnumFacing.UP ), - NorthOn( "north_on", EnumFacing.NORTH ), - SouthOn( "south_on", EnumFacing.SOUTH ), - WestOn( "west_on", EnumFacing.WEST ), - EastOn( "east_on", EnumFacing.EAST ), - DownOffPeripheral( "down_off_peripheral", EnumFacing.DOWN ), - UpOffPeripheral( "up_off_peripheral", EnumFacing.UP ), - NorthOffPeripheral( "north_off_peripheral", EnumFacing.NORTH ), - SouthOffPeripheral( "south_off_peripheral", EnumFacing.SOUTH ), - WestOffPeripheral( "west_off_peripheral", EnumFacing.WEST ), - EastOffPeripheral( "east_off_peripheral", EnumFacing.EAST ), - DownOnPeripheral( "down_on_peripheral", EnumFacing.DOWN ), - UpOnPeripheral( "up_on_peripheral", EnumFacing.UP ), - NorthOnPeripheral( "north_on_peripheral", EnumFacing.NORTH ), - SouthOnPeripheral( "south_on_peripheral", EnumFacing.SOUTH ), - WestOnPeripheral( "west_on_peripheral", EnumFacing.WEST ), - EastOnPeripheral( "east_on_peripheral", EnumFacing.EAST ); + DownOff( "down_off", Direction.DOWN ), + UpOff( "up_off", Direction.UP ), + NorthOff( "north_off", Direction.NORTH ), + SouthOff( "south_off", Direction.SOUTH ), + WestOff( "west_off", Direction.WEST ), + EastOff( "east_off", Direction.EAST ), + DownOn( "down_on", Direction.DOWN ), + UpOn( "up_on", Direction.UP ), + NorthOn( "north_on", Direction.NORTH ), + SouthOn( "south_on", Direction.SOUTH ), + WestOn( "west_on", Direction.WEST ), + EastOn( "east_on", Direction.EAST ), + DownOffPeripheral( "down_off_peripheral", Direction.DOWN ), + UpOffPeripheral( "up_off_peripheral", Direction.UP ), + NorthOffPeripheral( "north_off_peripheral", Direction.NORTH ), + SouthOffPeripheral( "south_off_peripheral", Direction.SOUTH ), + WestOffPeripheral( "west_off_peripheral", Direction.WEST ), + EastOffPeripheral( "east_off_peripheral", Direction.EAST ), + DownOnPeripheral( "down_on_peripheral", Direction.DOWN ), + UpOnPeripheral( "up_on_peripheral", Direction.UP ), + NorthOnPeripheral( "north_on_peripheral", Direction.NORTH ), + SouthOnPeripheral( "south_on_peripheral", Direction.SOUTH ), + WestOnPeripheral( "west_on_peripheral", Direction.WEST ), + EastOnPeripheral( "east_on_peripheral", Direction.EAST ); private static final CableModemVariant[] VALUES = values(); private final String name; - private final EnumFacing facing; + private final Direction facing; - CableModemVariant( String name, EnumFacing facing ) + CableModemVariant( String name, Direction facing ) { this.name = name; this.facing = facing; } @Nonnull - public static CableModemVariant from( EnumFacing facing ) + public static CableModemVariant from( Direction facing ) { return facing == null ? None : VALUES[1 + facing.getIndex()]; } @Nonnull - public static CableModemVariant from( EnumFacing facing, boolean modem, boolean peripheral ) + public static CableModemVariant from( Direction facing, boolean modem, boolean peripheral ) { int state = (modem ? 2 : 0) + (peripheral ? 1 : 0); return facing == null ? None : VALUES[1 + 6 * state + facing.getIndex()]; @@ -70,7 +70,7 @@ public enum CableModemVariant implements IStringSerializable return name; } - public EnumFacing getFacing() + public Direction getFacing() { return facing; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java index 4f9810f44..013f7f0ff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java @@ -9,8 +9,8 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; import dan200.computercraft.shared.peripheral.modem.ModemShapes; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.EnumFacing; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; @@ -24,14 +24,14 @@ public final class CableShapes private static final double MAX = 1 - MIN; private static final VoxelShape SHAPE_CABLE_CORE = VoxelShapes.create( MIN, MIN, MIN, MAX, MAX, MAX ); - private static final EnumMap SHAPE_CABLE_ARM = - new EnumMap<>( new ImmutableMap.Builder() - .put( EnumFacing.DOWN, VoxelShapes.create( MIN, 0, MIN, MAX, MIN, MAX ) ) - .put( EnumFacing.UP, VoxelShapes.create( MIN, MAX, MIN, MAX, 1, MAX ) ) - .put( EnumFacing.NORTH, VoxelShapes.create( MIN, MIN, 0, MAX, MAX, MIN ) ) - .put( EnumFacing.SOUTH, VoxelShapes.create( MIN, MIN, MAX, MAX, MAX, 1 ) ) - .put( EnumFacing.WEST, VoxelShapes.create( 0, MIN, MIN, MIN, MAX, MAX ) ) - .put( EnumFacing.EAST, VoxelShapes.create( MAX, MIN, MIN, 1, MAX, MAX ) ) + private static final EnumMap SHAPE_CABLE_ARM = + new EnumMap<>( new ImmutableMap.Builder() + .put( Direction.DOWN, VoxelShapes.create( MIN, 0, MIN, MAX, MIN, MAX ) ) + .put( Direction.UP, VoxelShapes.create( MIN, MAX, MIN, MAX, 1, MAX ) ) + .put( Direction.NORTH, VoxelShapes.create( MIN, MIN, 0, MAX, MAX, MIN ) ) + .put( Direction.SOUTH, VoxelShapes.create( MIN, MIN, MAX, MAX, MAX, 1 ) ) + .put( Direction.WEST, VoxelShapes.create( 0, MIN, MIN, MIN, MAX, MAX ) ) + .put( Direction.EAST, VoxelShapes.create( MAX, MIN, MIN, 1, MAX, MAX ) ) .build() ); @@ -42,10 +42,10 @@ public final class CableShapes { } - private static int getCableIndex( IBlockState state ) + private static int getCableIndex( BlockState state ) { int index = 0; - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { if( state.get( CONNECTIONS.get( facing ) ) ) index |= 1 << facing.ordinal(); } @@ -59,7 +59,7 @@ public final class CableShapes if( shape != null ) return shape; shape = SHAPE_CABLE_CORE; - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { if( (index & (1 << facing.ordinal())) != 0 ) { @@ -70,21 +70,21 @@ public final class CableShapes return CABLE_SHAPES[index] = shape; } - public static VoxelShape getCableShape( IBlockState state ) + public static VoxelShape getCableShape( BlockState state ) { if( !state.get( CABLE ) ) return VoxelShapes.empty(); return getCableShape( getCableIndex( state ) ); } - public static VoxelShape getModemShape( IBlockState state ) + public static VoxelShape getModemShape( BlockState state ) { - EnumFacing facing = state.get( MODEM ).getFacing(); + Direction facing = state.get( MODEM ).getFacing(); return facing == null ? VoxelShapes.empty() : ModemShapes.getBounds( facing ); } - public static VoxelShape getShape( IBlockState state ) + public static VoxelShape getShape( BlockState state ) { - EnumFacing facing = state.get( MODEM ).getFacing(); + Direction facing = state.get( MODEM ).getFacing(); if( !state.get( CABLE ) ) return getModemShape( state ); int cableIndex = getCableIndex( state ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java index d65ca60f0..32efb50a5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -7,11 +7,11 @@ package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.ComputerCraft; +import net.minecraft.block.BlockState; import net.minecraft.block.SoundType; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; import net.minecraft.item.BlockItemUseContext; -import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -24,7 +24,7 @@ import javax.annotation.Nonnull; import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*; -public abstract class ItemBlockCable extends ItemBlock +public abstract class ItemBlockCable extends BlockItem { private String translationKey; @@ -33,7 +33,7 @@ public abstract class ItemBlockCable extends ItemBlock super( block, settings ); } - boolean placeAt( World world, BlockPos pos, IBlockState state, EntityPlayer player ) + boolean placeAt( World world, BlockPos pos, BlockState state, PlayerEntity player ) { // TODO: Check entity collision. if( !state.isValidPosition( world, pos ) ) return false; @@ -53,7 +53,7 @@ public abstract class ItemBlockCable extends ItemBlock return true; } - boolean placeAtCorrected( World world, BlockPos pos, IBlockState state ) + boolean placeAtCorrected( World world, BlockPos pos, BlockState state ) { return placeAt( world, pos, correctConnections( world, pos, state ), null ); } @@ -84,26 +84,26 @@ public abstract class ItemBlockCable extends ItemBlock @Nonnull @Override - public EnumActionResult tryPlace( BlockItemUseContext context ) + public ActionResultType tryPlace( BlockItemUseContext context ) { ItemStack stack = context.getItem(); - if( stack.isEmpty() ) return EnumActionResult.FAIL; + if( stack.isEmpty() ) return ActionResultType.FAIL; World world = context.getWorld(); BlockPos pos = context.getPos(); - IBlockState existingState = world.getBlockState( pos ); + BlockState existingState = world.getBlockState( pos ); // Try to add a modem to a cable if( existingState.getBlock() == ComputerCraft.Blocks.cable && existingState.get( MODEM ) == CableModemVariant.None ) { - EnumFacing side = context.getFace().getOpposite(); - IBlockState newState = existingState + Direction side = context.getFace().getOpposite(); + BlockState newState = existingState .with( MODEM, CableModemVariant.from( side ) ) .with( CONNECTIONS.get( side ), existingState.get( CABLE ) ); if( placeAt( world, pos, newState, context.getPlayer() ) ) { stack.shrink( 1 ); - return EnumActionResult.SUCCESS; + return ActionResultType.SUCCESS; } } @@ -120,31 +120,31 @@ public abstract class ItemBlockCable extends ItemBlock @Nonnull @Override - public EnumActionResult tryPlace( BlockItemUseContext context ) + public ActionResultType tryPlace( BlockItemUseContext context ) { ItemStack stack = context.getItem(); - if( stack.isEmpty() ) return EnumActionResult.FAIL; + if( stack.isEmpty() ) return ActionResultType.FAIL; World world = context.getWorld(); BlockPos pos = context.getPos(); // Try to add a cable to a modem inside the block we're clicking on. BlockPos insidePos = pos.offset( context.getFace().getOpposite() ); - IBlockState insideState = world.getBlockState( insidePos ); + BlockState insideState = world.getBlockState( insidePos ); if( insideState.getBlock() == ComputerCraft.Blocks.cable && !insideState.get( BlockCable.CABLE ) && placeAtCorrected( world, insidePos, insideState.with( BlockCable.CABLE, true ) ) ) { stack.shrink( 1 ); - return EnumActionResult.SUCCESS; + return ActionResultType.SUCCESS; } // Try to add a cable to a modem adjacent to this block - IBlockState existingState = world.getBlockState( pos ); + BlockState existingState = world.getBlockState( pos ); if( existingState.getBlock() == ComputerCraft.Blocks.cable && !existingState.get( BlockCable.CABLE ) && placeAtCorrected( world, pos, existingState.with( BlockCable.CABLE, true ) ) ) { stack.shrink( 1 ); - return EnumActionResult.SUCCESS; + return ActionResultType.SUCCESS; } return super.tryPlace( context ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index e02c62f27..53fc60e7b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -17,21 +17,21 @@ import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import dan200.computercraft.shared.wired.CapabilityWiredElement; import net.minecraft.block.Block; -import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -44,7 +44,7 @@ import java.util.Map; public class TileCable extends TileGeneric implements IPeripheralTile { - public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ), TileCable::new ); @@ -86,7 +86,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile private boolean m_destroyed = false; - private EnumFacing modemDirection = EnumFacing.NORTH; + private Direction modemDirection = Direction.NORTH; private boolean hasModemDirection = false; private boolean m_connectionsFormed = false; @@ -194,20 +194,19 @@ public class TileCable extends TileGeneric implements IPeripheralTile } } - private EnumFacing getDirection() + private Direction getDirection() { - IBlockState state = getBlockState(); - EnumFacing facing = state.get( BlockCable.MODEM ).getFacing(); - return facing != null ? facing : EnumFacing.NORTH; + BlockState state = getBlockState(); + Direction facing = state.get( BlockCable.MODEM ).getFacing(); + return facing != null ? facing : Direction.NORTH; } @Override public void onNeighbourChange( @Nonnull BlockPos neighbour ) { - EnumFacing dir = getDirection(); + Direction dir = getDirection(); if( neighbour.equals( getPos().offset( dir ) ) && hasModem() - && getWorld().getBlockState( neighbour ).getBlockFaceShape( world, neighbour, dir.getOpposite() ) != BlockFaceShape.SOLID - ) + && getBlockState().isValidPosition( world, pos ) ) { if( hasCable() ) { @@ -221,7 +220,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile { // Drop everything and remove block Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( ComputerCraft.Items.wiredModem ) ); - getWorld().removeBlock( getPos() ); + getWorld().removeBlock( getPos(), false ); // This'll call #destroy(), so we don't need to reset the network here. } @@ -237,7 +236,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile super.onNeighbourTileEntityChange( neighbour ); if( !world.isRemote && m_peripheralAccessAllowed ) { - EnumFacing facing = getDirection(); + Direction facing = getDirection(); if( getPos().offset( facing ).equals( neighbour ) ) { if( m_peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals(); @@ -246,7 +245,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { if( !canAttachPeripheral() || player.isSneaking() ) return false; @@ -259,12 +258,12 @@ public class TileCable extends TileGeneric implements IPeripheralTile { if( oldName != null ) { - player.sendStatusMessage( new TextComponentTranslation( "chat.computercraft.wired_modem.peripheral_disconnected", + player.sendStatusMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_disconnected", CommandCopy.createCopyText( oldName ) ), false ); } if( newName != null ) { - player.sendStatusMessage( new TextComponentTranslation( "chat.computercraft.wired_modem.peripheral_connected", + player.sendStatusMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_connected", CommandCopy.createCopyText( newName ) ), false ); } } @@ -273,7 +272,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile } @Override - public void read( NBTTagCompound nbt ) + public void read( CompoundNBT nbt ) { super.read( nbt ); m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); @@ -282,7 +281,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Nonnull @Override - public NBTTagCompound write( NBTTagCompound nbt ) + public CompoundNBT write( CompoundNBT nbt ) { nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed ); m_peripheral.write( nbt, "" ); @@ -291,7 +290,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile private void updateBlockState() { - IBlockState state = getBlockState(); + BlockState state = getBlockState(); CableModemVariant oldVariant = state.get( BlockCable.MODEM ); CableModemVariant newVariant = CableModemVariant .from( oldVariant.getFacing(), m_modem.getModemState().isOpen(), m_peripheralAccessAllowed ); @@ -328,10 +327,10 @@ public class TileCable extends TileGeneric implements IPeripheralTile { if( getWorld().isRemote ) return; - IBlockState state = getBlockState(); + BlockState state = getBlockState(); World world = getWorld(); BlockPos current = getPos(); - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { BlockPos offset = current.offset( facing ); if( !world.isBlockLoaded( offset ) ) continue; @@ -419,7 +418,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) { if( capability == CapabilityWiredElement.CAPABILITY ) { @@ -432,7 +431,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile } @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { return !m_destroyed && hasModem() && side == getDirection() ? m_modem : null; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 510cb6fee..d7199e837 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -17,19 +17,20 @@ import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import dan200.computercraft.shared.wired.CapabilityWiredElement; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -44,7 +45,7 @@ import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModem public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { - public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ), TileWiredModemFull::new ); @@ -173,7 +174,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { if( !world.isRemote && m_peripheralAccessAllowed ) { - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { if( getPos().offset( facing ).equals( neighbour ) ) { @@ -185,7 +186,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { if( getWorld().isRemote ) return true; @@ -203,25 +204,25 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile return true; } - private static void sendPeripheralChanges( EntityPlayer player, String kind, Collection peripherals ) + private static void sendPeripheralChanges( PlayerEntity player, String kind, Collection peripherals ) { if( peripherals.isEmpty() ) return; List names = new ArrayList<>( peripherals ); names.sort( Comparator.naturalOrder() ); - TextComponentString base = new TextComponentString( "" ); + StringTextComponent base = new StringTextComponent( "" ); for( int i = 0; i < names.size(); i++ ) { if( i > 0 ) base.appendText( ", " ); base.appendSibling( CommandCopy.createCopyText( names.get( i ) ) ); } - player.sendStatusMessage( new TextComponentTranslation( kind, base ), false ); + player.sendStatusMessage( new TranslationTextComponent( kind, base ), false ); } @Override - public void read( NBTTagCompound nbt ) + public void read( CompoundNBT nbt ) { super.read( nbt ); m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); @@ -230,7 +231,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public NBTTagCompound write( NBTTagCompound nbt ) + public CompoundNBT write( CompoundNBT nbt ) { nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed ); for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].write( nbt, Integer.toString( i ) ); @@ -239,7 +240,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile private void updateBlockState() { - IBlockState state = getBlockState(); + BlockState state = getBlockState(); boolean modemOn = m_modemState.isOpen(), peripheralOn = m_peripheralAccessAllowed; if( state.get( MODEM_ON ) == modemOn && state.get( PERIPHERAL_ON ) == peripheralOn ) return; @@ -267,7 +268,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile connectionsChanged(); if( m_peripheralAccessAllowed ) { - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { m_peripherals[facing.ordinal()].attach( world, getPos(), facing ); } @@ -282,7 +283,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile World world = getWorld(); BlockPos current = getPos(); - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { BlockPos offset = current.offset( facing ); if( !world.isBlockLoaded( offset ) ) continue; @@ -300,7 +301,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile if( !m_peripheralAccessAllowed ) { boolean hasAny = false; - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()]; peripheral.attach( world, getPos(), facing ); @@ -360,7 +361,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) { if( capability == CapabilityWiredElement.CAPABILITY ) { @@ -378,7 +379,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile // IPeripheralTile @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { if( m_destroyed ) return null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index 7159aa5d8..840c4dc5e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -11,8 +11,8 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.Peripherals; import dan200.computercraft.shared.util.IDAssigner; import net.minecraft.block.Block; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; @@ -46,7 +46,7 @@ public final class WiredModemLocalPeripheral * @param direction The direction so search in * @return Whether the peripheral changed. */ - public boolean attach( @Nonnull World world, @Nonnull BlockPos origin, @Nonnull EnumFacing direction ) + public boolean attach( @Nonnull World world, @Nonnull BlockPos origin, @Nonnull Direction direction ) { IPeripheral oldPeripheral = peripheral; IPeripheral peripheral = this.peripheral = getPeripheralFrom( world, origin, direction ); @@ -116,13 +116,13 @@ public final class WiredModemLocalPeripheral : Collections.singletonMap( type + "_" + id, peripheral ); } - public void write( @Nonnull NBTTagCompound tag, @Nonnull String suffix ) + public void write( @Nonnull CompoundNBT tag, @Nonnull String suffix ) { if( id >= 0 ) tag.putInt( NBT_PERIPHERAL_ID + suffix, id ); if( type != null ) tag.putString( NBT_PERIPHERAL_TYPE + suffix, type ); } - public void read( @Nonnull NBTTagCompound tag, @Nonnull String suffix ) + public void read( @Nonnull CompoundNBT tag, @Nonnull String suffix ) { id = tag.contains( NBT_PERIPHERAL_ID + suffix, Constants.NBT.TAG_ANY_NUMERIC ) ? tag.getInt( NBT_PERIPHERAL_ID + suffix ) : -1; @@ -131,7 +131,7 @@ public final class WiredModemLocalPeripheral ? tag.getString( NBT_PERIPHERAL_TYPE + suffix ) : null; } - private static IPeripheral getPeripheralFrom( World world, BlockPos pos, EnumFacing direction ) + private static IPeripheral getPeripheralFrom( World world, BlockPos pos, Direction direction ) { BlockPos offset = pos.offset( direction ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index 208df3b0e..d5f643868 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -8,43 +8,45 @@ package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.peripheral.modem.ModemShapes; -import dan200.computercraft.shared.util.WaterloggableBlock; +import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; -import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; +import net.minecraft.block.IWaterLoggable; import net.minecraft.fluid.IFluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.state.BooleanProperty; import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; -import net.minecraft.world.IWorldReaderBase; +import net.minecraft.world.IWorldReader; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BlockWirelessModem extends BlockGeneric implements WaterloggableBlock +import static dan200.computercraft.shared.util.WaterloggableHelpers.*; + +public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable { public static final DirectionProperty FACING = BlockStateProperties.FACING; public static final BooleanProperty ON = BooleanProperty.create( "on" ); - public BlockWirelessModem( Properties settings, TileEntityType type ) + public BlockWirelessModem( Properties settings, NamedTileEntityType type ) { super( settings, type ); setDefaultState( getStateContainer().getBaseState() - .with( FACING, EnumFacing.NORTH ) + .with( FACING, Direction.NORTH ) .with( ON, false ) .with( WATERLOGGED, false ) ); } @Override - protected void fillStateContainer( StateContainer.Builder builder ) + protected void fillStateContainer( StateContainer.Builder builder ) { builder.add( FACING, ON, WATERLOGGED ); } @@ -52,7 +54,7 @@ public class BlockWirelessModem extends BlockGeneric implements WaterloggableBlo @Nonnull @Override @Deprecated - public VoxelShape getShape( IBlockState blockState, IBlockReader blockView, BlockPos blockPos ) + public VoxelShape getShape( BlockState blockState, IBlockReader blockView, BlockPos blockPos, ISelectionContext context ) { return ModemShapes.getBounds( blockState.get( FACING ) ); } @@ -60,7 +62,7 @@ public class BlockWirelessModem extends BlockGeneric implements WaterloggableBlo @Nonnull @Override @Deprecated - public IFluidState getFluidState( IBlockState state ) + public IFluidState getFluidState( BlockState state ) { return getWaterloggedFluidState( state ); } @@ -68,7 +70,7 @@ public class BlockWirelessModem extends BlockGeneric implements WaterloggableBlo @Nonnull @Override @Deprecated - public IBlockState updatePostPlacement( @Nonnull IBlockState state, EnumFacing side, IBlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + public BlockState updatePostPlacement( @Nonnull BlockState state, Direction side, BlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return side == state.get( FACING ) && !state.isValidPosition( world, pos ) @@ -78,35 +80,20 @@ public class BlockWirelessModem extends BlockGeneric implements WaterloggableBlo @Override @Deprecated - public boolean isValidPosition( IBlockState state, IWorldReaderBase world, BlockPos pos ) + public boolean isValidPosition( BlockState state, IWorldReader world, BlockPos pos ) { - EnumFacing facing = state.get( FACING ); + Direction facing = state.get( FACING ); BlockPos offsetPos = pos.offset( facing ); - IBlockState offsetState = world.getBlockState( offsetPos ); - return offsetState.getBlockFaceShape( world, offsetPos, facing.getOpposite() ) == BlockFaceShape.SOLID; + BlockState offsetState = world.getBlockState( offsetPos ); + return func_220056_d( offsetState, world, offsetPos, facing.getOpposite() ); } @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext placement ) + public BlockState getStateForPlacement( BlockItemUseContext placement ) { return getDefaultState() .with( FACING, placement.getFace().getOpposite() ) .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) ); } - - @Override - @Deprecated - public final boolean isFullCube( IBlockState state ) - { - return false; - } - - @Nonnull - @Override - @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockReader worldIn, IBlockState state, BlockPos pos, EnumFacing face ) - { - return BlockFaceShape.UNDEFINED; - } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index d3fb3d195..9da297f52 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -12,11 +12,11 @@ import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; -import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -27,12 +27,12 @@ import javax.annotation.Nullable; public class TileWirelessModem extends TileGeneric implements IPeripheralTile { - public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ), f -> new TileWirelessModem( f, false ) ); - public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ), f -> new TileWirelessModem( f, true ) ); @@ -72,7 +72,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile private final boolean advanced; private boolean hasModemDirection = false; - private EnumFacing modemDirection = EnumFacing.DOWN; + private Direction modemDirection = Direction.DOWN; private final ModemPeripheral modem; private boolean destroyed = false; @@ -142,7 +142,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile private void updateBlockState() { boolean on = modem.getModemState().isOpen(); - IBlockState state = getBlockState(); + BlockState state = getBlockState(); if( state.get( BlockWirelessModem.ON ) != on ) { getWorld().setBlockState( getPos(), state.with( BlockWirelessModem.ON, on ) ); @@ -152,7 +152,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile @Nullable @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { updateDirection(); return side == modemDirection ? modem : null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index 2ff323829..f924fb530 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -51,7 +51,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } if( position.y > 96.0 && maxRange > minRange ) { - return minRange + (position.y - 96.0) * ((maxRange - minRange) / ((world.getHeight() - 1) - 96.0)); + return minRange + (position.y - 96.0) * ((maxRange - minRange) / ((world.func_217301_I() - 1) - 96.0)); } return minRange; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 40e389323..104ef94cc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -8,9 +8,10 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.DirectionProperty; @@ -18,9 +19,8 @@ import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.BlockRenderLayer; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -30,18 +30,18 @@ import javax.annotation.Nullable; public class BlockMonitor extends BlockGeneric { public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation", - EnumFacing.UP, EnumFacing.DOWN, EnumFacing.NORTH ); + Direction.UP, Direction.DOWN, Direction.NORTH ); public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class ); - public BlockMonitor( Properties settings, TileEntityType type ) + public BlockMonitor( Properties settings, NamedTileEntityType type ) { super( settings, type ); setDefaultState( getStateContainer().getBaseState() - .with( ORIENTATION, EnumFacing.NORTH ) - .with( FACING, EnumFacing.NORTH ) + .with( ORIENTATION, Direction.NORTH ) + .with( FACING, Direction.NORTH ) .with( STATE, MonitorEdgeState.NONE ) ); } @@ -53,30 +53,30 @@ public class BlockMonitor extends BlockGeneric } @Override - protected void fillStateContainer( StateContainer.Builder builder ) + protected void fillStateContainer( StateContainer.Builder builder ) { builder.add( ORIENTATION, FACING, STATE ); } @Override @Nullable - public IBlockState getStateForPlacement( BlockItemUseContext context ) + public BlockState getStateForPlacement( BlockItemUseContext context ) { float pitch = context.getPlayer() == null ? 0 : context.getPlayer().rotationPitch; - EnumFacing orientation; + Direction orientation; if( pitch > 66.5f ) { // If the player is looking down, place it facing upwards - orientation = EnumFacing.UP; + orientation = Direction.UP; } else if( pitch < -66.5f ) { // If they're looking up, place it down. - orientation = EnumFacing.DOWN; + orientation = Direction.DOWN; } else { - orientation = EnumFacing.NORTH; + orientation = Direction.NORTH; } return getDefaultState() @@ -85,7 +85,7 @@ public class BlockMonitor extends BlockGeneric } @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState blockState, @Nullable EntityLivingBase livingEntity, ItemStack itemStack ) + public void onBlockPlacedBy( World world, BlockPos pos, BlockState blockState, @Nullable LivingEntity livingEntity, ItemStack itemStack ) { super.onBlockPlacedBy( world, pos, blockState, livingEntity, itemStack ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index d2fb79675..2571f55a0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.peripheral.monitor; +import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.shared.common.ClientTerminal; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.math.BlockPos; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 7ad5836da..f461fb7a1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -13,15 +13,16 @@ import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.util.NamedBlockEntityType; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.nbt.NBTTagCompound; +import dan200.computercraft.shared.util.NamedTileEntityType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -30,12 +31,12 @@ import java.util.Set; public class TileMonitor extends TileGeneric implements IPeripheralTile { - public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ), f -> new TileMonitor( f, false ) ); - public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_advanced" ), f -> new TileMonitor( f, true ) ); @@ -104,11 +105,18 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - if( !player.isSneaking() && getFront() == side ) + if( !player.isSneaking() && getFront() == hit.getFace() ) { - if( !getWorld().isRemote ) monitorTouched( hitX, hitY, hitZ ); + if( !getWorld().isRemote ) + { + monitorTouched( + (float) (hit.getHitVec().x - hit.getPos().getX()), + (float) (hit.getHitVec().y - hit.getPos().getY()), + (float) (hit.getHitVec().z - hit.getPos().getZ()) + ); + } return true; } @@ -117,7 +125,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile @Nonnull @Override - public NBTTagCompound write( NBTTagCompound tag ) + public CompoundNBT write( CompoundNBT tag ) { tag.putInt( NBT_X, m_xIndex ); tag.putInt( NBT_Y, m_yIndex ); @@ -127,7 +135,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile } @Override - public void read( NBTTagCompound tag ) + public void read( CompoundNBT tag ) { super.read( tag ); m_xIndex = tag.getInt( NBT_X ); @@ -168,7 +176,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile // IPeripheralTile implementation @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { createServerMonitor(); // Ensure the monitor is created before doing anything else. if( m_peripheral == null ) m_peripheral = new MonitorPeripheral( this ); @@ -238,7 +246,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile // Networking stuff @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); @@ -254,7 +262,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile } @Override - protected final void readDescription( @Nonnull NBTTagCompound nbt ) + protected final void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); @@ -300,32 +308,32 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile } // region Sizing and placement stuff - public EnumFacing getDirection() + public Direction getDirection() { return getBlockState().get( BlockMonitor.FACING ); } - public EnumFacing getOrientation() + public Direction getOrientation() { return getBlockState().get( BlockMonitor.ORIENTATION ); } - public EnumFacing getFront() + public Direction getFront() { - EnumFacing orientation = getOrientation(); - return orientation == EnumFacing.NORTH ? getDirection() : orientation; + Direction orientation = getOrientation(); + return orientation == Direction.NORTH ? getDirection() : orientation; } - public EnumFacing getRight() + public Direction getRight() { return getDirection().rotateYCCW(); } - public EnumFacing getDown() + public Direction getDown() { - EnumFacing orientation = getOrientation(); - if( orientation == EnumFacing.NORTH ) return EnumFacing.UP; - return orientation == EnumFacing.DOWN ? getDirection() : getDirection().getOpposite(); + Direction orientation = getOrientation(); + if( orientation == Direction.NORTH ) return Direction.UP; + return orientation == Direction.DOWN ? getDirection() : getDirection().getOpposite(); } public int getWidth() @@ -368,8 +376,8 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile private TileMonitor getNeighbour( int x, int y ) { BlockPos pos = getPos(); - EnumFacing right = getRight(); - EnumFacing down = getDown(); + Direction right = getRight(); + Direction down = getDown(); int xOffset = -m_xIndex + x; int yOffset = -m_yIndex + y; return getSimilarMonitorAt( pos.offset( right, xOffset ).offset( down, yOffset ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java index 2fd92b142..2b1bf0f74 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.peripheral.monitor; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; public class XYPair { @@ -24,7 +24,7 @@ public class XYPair return new XYPair( this.x + x, this.y + y ); } - public static XYPair of( float xPos, float yPos, float zPos, EnumFacing facing, EnumFacing orientation ) + public static XYPair of( float xPos, float yPos, float zPos, Direction facing, Direction orientation ) { switch( orientation ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java index 47d538c97..ef53a5f72 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -8,18 +8,18 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.BooleanProperty; import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.stats.StatList; +import net.minecraft.stats.Stats; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.INameable; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -37,30 +37,30 @@ public class BlockPrinter extends BlockGeneric { super( settings, TilePrinter.FACTORY ); setDefaultState( getStateContainer().getBaseState() - .with( FACING, EnumFacing.NORTH ) + .with( FACING, Direction.NORTH ) .with( TOP, false ) .with( BOTTOM, false ) ); } @Override - protected void fillStateContainer( StateContainer.Builder properties ) + protected void fillStateContainer( StateContainer.Builder properties ) { properties.add( FACING, TOP, BOTTOM ); } @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext placement ) + public BlockState getStateForPlacement( BlockItemUseContext placement ) { return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); } @Override - public void harvestBlock( @Nonnull World world, EntityPlayer player, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nullable TileEntity te, ItemStack stack ) + public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, ItemStack stack ) { if( te instanceof INameable && ((INameable) te).hasCustomName() ) { - player.addStat( StatList.BLOCK_MINED.get( this ) ); + player.addStat( Stats.BLOCK_MINED.get( this ) ); player.addExhaustion( 0.005F ); ItemStack result = new ItemStack( this ); @@ -74,7 +74,7 @@ public class BlockPrinter extends BlockGeneric } @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack ) + public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) { if( stack.hasDisplayName() ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index 7d6eae516..9ae869156 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -6,105 +6,85 @@ package dan200.computercraft.shared.peripheral.printer; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.inventory.IContainerListener; +import dan200.computercraft.shared.util.SingleIntArray; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; -import net.minecraft.inventory.Slot; -import net.minecraft.item.ItemDye; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.DyeItem; import net.minecraft.item.ItemStack; +import net.minecraft.util.IIntArray; +import net.minecraft.util.IntArray; import javax.annotation.Nonnull; public class ContainerPrinter extends Container { - private static final int PROPERTY_PRINTING = 0; + public static final ContainerType TYPE = new ContainerType<>( ContainerPrinter::new ); - private final TilePrinter m_printer; - private boolean m_lastPrinting; + private final IInventory inventory; + private final IIntArray properties; - public ContainerPrinter( IInventory playerInventory, TilePrinter printer ) + private ContainerPrinter( int id, PlayerInventory player, IInventory inventory, IIntArray properties ) { - m_printer = printer; - m_lastPrinting = false; + super( TYPE, id ); + this.properties = properties; + this.inventory = inventory; + + func_216961_a( properties ); // Ink slot - addSlot( new Slot( printer, 0, 13, 35 ) ); + addSlot( new Slot( inventory, 0, 13, 35 ) ); // In-tray - for( int x = 0; x < 6; x++ ) addSlot( new Slot( printer, x + 1, 61 + x * 18, 22 ) ); + for( int x = 0; x < 6; x++ ) addSlot( new Slot( inventory, x + 1, 61 + x * 18, 22 ) ); // Out-tray - for( int x = 0; x < 6; x++ ) addSlot( new Slot( printer, x + 7, 61 + x * 18, 49 ) ); + for( int x = 0; x < 6; x++ ) addSlot( new Slot( inventory, x + 7, 61 + x * 18, 49 ) ); // Player inv for( int y = 0; y < 3; y++ ) { for( int x = 0; x < 9; x++ ) { - addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); + addSlot( new Slot( player, x + y * 9 + 9, 8 + x * 18, 84 + y * 18 ) ); } } // Player hotbar - for( int x = 0; x < 9; x++ ) addSlot( new Slot( playerInventory, x, 8 + x * 18, 142 ) ); + for( int x = 0; x < 9; x++ ) + { + addSlot( new Slot( player, x, 8 + x * 18, 142 ) ); + } + } + + private ContainerPrinter( int id, PlayerInventory player ) + { + this( id, player, new Inventory( TilePrinter.SLOTS ), new IntArray( TilePrinter.PROPERTIES ) ); + } + + public ContainerPrinter( int id, PlayerInventory player, TilePrinter printer ) + { + this( id, player, printer, (SingleIntArray) (() -> printer.isPrinting() ? 1 : 0) ); } public boolean isPrinting() { - return m_lastPrinting; - } - - public TilePrinter getPrinter() - { - return m_printer; + return properties.func_221476_a( 0 ) != 0; } @Override - public void addListener( IContainerListener listener ) + public boolean canInteractWith( @Nonnull PlayerEntity player ) { - super.addListener( listener ); - listener.sendWindowProperty( this, PROPERTY_PRINTING, m_printer.isPrinting() ? 1 : 0 ); - } - - @Override - public void detectAndSendChanges() - { - super.detectAndSendChanges(); - - if( !m_printer.getWorld().isRemote ) - { - // Push the printing state to the client if needed. - boolean printing = m_printer.isPrinting(); - if( printing != m_lastPrinting ) - { - for( IContainerListener listener : listeners ) - { - listener.sendWindowProperty( this, PROPERTY_PRINTING, printing ? 1 : 0 ); - } - m_lastPrinting = printing; - } - } - } - - @Override - public void updateProgressBar( int property, int value ) - { - if( m_printer.getWorld().isRemote ) - { - if( property == PROPERTY_PRINTING ) m_lastPrinting = value != 0; - } - } - - @Override - public boolean canInteractWith( @Nonnull EntityPlayer player ) - { - return m_printer.isUsableByPlayer( player ); + return inventory.isUsableByPlayer( player ); } @Nonnull @Override - public ItemStack transferStackInSlot( EntityPlayer player, int index ) + public ItemStack transferStackInSlot( PlayerEntity player, int index ) { Slot slot = inventorySlots.get( index ); if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY; @@ -118,7 +98,7 @@ public class ContainerPrinter extends Container else { // Transfer from inventory to printer - if( stack.getItem() instanceof ItemDye ) + if( stack.getItem() instanceof DyeItem ) { if( !mergeItemStack( stack, 0, 1, false ) ) return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 42f8b6e7a..16c99504c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -12,28 +12,26 @@ import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.util.ColourUtils; import dan200.computercraft.shared.util.DefaultSidedInventory; -import dan200.computercraft.shared.util.NamedBlockEntityType; +import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Items; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.ItemStackHelper; -import net.minecraft.item.EnumDyeColor; -import net.minecraft.item.Item; -import net.minecraft.item.ItemDye; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.item.*; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.text.ITextComponent; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.network.NetworkHooks; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.SidedInvWrapper; @@ -43,9 +41,9 @@ import javax.annotation.Nullable; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; -public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile +public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile, INameable, INamedContainerProvider { - public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ), TilePrinter::new ); @@ -54,13 +52,16 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private static final String NBT_PRINTING = "Printing"; private static final String NBT_PAGE_TITLE = "PageTitle"; + static final int SLOTS = 13; + static final int PROPERTIES = 1; + private static final int[] BOTTOM_SLOTS = new int[] { 7, 8, 9, 10, 11, 12 }; private static final int[] TOP_SLOTS = new int[] { 1, 2, 3, 4, 5, 6 }; private static final int[] SIDE_SLOTS = new int[] { 0 }; ITextComponent customName; - private final NonNullList m_inventory = NonNullList.withSize( 13, ItemStack.EMPTY ); + private final NonNullList m_inventory = NonNullList.withSize( SLOTS, ItemStack.EMPTY ); private LazyOptional[] itemHandlerCaps; private final Terminal m_page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE ); @@ -95,16 +96,16 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { if( player.isSneaking() ) return false; - if( !getWorld().isRemote ) Containers.openPrinterGUI( player, this ); + if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this ); return true; } @Override - public void read( NBTTagCompound nbt ) + public void read( CompoundNBT nbt ) { super.read( nbt ); @@ -127,7 +128,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public NBTTagCompound write( NBTTagCompound nbt ) + public CompoundNBT write( CompoundNBT nbt ) { if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); @@ -149,14 +150,14 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); } @Override - public void readDescription( @Nonnull NBTTagCompound nbt ) + public void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; @@ -274,7 +275,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } @Override - public boolean isUsableByPlayer( @Nonnull EntityPlayer playerEntity ) + public boolean isUsableByPlayer( @Nonnull PlayerEntity playerEntity ) { return isUsable( playerEntity, false ); } @@ -283,7 +284,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public int[] getSlotsForFace( @Nonnull EnumFacing side ) + public int[] getSlotsForFace( @Nonnull Direction side ) { switch( side ) { @@ -299,7 +300,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent // IPeripheralTile implementation @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { return new PrinterPeripheral( this ); } @@ -367,7 +368,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private static boolean isInk( @Nonnull ItemStack stack ) { - return stack.getItem() instanceof ItemDye; + return stack.getItem() instanceof DyeItem; } private static boolean isPaper( @Nonnull ItemStack stack ) @@ -399,7 +400,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent if( !paperStack.isEmpty() && isPaper( paperStack ) ) { // Setup the new page - EnumDyeColor dye = ColourUtils.getStackColour( inkStack ); + DyeColor dye = ColourUtils.getStackColour( inkStack ); m_page.setTextColour( dye != null ? dye.getId() : 15 ); m_page.clear(); @@ -525,7 +526,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent { if( removed ) return; - IBlockState state = getBlockState(); + BlockState state = getBlockState(); if( state.get( BlockPrinter.TOP ) == top & state.get( BlockPrinter.BOTTOM ) == bottom ) return; getWorld().setBlockState( getPos(), state.with( BlockPrinter.TOP, top ).with( BlockPrinter.BOTTOM, bottom ) ); @@ -534,7 +535,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @SuppressWarnings( { "unchecked", "rawtypes" } ) @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability capability, @Nullable EnumFacing facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) { if( capability == ITEM_HANDLER_CAPABILITY ) { @@ -575,4 +576,17 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent { return customName != null ? customName : getBlockState().getBlock().getNameTextComponent(); } + + @Override + public ITextComponent getDisplayName() + { + return getName(); + } + + @Nonnull + @Override + public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerPrinter( id, inventory, this ); + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java index d31169fab..60ef1f9df 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -8,12 +8,12 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import javax.annotation.Nullable; @@ -25,18 +25,18 @@ public class BlockSpeaker extends BlockGeneric { super( settings, TileSpeaker.FACTORY ); setDefaultState( getStateContainer().getBaseState() - .with( FACING, EnumFacing.NORTH ) ); + .with( FACING, Direction.NORTH ) ); } @Override - protected void fillStateContainer( StateContainer.Builder properties ) + protected void fillStateContainer( StateContainer.Builder properties ) { properties.add( FACING ); } @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext placement ) + public BlockState getStateForPlacement( BlockItemUseContext placement ) { return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 2b115e6f4..1bb93aa84 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -11,7 +11,7 @@ import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.network.play.server.SPacketCustomSound; +import net.minecraft.network.play.server.SPlaySoundPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.state.properties.NoteBlockInstrument; import net.minecraft.util.ResourceLocation; @@ -146,7 +146,7 @@ public abstract class SpeakerPeripheral implements IPeripheral float adjVolume = Math.min( volume, 3.0f ); server.getPlayerList().sendToAllNearExcept( null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.dimension.getType(), - new SPacketCustomSound( name, SoundCategory.RECORDS, pos, adjVolume, pitch ) + new SPlaySoundPacket( name, SoundCategory.RECORDS, pos, adjVolume, pitch ) ); return null; } ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 667af245d..4c8d552ac 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -10,9 +10,9 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.util.NamedBlockEntityType; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.ITickable; +import dan200.computercraft.shared.util.NamedTileEntityType; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -21,11 +21,11 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TileSpeaker extends TileGeneric implements ITickable, IPeripheralTile +public class TileSpeaker extends TileGeneric implements ITickableTileEntity, IPeripheralTile { public static final int MIN_TICKS_BETWEEN_SOUNDS = 1; - public static final NamedBlockEntityType FACTORY = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ), TileSpeaker::new ); @@ -45,7 +45,7 @@ public class TileSpeaker extends TileGeneric implements ITickable, IPeripheralTi } @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { return m_peripheral; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index fb8c88f3e..96d8d0840 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -15,8 +15,8 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; import net.minecraftforge.items.wrapper.PlayerMainInvWrapper; @@ -58,9 +58,9 @@ public class PocketAPI implements ILuaAPI return context.executeMainThreadTask( () -> { Entity entity = m_computer.getEntity(); - if( !(entity instanceof EntityPlayer) ) return new Object[] { false, "Cannot find player" }; - EntityPlayer player = (EntityPlayer) entity; - InventoryPlayer inventory = player.inventory; + if( !(entity instanceof PlayerEntity) ) return new Object[] { false, "Cannot find player" }; + PlayerEntity player = (PlayerEntity) entity; + PlayerInventory inventory = player.inventory; IPocketUpgrade previousUpgrade = m_computer.getUpgrade(); // Attempt to find the upgrade, starting in the main segment, and then looking in the opposite @@ -97,9 +97,9 @@ public class PocketAPI implements ILuaAPI return context.executeMainThreadTask( () -> { Entity entity = m_computer.getEntity(); - if( !(entity instanceof EntityPlayer) ) return new Object[] { false, "Cannot find player" }; - EntityPlayer player = (EntityPlayer) entity; - InventoryPlayer inventory = player.inventory; + if( !(entity instanceof PlayerEntity) ) return new Object[] { false, "Cannot find player" }; + PlayerEntity player = (PlayerEntity) entity; + PlayerInventory inventory = player.inventory; IPocketUpgrade previousUpgrade = m_computer.getUpgrade(); if( previousUpgrade == null ) return new Object[] { false, "Nothing to unequip" }; diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index 264de4d48..2906a5a1d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -17,12 +17,12 @@ import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.EntityPlayerMP; -import net.minecraft.entity.player.InventoryPlayer; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; @@ -52,14 +52,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces Entity entity = m_entity; if( entity == null || m_stack == null || !entity.isAlive() ) return null; - if( entity instanceof EntityPlayer ) + if( entity instanceof PlayerEntity ) { - InventoryPlayer inventory = ((EntityPlayer) entity).inventory; + PlayerInventory inventory = ((PlayerEntity) entity).inventory; return inventory.mainInventory.contains( m_stack ) || inventory.offHandInventory.contains( m_stack ) ? entity : null; } - else if( entity instanceof EntityLivingBase ) + else if( entity instanceof LivingEntity ) { - EntityLivingBase living = (EntityLivingBase) entity; + LivingEntity living = (LivingEntity) entity; return living.getHeldItemMainhand() == m_stack || living.getHeldItemOffhand() == m_stack ? entity : null; } else @@ -84,14 +84,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public int getLight() { - NBTTagCompound tag = getUserData(); + CompoundNBT tag = getUserData(); return tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ? tag.getInt( NBT_LIGHT ) : -1; } @Override public void setLight( int colour ) { - NBTTagCompound tag = getUserData(); + CompoundNBT tag = getUserData(); if( colour >= 0 && colour <= 0xFFFFFF ) { if( !tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) || tag.getInt( NBT_LIGHT ) != colour ) @@ -109,7 +109,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Nonnull @Override - public NBTTagCompound getUpgradeNBTData() + public CompoundNBT getUpgradeNBTData() { return ItemPocketComputer.getUpgradeInfo( m_stack ); } @@ -117,7 +117,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public void updateUpgradeNBTData() { - if( m_entity instanceof EntityPlayer ) ((EntityPlayer) m_entity).inventory.markDirty(); + if( m_entity instanceof PlayerEntity ) ((PlayerEntity) m_entity).inventory.markDirty(); } @Override @@ -168,7 +168,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces } // If a new entity has picked it up then rebroadcast the terminal to them - if( entity != m_entity && entity instanceof EntityPlayerMP ) markTerminalChanged(); + if( entity != m_entity && entity instanceof ServerPlayerEntity ) markTerminalChanged(); m_entity = entity; m_stack = stack; @@ -185,10 +185,10 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces { super.broadcastState( force ); - if( (hasTerminalChanged() || force) && m_entity instanceof EntityPlayerMP ) + if( (hasTerminalChanged() || force) && m_entity instanceof ServerPlayerEntity ) { // Broadcast the state to the current entity if they're not already interacting with it. - EntityPlayerMP player = (EntityPlayerMP) m_entity; + ServerPlayerEntity player = (ServerPlayerEntity) m_entity; if( player.connection != null && !isInteracting( player ) ) { NetworkHandler.sendToPlayer( player, createTerminalPacket() ); diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java index 9619ba9e3..4c3e9cb39 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java @@ -10,21 +10,26 @@ import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; +import dan200.computercraft.shared.network.container.ContainerData; +import dan200.computercraft.shared.network.container.PocketComputerContainerData; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Hand; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ContainerPocketComputer extends ContainerHeldItem implements IContainerComputer { + public static final ContainerType TYPE = ContainerData.create( PocketComputerContainerData::new ); + private final InputState input = new InputState( this ); - public ContainerPocketComputer( EntityPlayer player, EnumHand hand ) + public ContainerPocketComputer( int id, @Nonnull PlayerEntity player, Hand hand ) { - super( player, hand ); + super( TYPE, id, player, hand ); } @Nullable @@ -44,7 +49,7 @@ public class ContainerPocketComputer extends ContainerHeldItem implements IConta } @Override - public void onContainerClosed( EntityPlayer player ) + public void onContainerClosed( PlayerEntity player ) { super.onContainerClosed( player ); input.close(); diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index ab681c433..f81ac140e 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -20,23 +20,23 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.network.Containers; +import dan200.computercraft.shared.network.container.PocketComputerContainerData; import dan200.computercraft.shared.pocket.apis.PocketAPI; import dan200.computercraft.shared.pocket.core.PocketServerComputer; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.IInventory; import net.minecraft.item.IItemPropertyGetter; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.*; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -68,7 +68,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I { ItemStack result = new ItemStack( this ); if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id ); - if( label != null ) result.setDisplayName( new TextComponentString( label ) ); + if( label != null ) result.setDisplayName( new StringTextComponent( label ) ); if( upgrade != null ) result.getOrCreateTag().putString( NBT_UPGRADE, upgrade.getUpgradeID().toString() ); if( colour != -1 ) result.getOrCreateTag().putInt( NBT_COLOUR, colour ); return result; @@ -91,7 +91,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I if( !world.isRemote ) { // Server side - IInventory inventory = entity instanceof EntityPlayer ? ((EntityPlayer) entity).inventory : null; + IInventory inventory = entity instanceof PlayerEntity ? ((PlayerEntity) entity).inventory : null; PocketServerComputer computer = createServerComputer( world, inventory, entity, stack ); if( computer != null ) { @@ -134,7 +134,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Nonnull @Override - public ActionResult onItemRightClick( World world, EntityPlayer player, @Nonnull EnumHand hand ) + public ActionResult onItemRightClick( World world, PlayerEntity player, @Nonnull Hand hand ) { ItemStack stack = player.getHeldItem( hand ); if( !world.isRemote ) @@ -154,9 +154,9 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I } } - if( !stop ) Containers.openPocketComputerGUI( player, hand ); + if( !stop ) new PocketComputerContainerData( hand ).open( player ); } - return new ActionResult<>( EnumActionResult.SUCCESS, stack ); + return new ActionResult<>( ActionResultType.SUCCESS, stack ); } @Nonnull @@ -167,8 +167,8 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I IPocketUpgrade upgrade = getUpgrade( stack ); if( upgrade != null ) { - return new TextComponentTranslation( baseString + ".upgraded", - new TextComponentTranslation( upgrade.getUnlocalisedAdjective() ) + return new TranslationTextComponent( baseString + ".upgraded", + new TranslationTextComponent( upgrade.getUnlocalisedAdjective() ) ); } else @@ -186,7 +186,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I int id = getComputerID( stack ); if( id >= 0 ) { - list.add( new TextComponentTranslation( "gui.computercraft.tooltip.computer_id", id ) + list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id ) .applyTextStyle( TextFormatting.GRAY ) ); } } @@ -313,7 +313,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I { if( label != null ) { - stack.setDisplayName( new TextComponentString( label ) ); + stack.setDisplayName( new StringTextComponent( label ) ); } else { @@ -335,7 +335,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I private static int getInstanceID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; } @@ -346,7 +346,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I private static int getSessionID( @Nonnull ItemStack stack ) { - NBTTagCompound nbt = stack.getTag(); + CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_SESSION ) ? nbt.getInt( NBT_SESSION ) : -1; } @@ -368,7 +368,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I ClientComputer computer = getClientComputer( stack ); if( computer != null && computer.isOn() ) { - NBTTagCompound computerNBT = computer.getUserData(); + CompoundNBT computerNBT = computer.getUserData(); if( computerNBT != null && computerNBT.contains( NBT_LIGHT ) ) { return computerNBT.getInt( NBT_LIGHT ); @@ -379,7 +379,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I public static IPocketUpgrade getUpgrade( @Nonnull ItemStack stack ) { - NBTTagCompound compound = stack.getTag(); + CompoundNBT compound = stack.getTag(); return compound != null && compound.contains( NBT_UPGRADE ) ? PocketUpgrades.get( compound.getString( NBT_UPGRADE ) ) : null; @@ -387,7 +387,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I public static void setUpgrade( @Nonnull ItemStack stack, IPocketUpgrade upgrade ) { - NBTTagCompound compound = stack.getOrCreateTag(); + CompoundNBT compound = stack.getOrCreateTag(); if( upgrade == null ) { @@ -401,7 +401,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I compound.remove( NBT_UPGRADE_INFO ); } - public static NBTTagCompound getUpgradeInfo( @Nonnull ItemStack stack ) + public static CompoundNBT getUpgradeInfo( @Nonnull ItemStack stack ) { return stack.getOrCreateChildTag( NBT_UPGRADE_INFO ); } diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index 76fbac517..381e7cc73 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -6,23 +6,22 @@ package dan200.computercraft.shared.pocket.recipes; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; -import dan200.computercraft.shared.util.AbstractRecipe; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.crafting.SpecialRecipe; +import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import javax.annotation.Nonnull; -public final class PocketComputerUpgradeRecipe extends AbstractRecipe +public final class PocketComputerUpgradeRecipe extends SpecialRecipe { private PocketComputerUpgradeRecipe( ResourceLocation identifier ) { @@ -43,14 +42,14 @@ public final class PocketComputerUpgradeRecipe extends AbstractRecipe } @Override - public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) { return !getCraftingResult( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inventory ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory ) { // Scan the grid for a pocket computer ItemStack computer = ItemStack.EMPTY; @@ -115,8 +114,5 @@ public final class PocketComputerUpgradeRecipe extends AbstractRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( - ComputerCraft.MOD_ID + ":pocket_computer_upgrade", - PocketComputerUpgradeRecipe::new - ); + public static final IRecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( PocketComputerUpgradeRecipe::new ); } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 66e749df6..cde8638db 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -16,30 +16,35 @@ import dan200.computercraft.shared.Config; import dan200.computercraft.shared.command.CommandComputerCraft; import dan200.computercraft.shared.command.arguments.ArgumentSerializers; import dan200.computercraft.shared.common.ColourableRecipe; +import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.media.recipes.DiskRecipe; import dan200.computercraft.shared.media.recipes.PrintoutRecipe; -import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; +import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; +import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import dan200.computercraft.shared.wired.CapabilityWiredElement; -import net.minecraft.inventory.Container; +import net.minecraft.inventory.container.Container; import net.minecraft.item.Item; -import net.minecraft.item.ItemRecord; -import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.MusicDiscItem; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityCommandBlock; +import net.minecraft.util.registry.Registry; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; @@ -57,19 +62,25 @@ public final class ComputerCraftProxyCommon public static void init( FMLCommonSetupEvent event ) { NetworkHandler.setup(); - Containers.setup(); registerProviders(); - RecipeSerializers.register( ColourableRecipe.SERIALIZER ); - RecipeSerializers.register( ComputerUpgradeRecipe.SERIALIZER ); - RecipeSerializers.register( PocketComputerUpgradeRecipe.SERIALIZER ); - RecipeSerializers.register( DiskRecipe.SERIALIZER ); - RecipeSerializers.register( PrintoutRecipe.SERIALIZER ); - RecipeSerializers.register( TurtleRecipe.SERIALIZER ); - RecipeSerializers.register( TurtleUpgradeRecipe.SERIALIZER ); - RecipeSerializers.register( ImpostorShapelessRecipe.SERIALIZER ); - RecipeSerializers.register( ImpostorRecipe.SERIALIZER ); + // Eww, eww, eww - can we move this to an event? + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":colour", ColourableRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":computer_upgrade", ComputerUpgradeRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":pocket_computer_upgrade", PocketComputerUpgradeRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":disk", DiskRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":printout", PrintoutRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":turtle", TurtleRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":turtle_upgrade", TurtleUpgradeRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":impostor_shapeless", ImpostorShapelessRecipe.SERIALIZER ); + IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":impostor_shaped", ImpostorRecipe.SERIALIZER ); + + Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":printer", ContainerPrinter.TYPE ); + Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":disk_drive", ContainerDiskDrive.TYPE ); + Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":pocket_computer", ContainerPocketComputer.TYPE ); + Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":printout", ContainerHeldItem.PRINTOUT_TYPE ); + Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":view_computer", ContainerViewComputer.TYPE ); ArgumentSerializers.register(); @@ -86,7 +97,7 @@ public final class ComputerCraftProxyCommon ComputerCraftAPI.registerPeripheralProvider( ( world, pos, side ) -> { TileEntity tile = world.getTileEntity( pos ); - return ComputerCraft.enableCommandBlock && tile instanceof TileEntityCommandBlock ? new CommandBlockPeripheral( (TileEntityCommandBlock) tile ) : null; + return ComputerCraft.enableCommandBlock && tile instanceof CommandBlockTileEntity ? new CommandBlockPeripheral( (CommandBlockTileEntity) tile ) : null; } ); // Register bundled power providers @@ -96,7 +107,7 @@ public final class ComputerCraftProxyCommon ComputerCraftAPI.registerMediaProvider( stack -> { Item item = stack.getItem(); if( item instanceof IMedia ) return (IMedia) item; - if( item instanceof ItemRecord ) return RecordMedia.INSTANCE; + if( item instanceof MusicDiscItem ) return RecordMedia.INSTANCE; return null; } ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index 1e99819b1..7927934f7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -12,7 +12,7 @@ import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntityFurnace; +import net.minecraft.tileentity.FurnaceTileEntity; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -54,7 +54,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler int basicBurnTime = stack.getBurnTime(); int burnTime = ForgeEventFactory.getItemBurnTime( stack, - basicBurnTime == -1 ? TileEntityFurnace.getBurnTimes().getOrDefault( stack.getItem(), 0 ) : basicBurnTime + basicBurnTime == -1 ? FurnaceTileEntity.func_214001_f().getOrDefault( stack.getItem(), 0 ) : basicBurnTime ); return (burnTime * 5) / 100; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index d16515e3b..b5572b80c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -13,14 +13,15 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import dan200.computercraft.shared.util.WaterloggableBlock; +import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; -import net.minecraft.block.state.BlockFaceShape; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.IWaterLoggable; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.projectile.EntityFireball; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.DamagingProjectileEntity; import net.minecraft.fluid.IFluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; @@ -28,12 +29,11 @@ import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumBlockRenderType; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.world.*; @@ -41,7 +41,10 @@ import net.minecraft.world.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class BlockTurtle extends BlockComputerBase implements WaterloggableBlock +import static dan200.computercraft.shared.util.WaterloggableHelpers.*; +import static net.minecraft.state.properties.BlockStateProperties.WATERLOGGED; + +public class BlockTurtle extends BlockComputerBase implements IWaterLoggable { public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; @@ -50,17 +53,17 @@ public class BlockTurtle extends BlockComputerBase implements Waterl 0.875, 0.875, 0.875 ); - public BlockTurtle( Properties settings, ComputerFamily family, TileEntityType type ) + public BlockTurtle( Properties settings, ComputerFamily family, NamedTileEntityType type ) { super( settings, family, type ); setDefaultState( getStateContainer().getBaseState() - .with( FACING, EnumFacing.NORTH ) + .with( FACING, Direction.NORTH ) .with( WATERLOGGED, false ) ); } @Override - protected void fillStateContainer( StateContainer.Builder builder ) + protected void fillStateContainer( StateContainer.Builder builder ) { builder.add( FACING, WATERLOGGED ); } @@ -68,30 +71,15 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nonnull @Override @Deprecated - public EnumBlockRenderType getRenderType( IBlockState state ) + public BlockRenderType getRenderType( BlockState state ) { - return EnumBlockRenderType.INVISIBLE; - } - - @Override - @Deprecated - public boolean isFullCube( IBlockState state ) - { - return false; + return BlockRenderType.INVISIBLE; } @Nonnull @Override @Deprecated - public BlockFaceShape getBlockFaceShape( IBlockReader world, IBlockState state, BlockPos pos, EnumFacing side ) - { - return BlockFaceShape.UNDEFINED; - } - - @Nonnull - @Override - @Deprecated - public VoxelShape getShape( IBlockState state, IBlockReader world, BlockPos pos ) + public VoxelShape getShape( BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context ) { TileEntity tile = world.getTileEntity( pos ); Vec3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3d.ZERO; @@ -100,7 +88,7 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nullable @Override - public IBlockState getStateForPlacement( BlockItemUseContext placement ) + public BlockState getStateForPlacement( BlockItemUseContext placement ) { return getDefaultState() .with( FACING, placement.getPlacementHorizontalFacing() ) @@ -110,7 +98,7 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nonnull @Override @Deprecated - public IFluidState getFluidState( IBlockState state ) + public IFluidState getFluidState( BlockState state ) { return getWaterloggedFluidState( state ); } @@ -118,14 +106,14 @@ public class BlockTurtle extends BlockComputerBase implements Waterl @Nonnull @Override @Deprecated - public IBlockState updatePostPlacement( @Nonnull IBlockState state, EnumFacing side, IBlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + public BlockState updatePostPlacement( @Nonnull BlockState state, Direction side, BlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return state; } @Override - public void onBlockPlacedBy( World world, BlockPos pos, IBlockState state, @Nullable EntityLivingBase player, @Nonnull ItemStack stack ) + public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack ) { super.onBlockPlacedBy( world, pos, state, player, stack ); @@ -134,9 +122,9 @@ public class BlockTurtle extends BlockComputerBase implements Waterl { TileTurtle turtle = (TileTurtle) tile; - if( player instanceof EntityPlayer ) + if( player instanceof PlayerEntity ) { - ((TileTurtle) tile).setOwningPlayer( ((EntityPlayer) player).getGameProfile() ); + ((TileTurtle) tile).setOwningPlayer( ((PlayerEntity) player).getGameProfile() ); } if( stack.getItem() instanceof ITurtleItem ) @@ -163,9 +151,9 @@ public class BlockTurtle extends BlockComputerBase implements Waterl } @Override - public float getExplosionResistance( IBlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion ) + public float getExplosionResistance( BlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion ) { - if( getFamily() == ComputerFamily.Advanced && (exploder instanceof EntityLivingBase || exploder instanceof EntityFireball) ) + if( getFamily() == ComputerFamily.Advanced && (exploder instanceof LivingEntity || exploder instanceof DamagingProjectileEntity) ) { return 2000; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 59a396a9c..31933762e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -20,23 +20,23 @@ import dan200.computercraft.shared.computer.blocks.TileComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.Containers; import dan200.computercraft.shared.turtle.apis.TurtleAPI; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.util.*; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.init.Items; -import net.minecraft.item.EnumDyeColor; -import net.minecraft.item.ItemDye; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.DyeColor; +import net.minecraft.item.DyeItem; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.nbt.NBTTagList; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.Constants; @@ -57,12 +57,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public static final int INVENTORY_WIDTH = 4; public static final int INVENTORY_HEIGHT = 4; - public static final NamedBlockEntityType FACTORY_NORMAL = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), type -> new TileTurtle( type, ComputerFamily.Normal ) ); - public static final NamedBlockEntityType FACTORY_ADVANCED = NamedBlockEntityType.create( + public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), type -> new TileTurtle( type, ComputerFamily.Advanced ) ); @@ -143,7 +143,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default else { // Just turn off any redstone we had on - for( EnumFacing dir : DirectionUtil.FACINGS ) + for( Direction dir : DirectionUtil.FACINGS ) { RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir ); } @@ -171,18 +171,18 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - public boolean onActivate( EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ ) + public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { // Apply dye ItemStack currentItem = player.getHeldItem( hand ); if( !currentItem.isEmpty() ) { - if( currentItem.getItem() instanceof ItemDye ) + if( currentItem.getItem() instanceof DyeItem ) { // Dye to change turtle colour if( !getWorld().isRemote ) { - EnumDyeColor dye = ((ItemDye) currentItem.getItem()).getDyeColor(); + DyeColor dye = ((DyeItem) currentItem.getItem()).getDyeColor(); if( m_brain.getDyeColour() != dye ) { m_brain.setDyeColour( dye ); @@ -214,23 +214,23 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } // Open GUI or whatever - return super.onActivate( player, hand, side, hitX, hitY, hitZ ); + return super.onActivate( player, hand, hit ); } @Override - protected boolean canNameWithTag( EntityPlayer player ) + protected boolean canNameWithTag( PlayerEntity player ) { return true; } @Override - public void openGUI( EntityPlayer player ) + public void openGUI( PlayerEntity player ) { - Containers.openTurtleGUI( player, this ); + // TODO: Containers.openTurtleGUI( player, this ); } @Override - protected double getInteractRange( EntityPlayer player ) + protected double getInteractRange( PlayerEntity player ) { return 12.0; } @@ -285,17 +285,17 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - public void read( NBTTagCompound nbt ) + public void read( CompoundNBT nbt ) { super.read( nbt ); // Read inventory - NBTTagList nbttaglist = nbt.getList( "Items", Constants.NBT.TAG_COMPOUND ); + ListNBT nbttaglist = nbt.getList( "Items", Constants.NBT.TAG_COMPOUND ); m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); for( int i = 0; i < nbttaglist.size(); i++ ) { - NBTTagCompound tag = nbttaglist.getCompound( i ); + CompoundNBT tag = nbttaglist.getCompound( i ); int slot = tag.getByte( "Slot" ) & 0xff; if( slot < getSizeInventory() ) { @@ -310,15 +310,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Nonnull @Override - public NBTTagCompound write( NBTTagCompound nbt ) + public CompoundNBT write( CompoundNBT nbt ) { // Write inventory - NBTTagList nbttaglist = new NBTTagList(); + ListNBT nbttaglist = new ListNBT(); for( int i = 0; i < INVENTORY_SIZE; i++ ) { if( !m_inventory.get( i ).isEmpty() ) { - NBTTagCompound tag = new NBTTagCompound(); + CompoundNBT tag = new CompoundNBT(); tag.putByte( "Slot", (byte) i ); m_inventory.get( i ).write( tag ); nbttaglist.add( tag ); @@ -341,14 +341,14 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default // IDirectionalTile @Override - public EnumFacing getDirection() + public Direction getDirection() { return getBlockState().get( BlockTurtle.FACING ); } - public void setDirection( EnumFacing dir ) + public void setDirection( Direction dir ) { - if( dir.getAxis() == EnumFacing.Axis.Y ) dir = EnumFacing.NORTH; + if( dir.getAxis() == Direction.Axis.Y ) dir = Direction.NORTH; world.setBlockState( pos, getBlockState().with( BlockTurtle.FACING, dir ) ); updateOutput(); updateInput(); @@ -536,7 +536,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - public boolean isUsableByPlayer( @Nonnull EntityPlayer player ) + public boolean isUsableByPlayer( @Nonnull PlayerEntity player ) { return isUsable( player, false ); } @@ -555,14 +555,14 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default // Networking stuff @Override - protected void writeDescription( @Nonnull NBTTagCompound nbt ) + protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); m_brain.writeDescription( nbt ); } @Override - protected void readDescription( @Nonnull NBTTagCompound nbt ) + protected void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); m_brain.readDescription( nbt ); @@ -601,7 +601,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Nullable @Override - public IPeripheral getPeripheral( @Nonnull EnumFacing side ) + public IPeripheral getPeripheral( @Nonnull Direction side ) { return hasMoved() ? null : new ComputerPeripheral( "turtle", createProxy() ); } @@ -613,7 +613,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability cap, @Nullable EnumFacing side ) + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) { if( cap == ITEM_HANDLER_CAPABILITY ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java index 1e8a5175f..b102c1c53 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; public enum InteractDirection { @@ -15,7 +15,7 @@ public enum InteractDirection Up, Down; - public EnumFacing toWorldDir( ITurtleAccess turtle ) + public Direction toWorldDir( ITurtleAccess turtle ) { switch( this ) { @@ -23,9 +23,9 @@ public enum InteractDirection default: return turtle.getDirection(); case Up: - return EnumFacing.UP; + return Direction.UP; case Down: - return EnumFacing.DOWN; + return Direction.DOWN; } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java index 26c6d9681..2be874562 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; public enum MoveDirection { @@ -16,7 +16,7 @@ public enum MoveDirection Up, Down; - public EnumFacing toWorldDir( ITurtleAccess turtle ) + public Direction toWorldDir( ITurtleAccess turtle ) { switch( this ) { @@ -26,9 +26,9 @@ public enum MoveDirection case Back: return turtle.getDirection().getOpposite(); case Up: - return EnumFacing.UP; + return Direction.UP; case Down: - return EnumFacing.DOWN; + return Direction.DOWN; } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index b21c5e763..0920f28b5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -24,18 +24,18 @@ import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; import net.minecraft.fluid.IFluidState; -import net.minecraft.init.Particles; import net.minecraft.inventory.IInventory; -import net.minecraft.item.EnumDyeColor; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.item.DyeColor; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.ParticleTypes; import net.minecraft.tags.FluidTags; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EntitySelectors; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; +import net.minecraft.util.EntityPredicates; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -49,7 +49,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import static dan200.computercraft.shared.common.IColouredItem.NBT_COLOUR; -import static dan200.computercraft.shared.util.WaterloggableBlock.WATERLOGGED; +import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED; public class TurtleBrain implements ITurtleAccess { @@ -73,7 +73,7 @@ public class TurtleBrain implements ITurtleAccess private Map m_upgrades = new EnumMap<>( TurtleSide.class ); private Map peripherals = new EnumMap<>( TurtleSide.class ); - private Map m_upgradeNBTData = new EnumMap<>( TurtleSide.class ); + private Map m_upgradeNBTData = new EnumMap<>( TurtleSide.class ); private int m_selectedSlot = 0; private int m_fuelLevel = 0; @@ -154,7 +154,7 @@ public class TurtleBrain implements ITurtleAccess * * @param nbt The tag to read from */ - private void readCommon( NBTTagCompound nbt ) + private void readCommon( CompoundNBT nbt ) { // Read fields m_colourHex = nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : -1; @@ -177,7 +177,7 @@ public class TurtleBrain implements ITurtleAccess } } - private void writeCommon( NBTTagCompound nbt ) + private void writeCommon( CompoundNBT nbt ) { nbt.putInt( NBT_FUEL, m_fuelLevel ); if( m_colourHex != -1 ) nbt.putInt( NBT_COLOUR, m_colourHex ); @@ -200,7 +200,7 @@ public class TurtleBrain implements ITurtleAccess } } - public void readFromNBT( NBTTagCompound nbt ) + public void readFromNBT( CompoundNBT nbt ) { readCommon( nbt ); @@ -210,7 +210,7 @@ public class TurtleBrain implements ITurtleAccess // Read owner if( nbt.contains( "Owner", Constants.NBT.TAG_COMPOUND ) ) { - NBTTagCompound owner = nbt.getCompound( "Owner" ); + CompoundNBT owner = nbt.getCompound( "Owner" ); m_owningPlayer = new GameProfile( new UUID( owner.getLong( "UpperId" ), owner.getLong( "LowerId" ) ), owner.getString( "Name" ) @@ -222,7 +222,7 @@ public class TurtleBrain implements ITurtleAccess } } - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public CompoundNBT writeToNBT( CompoundNBT nbt ) { writeCommon( nbt ); @@ -232,7 +232,7 @@ public class TurtleBrain implements ITurtleAccess // Write owner if( m_owningPlayer != null ) { - NBTTagCompound owner = new NBTTagCompound(); + CompoundNBT owner = new CompoundNBT(); nbt.put( "Owner", owner ); owner.putLong( "UpperId", m_owningPlayer.getId().getMostSignificantBits() ); @@ -248,7 +248,7 @@ public class TurtleBrain implements ITurtleAccess return upgrade != null ? upgrade.getUpgradeID().toString() : null; } - public void readDescription( NBTTagCompound nbt ) + public void readDescription( CompoundNBT nbt ) { readCommon( nbt ); @@ -265,7 +265,7 @@ public class TurtleBrain implements ITurtleAccess } } - public void writeDescription( NBTTagCompound nbt ) + public void writeDescription( CompoundNBT nbt ) { writeCommon( nbt ); nbt.putInt( "Animation", m_animation.ordinal() ); @@ -297,7 +297,7 @@ public class TurtleBrain implements ITurtleAccess World oldWorld = getWorld(); TileTurtle oldOwner = m_owner; BlockPos oldPos = m_owner.getPos(); - IBlockState oldBlock = m_owner.getBlockState(); + BlockState oldBlock = m_owner.getBlockState(); if( oldWorld == world && oldPos.equals( pos ) ) { @@ -312,7 +312,7 @@ public class TurtleBrain implements ITurtleAccess if( !world.getWorldBorder().contains( pos ) ) return false; IFluidState existingFluid = world.getBlockState( pos ).getFluidState(); - IBlockState newState = oldBlock + BlockState newState = oldBlock // We only mark this as waterlogged when travelling into a source block. This prevents us from spreading // fluid by creating a new source when moving into a block, causing the next block to be almost full and // then moving into that. @@ -340,7 +340,7 @@ public class TurtleBrain implements ITurtleAccess newTurtle.createServerComputer().setPosition( pos ); // Remove the old turtle - oldWorld.removeBlock( oldPos ); + oldWorld.removeBlock( oldPos, false ); // Make sure everybody knows about it newTurtle.updateBlock(); @@ -351,7 +351,7 @@ public class TurtleBrain implements ITurtleAccess } // Something went wrong, remove the newly created turtle - world.removeBlock( pos ); + world.removeBlock( pos, false ); } } finally @@ -406,13 +406,13 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public EnumFacing getDirection() + public Direction getDirection() { return m_owner.getDirection(); } @Override - public void setDirection( @Nonnull EnumFacing dir ) + public void setDirection( @Nonnull Direction dir ) { m_owner.setDirection( dir ); } @@ -570,14 +570,14 @@ public class TurtleBrain implements ITurtleAccess } } - public EnumDyeColor getDyeColour() + public DyeColor getDyeColour() { if( m_colourHex == -1 ) return null; Colour colour = Colour.fromHex( m_colourHex ); - return colour == null ? null : EnumDyeColor.byId( 15 - colour.ordinal() ); + return colour == null ? null : DyeColor.byId( 15 - colour.ordinal() ); } - public void setDyeColour( EnumDyeColor dyeColour ) + public void setDyeColour( DyeColor dyeColour ) { int newColour = -1; if( dyeColour != null ) @@ -668,10 +668,10 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public NBTTagCompound getUpgradeNBTData( TurtleSide side ) + public CompoundNBT getUpgradeNBTData( TurtleSide side ) { - NBTTagCompound nbt = m_upgradeNBTData.get( side ); - if( nbt == null ) m_upgradeNBTData.put( side, nbt = new NBTTagCompound() ); + CompoundNBT nbt = m_upgradeNBTData.get( side ); + if( nbt == null ) m_upgradeNBTData.put( side, nbt = new CompoundNBT() ); return nbt; } @@ -691,7 +691,7 @@ public class TurtleBrain implements ITurtleAccess case MoveDown: { // Get direction - EnumFacing dir; + Direction dir; switch( m_animation ) { case MoveForward: @@ -702,10 +702,10 @@ public class TurtleBrain implements ITurtleAccess dir = getDirection().getOpposite(); break; case MoveUp: - dir = EnumFacing.UP; + dir = Direction.UP; break; case MoveDown: - dir = EnumFacing.DOWN; + dir = Direction.DOWN; break; } @@ -838,7 +838,7 @@ public class TurtleBrain implements ITurtleAccess m_animation == TurtleAnimation.MoveDown ) { BlockPos pos = getPosition(); - EnumFacing moveDir; + Direction moveDir; switch( m_animation ) { case MoveForward: @@ -849,10 +849,10 @@ public class TurtleBrain implements ITurtleAccess moveDir = getDirection().getOpposite(); break; case MoveUp: - moveDir = EnumFacing.UP; + moveDir = Direction.UP; break; case MoveDown: - moveDir = EnumFacing.DOWN; + moveDir = Direction.DOWN; break; } @@ -893,7 +893,7 @@ public class TurtleBrain implements ITurtleAccess } AxisAlignedBB aabb = new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ ); - List list = world.getEntitiesWithinAABB( Entity.class, aabb, EntitySelectors.NOT_SPECTATING ); + List list = world.getEntitiesWithinAABB( Entity.class, aabb, EntityPredicates.NOT_SPECTATING ); if( !list.isEmpty() ) { double pushStep = 1.0f / ANIM_DURATION; @@ -902,7 +902,7 @@ public class TurtleBrain implements ITurtleAccess double pushStepZ = moveDir.getZOffset() * pushStep; for( Entity entity : list ) { - entity.move( MoverType.PISTON, pushStepX, pushStepY, pushStepZ ); + entity.move( MoverType.PISTON, new Vec3d( pushStepX, pushStepY, pushStepZ ) ); } } } @@ -922,7 +922,7 @@ public class TurtleBrain implements ITurtleAccess double y = position.y + 0.5 + world.rand.nextGaussian() * 0.1; double z = position.z + world.rand.nextGaussian() * 0.1; world.addParticle( - Particles.HEART, x, y, z, + ParticleTypes.HEART, x, y, z, world.rand.nextGaussian() * 0.02, world.rand.nextGaussian() * 0.02, world.rand.nextGaussian() * 0.02 diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index 7e14655e1..3d143019d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -10,16 +10,17 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.NonNullList; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.ServerWorld; import net.minecraft.world.World; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import javax.annotation.Nonnull; import java.lang.reflect.Method; +import java.util.List; public class TurtleCompareCommand implements ITurtleCommand { @@ -35,7 +36,7 @@ public class TurtleCompareCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - EnumFacing direction = m_direction.toWorldDir( turtle ); + Direction direction = m_direction.toWorldDir( turtle ); // Get currently selected stack ItemStack selectedStack = turtle.getInventory().getStackInSlot( turtle.getSelectedSlot() ); @@ -48,7 +49,7 @@ public class TurtleCompareCommand implements ITurtleCommand ItemStack lookAtStack = ItemStack.EMPTY; if( !world.isAirBlock( newPosition ) ) { - IBlockState lookAtState = world.getBlockState( newPosition ); + BlockState lookAtState = world.getBlockState( newPosition ); Block lookAtBlock = lookAtState.getBlock(); if( !lookAtBlock.isAir( lookAtState, world, newPosition ) ) { @@ -57,7 +58,7 @@ public class TurtleCompareCommand implements ITurtleCommand { try { - Method method = ObfuscationReflectionHelper.findMethod( Block.class, "func_180643_i", IBlockState.class ); + Method method = ObfuscationReflectionHelper.findMethod( Block.class, "func_180643_i", BlockState.class ); lookAtStack = (ItemStack) method.invoke( lookAtBlock, lookAtState ); } catch( ReflectiveOperationException | RuntimeException ignored ) @@ -69,8 +70,7 @@ public class TurtleCompareCommand implements ITurtleCommand // (try 5 times to try and beat random number generators) for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ ) { - NonNullList drops = NonNullList.create(); - lookAtState.getDrops( drops, world, newPosition, 0 ); + List drops = Block.getDrops( lookAtState, (ServerWorld) world, newPosition, world.getTileEntity( newPosition ) ); if( !drops.isEmpty() ) { for( ItemStack drop : drops ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index ab89ae6b0..f450d3b5a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -10,7 +10,7 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -30,7 +30,7 @@ public class TurtleDetectCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - EnumFacing direction = m_direction.toWorldDir( turtle ); + Direction direction = m_direction.toWorldDir( turtle ); // Check if thing in front is air or not World world = turtle.getWorld(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index 21de8bab1..44297639b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -14,7 +14,7 @@ import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -45,7 +45,7 @@ public class TurtleDropCommand implements ITurtleCommand } // Get world direction from direction - EnumFacing direction = m_direction.toWorldDir( turtle ); + Direction direction = m_direction.toWorldDir( turtle ); // Get things to drop ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); @@ -58,7 +58,7 @@ public class TurtleDropCommand implements ITurtleCommand World world = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.offset( direction ); - EnumFacing side = direction.getOpposite(); + Direction side = direction.getOpposite(); IItemHandler inventory = InventoryUtil.getInventory( world, newPosition, side ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index d1f75e761..3a39bac20 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -12,9 +12,9 @@ import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.state.IProperty; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -38,14 +38,14 @@ public class TurtleInspectCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - EnumFacing direction = this.direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not World world = turtle.getWorld(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.offset( direction ); - IBlockState state = world.getBlockState( newPosition ); + BlockState state = world.getBlockState( newPosition ); if( state.getBlock().isAir( state, world, newPosition ) ) { return TurtleCommandResult.failure( "No block to inspect" ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index dfe3dd5c1..d6d639523 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -14,12 +14,13 @@ import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -40,7 +41,7 @@ public class TurtleMoveCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - EnumFacing direction = m_direction.toWorldDir( turtle ); + Direction direction = m_direction.toWorldDir( turtle ); // Check if we can move World oldWorld = turtle.getWorld(); @@ -55,7 +56,7 @@ public class TurtleMoveCommand implements ITurtleCommand } // Check existing block is air or replaceable - IBlockState state = oldWorld.getBlockState( newPosition ); + BlockState state = oldWorld.getBlockState( newPosition ); if( !oldWorld.isAirBlock( newPosition ) && !WorldUtil.isLiquidBlock( oldWorld, newPosition ) && !state.getMaterial().isReplaceable() ) @@ -64,14 +65,13 @@ public class TurtleMoveCommand implements ITurtleCommand } // Check there isn't anything in the way - AxisAlignedBB aabb = getBox( state.getCollisionShape( oldWorld, oldPosition ) ); - aabb = aabb.offset( + VoxelShape collision = state.getCollisionShape( oldWorld, oldPosition ).withOffset( newPosition.getX(), newPosition.getY(), newPosition.getZ() ); - if( !oldWorld.checkNoEntityCollision( null, aabb ) ) + if( !oldWorld.checkNoEntityCollision( null, collision ) ) { if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.Up || m_direction == MoveDirection.Down ) { @@ -79,19 +79,15 @@ public class TurtleMoveCommand implements ITurtleCommand } // Check there is space for all the pushable entities to be pushed - List list = oldWorld.getEntitiesWithinAABB( Entity.class, aabb, x -> x != null && x.isAlive() && x.preventEntitySpawning ); + List list = oldWorld.getEntitiesWithinAABB( Entity.class, getBox( collision ), x -> x != null && x.isAlive() && x.preventEntitySpawning ); for( Entity entity : list ) { - AxisAlignedBB entityBB = entity.getBoundingBox(); - if( entityBB == null ) entityBB = entity.getCollisionBoundingBox(); - if( entityBB == null ) continue; - - AxisAlignedBB pushedBB = entityBB.offset( + AxisAlignedBB pushedBB = entity.getBoundingBox().offset( direction.getXOffset(), direction.getYOffset(), direction.getZOffset() ); - if( !oldWorld.checkNoEntityCollision( null, pushedBB ) ) + if( !oldWorld.checkNoEntityCollision( null, VoxelShapes.create( pushedBB ) ) ) { return TurtleCommandResult.failure( "Movement obstructed" ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 22e65a5eb..b1896cec2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -17,19 +17,20 @@ import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DropConsumer; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.LivingEntity; import net.minecraft.item.*; +import net.minecraft.tileentity.SignTileEntity; import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntitySign; import net.minecraft.util.ActionResult; -import net.minecraft.util.EnumActionResult; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.MinecraftForge; @@ -63,7 +64,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } // Remember old block - EnumFacing direction = m_direction.toWorldDir( turtle ); + Direction direction = m_direction.toWorldDir( turtle ); BlockPos coordinates = turtle.getPosition().offset( direction ); // Create a fake player, and orient it appropriately @@ -95,7 +96,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { return TurtleCommandResult.failure( errorMessage[0] ); } - else if( stack.getItem() instanceof ItemBlock ) + else if( stack.getItem() instanceof BlockItem ) { return TurtleCommandResult.failure( "Cannot place block here" ); } @@ -106,7 +107,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } } - public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle, EnumFacing direction, Object[] extraArguments, String[] outErrorMessage ) + public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle, Direction direction, Object[] extraArguments, String[] outErrorMessage ) { // Create a fake player, and orient it appropriately BlockPos playerPosition = turtle.getPosition().offset( direction ); @@ -115,7 +116,7 @@ public class TurtlePlaceCommand implements ITurtleCommand return deploy( stack, turtle, turtlePlayer, direction, extraArguments, outErrorMessage ); } - public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, EnumFacing direction, Object[] extraArguments, String[] outErrorMessage ) + public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, Direction direction, Object[] extraArguments, String[] outErrorMessage ) { // Deploy on an entity ItemStack remainder = deployOnEntity( stack, turtle, turtlePlayer, direction, extraArguments, outErrorMessage ); @@ -140,10 +141,10 @@ public class TurtlePlaceCommand implements ITurtleCommand return remainder; } - if( direction.getAxis() != EnumFacing.Axis.Y ) + if( direction.getAxis() != Direction.Axis.Y ) { // Deploy down on the block in front - remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.down(), EnumFacing.UP, extraArguments, false, outErrorMessage ); + remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.down(), Direction.UP, extraArguments, false, outErrorMessage ); if( remainder != stack ) { return remainder; @@ -161,14 +162,14 @@ public class TurtlePlaceCommand implements ITurtleCommand return stack; } - public static TurtlePlayer createPlayer( ITurtleAccess turtle, BlockPos position, EnumFacing direction ) + public static TurtlePlayer createPlayer( ITurtleAccess turtle, BlockPos position, Direction direction ) { TurtlePlayer turtlePlayer = TurtlePlayer.get( turtle ); orientPlayer( turtle, turtlePlayer, position, direction ); return turtlePlayer; } - private static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing direction ) + private static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, Direction direction ) { turtlePlayer.posX = position.getX() + 0.5; turtlePlayer.posY = position.getY() + 0.5; @@ -182,7 +183,7 @@ public class TurtlePlaceCommand implements ITurtleCommand turtlePlayer.posZ += 0.48 * direction.getZOffset(); } - if( direction.getAxis() != EnumFacing.Axis.Y ) + if( direction.getAxis() != Direction.Axis.Y ) { turtlePlayer.rotationYaw = direction.getHorizontalAngle(); turtlePlayer.rotationPitch = 0.0f; @@ -204,7 +205,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } @Nonnull - private static ItemStack deployOnEntity( @Nonnull ItemStack stack, final ITurtleAccess turtle, TurtlePlayer turtlePlayer, EnumFacing direction, Object[] extraArguments, String[] outErrorMessage ) + private static ItemStack deployOnEntity( @Nonnull ItemStack stack, final ITurtleAccess turtle, TurtlePlayer turtlePlayer, Direction direction, Object[] extraArguments, String[] outErrorMessage ) { // See if there is an entity present final World world = turtle.getWorld(); @@ -231,33 +232,33 @@ public class TurtlePlaceCommand implements ITurtleCommand // Place on the entity boolean placed = false; - EnumActionResult cancelResult = ForgeHooks.onInteractEntityAt( turtlePlayer, hitEntity, hitPos, EnumHand.MAIN_HAND ); + ActionResultType cancelResult = ForgeHooks.onInteractEntityAt( turtlePlayer, hitEntity, hitPos, Hand.MAIN_HAND ); if( cancelResult == null ) { - cancelResult = hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, EnumHand.MAIN_HAND ); + cancelResult = hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, Hand.MAIN_HAND ); } - if( cancelResult == EnumActionResult.SUCCESS ) + if( cancelResult == ActionResultType.SUCCESS ) { placed = true; } else { // See EntityPlayer.interactOn - cancelResult = ForgeHooks.onInteractEntity( turtlePlayer, hitEntity, EnumHand.MAIN_HAND ); - if( cancelResult == EnumActionResult.SUCCESS ) + cancelResult = ForgeHooks.onInteractEntity( turtlePlayer, hitEntity, Hand.MAIN_HAND ); + if( cancelResult == ActionResultType.SUCCESS ) { placed = true; } else if( cancelResult == null ) { - if( hitEntity.processInitialInteract( turtlePlayer, EnumHand.MAIN_HAND ) ) + if( hitEntity.processInitialInteract( turtlePlayer, Hand.MAIN_HAND ) ) { placed = true; } - else if( hitEntity instanceof EntityLivingBase ) + else if( hitEntity instanceof LivingEntity ) { - placed = stackCopy.interactWithEntity( turtlePlayer, (EntityLivingBase) hitEntity, EnumHand.MAIN_HAND ); + placed = stackCopy.interactWithEntity( turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND ); if( placed ) turtlePlayer.loadInventory( stackCopy ); } } @@ -286,17 +287,17 @@ public class TurtlePlaceCommand implements ITurtleCommand } } - private static boolean canDeployOnBlock( @Nonnull BlockItemUseContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, EnumFacing side, boolean allowReplaceable, String[] outErrorMessage ) + private static boolean canDeployOnBlock( @Nonnull BlockItemUseContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, Direction side, boolean allowReplaceable, String[] outErrorMessage ) { World world = turtle.getWorld(); if( World.isValid( position ) && !world.isAirBlock( position ) && - !(context.getItem().getItem() instanceof ItemBlock && WorldUtil.isLiquidBlock( world, position )) ) + !(context.getItem().getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) ) { return false; } - IBlockState state = world.getBlockState( position ); + BlockState state = world.getBlockState( position ); boolean replaceable = state.isReplaceable( context ); if( !allowReplaceable && replaceable ) return false; @@ -318,10 +319,10 @@ public class TurtlePlaceCommand implements ITurtleCommand } @Nonnull - private static ItemStack deployOnBlock( @Nonnull ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, EnumFacing side, Object[] extraArguments, boolean allowReplace, String[] outErrorMessage ) + private static ItemStack deployOnBlock( @Nonnull ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, Direction side, Object[] extraArguments, boolean allowReplace, String[] outErrorMessage ) { // Re-orient the fake player - EnumFacing playerDir = side.getOpposite(); + Direction playerDir = side.getOpposite(); BlockPos playerPosition = position.offset( side ); orientPlayer( turtle, turtlePlayer, playerPosition, playerDir ); @@ -338,7 +339,8 @@ public class TurtlePlaceCommand implements ITurtleCommand } // Check if there's something suitable to place onto - ItemUseContext context = new ItemUseContext( turtlePlayer, stackCopy, position, side, hitX, hitY, hitZ ); + BlockRayTraceResult hit = new BlockRayTraceResult( new Vec3d( hitX, hitY, hitZ ), side, position, false ); + ItemUseContext context = new ItemUseContext( turtlePlayer, Hand.MAIN_HAND, hit ); if( !canDeployOnBlock( new BlockItemUseContext( context ), turtle, turtlePlayer, position, side, allowReplace, outErrorMessage ) ) { return stack; @@ -353,33 +355,33 @@ public class TurtlePlaceCommand implements ITurtleCommand // See PlayerInteractionManager.processRightClickBlock // TODO: ^ Check we're still consistent. - PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, position, side, new Vec3d( hitX, hitY, hitZ ) ); + PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, Hand.MAIN_HAND, position, side ); if( !event.isCanceled() ) { - if( item.onItemUseFirst( stack, context ) == EnumActionResult.SUCCESS ) + if( item.onItemUseFirst( stack, context ) == ActionResultType.SUCCESS ) { placed = true; turtlePlayer.loadInventory( stackCopy ); } else if( event.getUseItem() != Event.Result.DENY && - stackCopy.onItemUse( context ) == EnumActionResult.SUCCESS ) + stackCopy.onItemUse( context ) == ActionResultType.SUCCESS ) { placed = true; turtlePlayer.loadInventory( stackCopy ); } } - if( !placed && (item instanceof ItemBucket || item instanceof ItemBoat || item instanceof ItemLilyPad || item instanceof ItemGlassBottle) ) + if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem) ) { - EnumActionResult actionResult = ForgeHooks.onItemRightClick( turtlePlayer, EnumHand.MAIN_HAND ); - if( actionResult == EnumActionResult.SUCCESS ) + ActionResultType actionResult = ForgeHooks.onItemRightClick( turtlePlayer, Hand.MAIN_HAND ); + if( actionResult == ActionResultType.SUCCESS ) { placed = true; } else if( actionResult == null ) { - ActionResult result = stackCopy.useItemRightClick( turtle.getWorld(), turtlePlayer, EnumHand.MAIN_HAND ); - if( result.getType() == EnumActionResult.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) ) + ActionResult result = stackCopy.useItemRightClick( turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND ); + if( result.getType() == ActionResultType.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) ) { placed = true; turtlePlayer.loadInventory( result.getResult() ); @@ -388,7 +390,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } // Set text on signs - if( placed && item instanceof ItemSign ) + if( placed && item instanceof SignItem ) { if( extraArguments != null && extraArguments.length >= 1 && extraArguments[0] instanceof String ) { @@ -398,9 +400,9 @@ public class TurtlePlaceCommand implements ITurtleCommand { tile = world.getTileEntity( position.offset( side ) ); } - if( tile instanceof TileEntitySign ) + if( tile instanceof SignTileEntity ) { - TileEntitySign signTile = (TileEntitySign) tile; + SignTileEntity signTile = (SignTileEntity) tile; String s = (String) extraArguments[0]; String[] split = s.split( "\n" ); int firstLine = split.length <= 2 ? 1 : 0; @@ -410,20 +412,20 @@ public class TurtlePlaceCommand implements ITurtleCommand { if( split[i - firstLine].length() > 15 ) { - signTile.signText[i] = new TextComponentString( split[i - firstLine].substring( 0, 15 ) ); + signTile.signText[i] = new StringTextComponent( split[i - firstLine].substring( 0, 15 ) ); } else { - signTile.signText[i] = new TextComponentString( split[i - firstLine] ); + signTile.signText[i] = new StringTextComponent( split[i - firstLine] ); } } else { - signTile.signText[i] = new TextComponentString( "" ); + signTile.signText[i] = new StringTextComponent( "" ); } } signTile.markDirty(); - world.markBlockRangeForRenderUpdate( signTile.getPos(), signTile.getPos() ); + world.notifyBlockUpdate( tile.getPos(), tile.getBlockState(), tile.getBlockState(), 3 ); } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 564033055..6dadf9126 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -11,20 +11,13 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityClassification; import net.minecraft.entity.EntityType; -import net.minecraft.entity.IMerchant; -import net.minecraft.entity.passive.AbstractHorse; -import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntitySign; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.IInteractionObject; -import net.minecraft.world.World; -import net.minecraft.world.WorldServer; +import net.minecraft.world.ServerWorld; import net.minecraftforge.common.util.FakePlayer; import javax.annotation.Nonnull; @@ -33,24 +26,20 @@ import java.util.UUID; public final class TurtlePlayer extends FakePlayer { - public static final GameProfile DEFAULT_PROFILE = new GameProfile( + private static final GameProfile DEFAULT_PROFILE = new GameProfile( UUID.fromString( "0d0c4ca0-4ff1-11e4-916c-0800200c9a66" ), "[ComputerCraft]" ); - public static final EntityType TYPE = EntityType.Builder.create( TurtlePlayer.class, TurtlePlayer::new ) + public static final EntityType TYPE = EntityType.Builder.create( EntityClassification.MISC ) .disableSerialization() .disableSummoning() + .size( 0, 0 ) .build( ComputerCraft.MOD_ID + ":turtle_player" ); - private TurtlePlayer( World world ) - { - super( (WorldServer) world, DEFAULT_PROFILE ); - } - private TurtlePlayer( ITurtleAccess turtle ) { - super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); + super( (ServerWorld) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); setState( turtle ); } @@ -106,7 +95,7 @@ public final class TurtlePlayer extends FakePlayer // Store (or drop) anything else we found BlockPos dropPosition = turtle.getPosition(); - EnumFacing dropDirection = turtle.getDirection().getOpposite(); + Direction dropDirection = turtle.getDirection().getOpposite(); for( int i = 0; i < inventory.getSizeInventory(); i++ ) { ItemStack stack = inventory.getStackInSlot( i ); @@ -124,92 +113,19 @@ public final class TurtlePlayer extends FakePlayer return results; } + @Nonnull + @Override + public EntityType getType() + { + return TYPE; + } + @Override public Vec3d getPositionVector() { return new Vec3d( posX, posY, posZ ); } - @Override - public float getEyeHeight() - { - return 0.0f; - } - - @Override - public float getDefaultEyeHeight() - { - return 0.0f; - } - - @Override - public void sendEnterCombat() - { - } - - @Override - public void sendEndCombat() - { - } - - @Nonnull - @Override - public SleepResult trySleep( @Nonnull BlockPos bedLocation ) - { - return SleepResult.OTHER_PROBLEM; - } - - // TODO: Flesh this out. Or just stub out the connection, like plethora? - - @Override - public void openSignEditor( TileEntitySign signTile ) - { - } - - @Override - public void displayGui( IInteractionObject guiOwner ) - { - } - - @Override - public void displayGUIChest( IInventory chestInventory ) - { - } - - @Override - public void displayVillagerTradeGui( IMerchant villager ) - { - } - - @Override - public void openHorseInventory( AbstractHorse horse, IInventory inventoryIn ) - { - } - - @Override - public void openBook( ItemStack stack, @Nonnull EnumHand hand ) - { - } - - @Override - public void updateHeldItem() - { - } - - @Override - protected void onItemUseFinish() - { - } - - /* - @Override - public void mountEntityAndWakeUp() - { - } - */ - - @Override - public void dismountEntity( @Nonnull Entity entity ) - { - } + // TODO: Work out what needs stubbing again. + // Or just replace the network. } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index 7fd9b598d..37794b732 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -12,10 +12,10 @@ import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; -import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; -import net.minecraft.util.EntitySelectors; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; +import net.minecraft.util.EntityPredicates; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -48,13 +48,13 @@ public class TurtleSuckCommand implements ITurtleCommand } // Get world direction from direction - EnumFacing direction = m_direction.toWorldDir( turtle ); + Direction direction = m_direction.toWorldDir( turtle ); // Get inventory for thing in front World world = turtle.getWorld(); BlockPos turtlePosition = turtle.getPosition(); BlockPos blockPosition = turtlePosition.offset( direction ); - EnumFacing side = direction.getOpposite(); + Direction side = direction.getOpposite(); IItemHandler inventory = InventoryUtil.getInventory( world, blockPosition, side ); @@ -98,10 +98,10 @@ public class TurtleSuckCommand implements ITurtleCommand blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), blockPosition.getX() + 1.0, blockPosition.getY() + 1.0, blockPosition.getZ() + 1.0 ); - List list = world.getEntitiesWithinAABB( EntityItem.class, aabb, EntitySelectors.IS_ALIVE ); + List list = world.getEntitiesWithinAABB( ItemEntity.class, aabb, EntityPredicates.IS_ALIVE ); if( list.isEmpty() ) return TurtleCommandResult.failure( "No items to take" ); - for( EntityItem entity : list ) + for( ItemEntity entity : list ) { // Suck up the item ItemStack stack = entity.getItem().copy(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 26ee1e557..61713a0af 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -12,11 +12,11 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtleBrain; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.inventory.IContainerListener; -import net.minecraft.inventory.IInventory; -import net.minecraft.inventory.Slot; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; @@ -24,30 +24,29 @@ import javax.annotation.Nullable; public class ContainerTurtle extends Container implements IContainerComputer { - private static final int PROGRESS_ID_SELECTED_SLOT = 0; + public static final ContainerType TYPE = null; - public final int playerInvStartY; - public final int turtleInvStartX; + public static final int PLAYER_START_Y = 134; + public static final int TURTLE_START_X = 175; private final ITurtleAccess m_turtle; private IComputer m_computer; private final InputState input = new InputState( this ); - private int m_selectedSlot; + private int selectedSlot; - protected ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle, int playerInvStartY, int turtleInvStartX ) + protected ContainerTurtle( int id, PlayerInventory playerInventory, ITurtleAccess turtle ) { - this.playerInvStartY = playerInvStartY; - this.turtleInvStartX = turtleInvStartX; + super( TYPE, id ); m_turtle = turtle; - m_selectedSlot = m_turtle.getWorld().isRemote ? 0 : m_turtle.getSelectedSlot(); + selectedSlot = m_turtle.getWorld().isRemote ? 0 : m_turtle.getSelectedSlot(); // Turtle inventory for( int y = 0; y < 4; y++ ) { for( int x = 0; x < 4; x++ ) { - addSlot( new Slot( m_turtle.getInventory(), x + y * 4, turtleInvStartX + 1 + x * 18, playerInvStartY + 1 + y * 18 ) ); + addSlot( new Slot( m_turtle.getInventory(), x + y * 4, TURTLE_START_X + 1 + x * 18, PLAYER_START_Y + 1 + y * 18 ) ); } } @@ -56,83 +55,37 @@ public class ContainerTurtle extends Container implements IContainerComputer { for( int x = 0; x < 9; x++ ) { - addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, playerInvStartY + 1 + y * 18 ) ); + addSlot( new Slot( playerInventory, x + y * 9 + 9, 8 + x * 18, PLAYER_START_Y + 1 + y * 18 ) ); } } // Player hotbar for( int x = 0; x < 9; x++ ) { - addSlot( new Slot( playerInventory, x, 8 + x * 18, playerInvStartY + 3 * 18 + 5 ) ); + addSlot( new Slot( playerInventory, x, 8 + x * 18, PLAYER_START_Y + 3 * 18 + 5 ) ); } } - public ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle ) + public ContainerTurtle( int id, PlayerInventory playerInventory, ITurtleAccess turtle, IComputer computer ) { - this( playerInventory, turtle, 134, 175 ); - } - - public ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle, IComputer computer ) - { - this( playerInventory, turtle ); + this( id, playerInventory, turtle ); m_computer = computer; } public int getSelectedSlot() { - return m_selectedSlot; - } - - private void sendStateToPlayer( IContainerListener listener ) - { - int selectedSlot = m_turtle.getSelectedSlot(); - listener.sendWindowProperty( this, PROGRESS_ID_SELECTED_SLOT, selectedSlot ); + return selectedSlot; } @Override - public void addListener( IContainerListener listener ) - { - super.addListener( listener ); - sendStateToPlayer( listener ); - } - - @Override - public void detectAndSendChanges() - { - super.detectAndSendChanges(); - - int selectedSlot = m_turtle.getSelectedSlot(); - for( IContainerListener listener : listeners ) - { - if( m_selectedSlot != selectedSlot ) - { - listener.sendWindowProperty( this, PROGRESS_ID_SELECTED_SLOT, selectedSlot ); - } - } - m_selectedSlot = selectedSlot; - } - - @Override - public void updateProgressBar( int id, int value ) - { - super.updateProgressBar( id, value ); - switch( id ) - { - case PROGRESS_ID_SELECTED_SLOT: - m_selectedSlot = value; - break; - } - } - - @Override - public boolean canInteractWith( @Nonnull EntityPlayer player ) + public boolean canInteractWith( @Nonnull PlayerEntity player ) { TileTurtle turtle = ((TurtleBrain) m_turtle).getOwner(); return turtle != null && turtle.isUsableByPlayer( player ); } @Nonnull - private ItemStack tryItemMerge( EntityPlayer player, int slotNum, int firstSlot, int lastSlot, boolean reverse ) + private ItemStack tryItemMerge( PlayerEntity player, int slotNum, int firstSlot, int lastSlot, boolean reverse ) { Slot slot = inventorySlots.get( slotNum ); ItemStack originalStack = ItemStack.EMPTY; @@ -168,7 +121,7 @@ public class ContainerTurtle extends Container implements IContainerComputer @Nonnull @Override - public ItemStack transferStackInSlot( EntityPlayer player, int slotNum ) + public ItemStack transferStackInSlot( PlayerEntity player, int slotNum ) { if( slotNum >= 0 && slotNum < 16 ) { @@ -196,7 +149,7 @@ public class ContainerTurtle extends Container implements IContainerComputer } @Override - public void onContainerClosed( EntityPlayer player ) + public void onContainerClosed( PlayerEntity player ) { super.onContainerClosed( player ); input.close(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index 33519d2d6..889cf1a20 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -16,12 +16,12 @@ import dan200.computercraft.shared.computer.items.ItemComputerBase; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -39,7 +39,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem { // Build the stack ItemStack stack = new ItemStack( this ); - if( label != null ) stack.setDisplayName( new TextComponentString( label ) ); + if( label != null ) stack.setDisplayName( new StringTextComponent( label ) ); if( id >= 0 ) stack.getOrCreateTag().putInt( NBT_ID, id ); IColouredItem.setColourBasic( stack, colour ); if( fuelLevel > 0 ) stack.getOrCreateTag().putInt( NBT_FUEL, fuelLevel ); @@ -83,26 +83,26 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); if( left != null && right != null ) { - return new TextComponentTranslation( baseString + ".upgraded_twice", - new TextComponentTranslation( right.getUnlocalisedAdjective() ), - new TextComponentTranslation( left.getUnlocalisedAdjective() ) + return new TranslationTextComponent( baseString + ".upgraded_twice", + new TranslationTextComponent( right.getUnlocalisedAdjective() ), + new TranslationTextComponent( left.getUnlocalisedAdjective() ) ); } else if( left != null ) { - return new TextComponentTranslation( baseString + ".upgraded", - new TextComponentTranslation( left.getUnlocalisedAdjective() ) + return new TranslationTextComponent( baseString + ".upgraded", + new TranslationTextComponent( left.getUnlocalisedAdjective() ) ); } else if( right != null ) { - return new TextComponentTranslation( baseString + ".upgraded", - new TextComponentTranslation( right.getUnlocalisedAdjective() ) + return new TranslationTextComponent( baseString + ".upgraded", + new TranslationTextComponent( right.getUnlocalisedAdjective() ) ); } else { - return new TextComponentTranslation( baseString ); + return new TranslationTextComponent( baseString ); } } @@ -144,7 +144,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem @Override public ITurtleUpgrade getUpgrade( @Nonnull ItemStack stack, @Nonnull TurtleSide side ) { - NBTTagCompound tag = stack.getTag(); + CompoundNBT tag = stack.getTag(); if( tag == null ) return null; String key = side == TurtleSide.Left ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE; @@ -154,14 +154,14 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem @Override public ResourceLocation getOverlay( @Nonnull ItemStack stack ) { - NBTTagCompound tag = stack.getTag(); + CompoundNBT tag = stack.getTag(); return tag != null && tag.contains( NBT_OVERLAY ) ? new ResourceLocation( tag.getString( NBT_OVERLAY ) ) : null; } @Override public int getFuelLevel( @Nonnull ItemStack stack ) { - NBTTagCompound tag = stack.getTag(); + CompoundNBT tag = stack.getTag(); return tag != null && tag.contains( NBT_FUEL ) ? tag.getInt( NBT_FUEL ) : 0; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java index ff48d31da..103654b99 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.recipes; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe; @@ -43,7 +42,6 @@ public final class TurtleRecipe extends ComputerFamilyRecipe return TurtleItemFactory.create( computerID, label, -1, getFamily(), null, null, 0, null ); } - private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ); public static final IRecipeSerializer SERIALIZER = new Serializer() { @Override @@ -51,12 +49,5 @@ public final class TurtleRecipe extends ComputerFamilyRecipe { return new TurtleRecipe( identifier, group, width, height, ingredients, result, family ); } - - @Nonnull - @Override - public ResourceLocation getName() - { - return ID; - } }; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index c896666f6..40a01cf6e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -6,24 +6,23 @@ package dan200.computercraft.shared.turtle.recipes; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import dan200.computercraft.shared.util.AbstractRecipe; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; -import net.minecraft.item.crafting.RecipeSerializers; +import net.minecraft.item.crafting.SpecialRecipe; +import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import javax.annotation.Nonnull; -public final class TurtleUpgradeRecipe extends AbstractRecipe +public final class TurtleUpgradeRecipe extends SpecialRecipe { private TurtleUpgradeRecipe( ResourceLocation id ) { @@ -44,14 +43,14 @@ public final class TurtleUpgradeRecipe extends AbstractRecipe } @Override - public boolean matches( @Nonnull IInventory inventory, @Nonnull World world ) + public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world ) { return !getCraftingResult( inventory ).isEmpty(); } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inventory ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory ) { // Scan the grid for a row containing a turtle and 1 or 2 items ItemStack leftItem = ItemStack.EMPTY; @@ -187,7 +186,5 @@ public final class TurtleUpgradeRecipe extends AbstractRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new RecipeSerializers.SimpleSerializer<>( - ComputerCraft.MOD_ID + ":turtle_upgrade", TurtleUpgradeRecipe::new - ); + public static final IRecipeSerializer SERIALIZER = new SpecialRecipeSerializer<>( TurtleUpgradeRecipe::new ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 884781afc..c73df2afc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -11,11 +11,11 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; +import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.init.Blocks; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index 13a7e6d17..e7dda6993 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -12,11 +12,11 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import net.minecraft.block.BlockState; import net.minecraft.block.material.Material; -import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -36,7 +36,7 @@ public class TurtleHoe extends TurtleTool } @Override - protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) { if( !super.canBreakBlock( state, world, pos, player ) ) return false; @@ -46,12 +46,12 @@ public class TurtleHoe extends TurtleTool material == Material.GOURD || material == Material.LEAVES || material == Material.OCEAN_PLANT || - material == Material.VINE; + material == Material.TALL_PLANTS; } @Nonnull @Override - public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing direction ) + public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) { if( verb == TurtleVerb.Dig ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 169dd98cc..85fe72fea 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -9,17 +9,15 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeType; import net.minecraft.util.NonNullList; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TextComponentString; +import net.minecraft.world.ServerWorld; import net.minecraft.world.World; -import net.minecraft.world.WorldServer; import net.minecraftforge.common.ForgeHooks; -import net.minecraftforge.common.crafting.VanillaRecipeTypes; import net.minecraftforge.fml.hooks.BasicEventHooks; import javax.annotation.Nonnull; @@ -28,7 +26,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -public class TurtleInventoryCrafting extends InventoryCrafting +public class TurtleInventoryCrafting extends CraftingInventory { private ITurtleAccess m_turtle; private int m_xStart; @@ -46,7 +44,7 @@ public class TurtleInventoryCrafting extends InventoryCrafting } @Nullable - private IRecipe tryCrafting( int xStart, int yStart ) + private IRecipe tryCrafting( int xStart, int yStart ) { m_xStart = xStart; m_yStart = yStart; @@ -68,16 +66,16 @@ public class TurtleInventoryCrafting extends InventoryCrafting } // Check the actual crafting - return m_turtle.getWorld().getRecipeManager().getRecipe( this, m_turtle.getWorld(), VanillaRecipeTypes.CRAFTING ); + return m_turtle.getWorld().getRecipeManager().func_215371_a( IRecipeType.field_222149_a, this, m_turtle.getWorld() ).orElse( null ); } @Nullable public List doCrafting( World world, int maxCount ) { - if( world.isRemote || !(world instanceof WorldServer) ) return null; + if( world.isRemote || !(world instanceof ServerWorld) ) return null; // Find out what we can craft - IRecipe recipe = tryCrafting( 0, 0 ); + IRecipe recipe = tryCrafting( 0, 0 ); if( recipe == null ) recipe = tryCrafting( 0, 1 ); if( recipe == null ) recipe = tryCrafting( 1, 0 ); if( recipe == null ) recipe = tryCrafting( 1, 1 ); @@ -173,19 +171,6 @@ public class TurtleInventoryCrafting extends InventoryCrafting return m_turtle.getInventory().getStackInSlot( i ); } - @Nonnull - @Override - public ITextComponent getName() - { - return new TextComponentString( "" ); - } - - @Override - public boolean hasCustomName() - { - return false; - } - @Nonnull @Override public ItemStack removeStackFromSlot( int i ) @@ -222,7 +207,7 @@ public class TurtleInventoryCrafting extends InventoryCrafting } @Override - public boolean isUsableByPlayer( EntityPlayer player ) + public boolean isUsableByPlayer( PlayerEntity player ) { return true; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 4fa8e9a62..e6bbcf6d5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -16,8 +16,8 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.EnumFacing; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -100,7 +100,7 @@ public class TurtleModem extends AbstractTurtleUpgrade @Nonnull @Override - public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing dir ) + public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction dir ) { return TurtleCommandResult.failure(); } @@ -137,7 +137,7 @@ public class TurtleModem extends AbstractTurtleUpgrade boolean active = false; if( turtle != null ) { - NBTTagCompound turtleNBT = turtle.getUpgradeNBTData( side ); + CompoundNBT turtleNBT = turtle.getUpgradeNBTData( side ); if( turtleNBT.contains( "active" ) ) { active = turtleNBT.getBoolean( "active" ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index 464765a8e..8c30075f6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -12,11 +12,11 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleVerb; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import net.minecraft.block.BlockState; import net.minecraft.block.material.Material; -import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -36,27 +36,26 @@ public class TurtleShovel extends TurtleTool } @Override - protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) { if( !super.canBreakBlock( state, world, pos, player ) ) return false; Material material = state.getMaterial(); - return material == Material.GROUND || + return material == Material.EARTH || material == Material.SAND || material == Material.SNOW || material == Material.CLAY || - material == Material.CRAFTED_SNOW || - material == Material.GRASS || + material == Material.SNOW_BLOCK || material == Material.PLANTS || material == Material.CACTUS || material == Material.GOURD || material == Material.LEAVES || - material == Material.VINE; + material == Material.TALL_PLANTS; } @Nonnull @Override - public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing direction ) + public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) { if( verb == TurtleVerb.Dig ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 31b445081..dd6a64daf 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -7,8 +7,8 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import net.minecraft.block.BlockState; import net.minecraft.block.material.Material; -import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -27,15 +27,15 @@ public class TurtleSword extends TurtleTool } @Override - protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) { if( !super.canBreakBlock( state, world, pos, player ) ) return false; Material material = state.getMaterial(); return material == Material.PLANTS || material == Material.LEAVES || - material == Material.VINE || - material == Material.CLOTH || + material == Material.TALL_PLANTS || + material == Material.WOOL || material == Material.WEB; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 3d64cd141..5f82731b9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -18,19 +18,19 @@ import dan200.computercraft.shared.util.DropConsumer; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; -import net.minecraft.block.state.IBlockState; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; -import net.minecraft.entity.item.EntityArmorStand; +import net.minecraft.entity.item.ArmorStandEntity; import net.minecraft.fluid.IFluidState; -import net.minecraft.init.Blocks; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -84,7 +84,7 @@ public class TurtleTool extends AbstractTurtleUpgrade @Nonnull @Override - public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull EnumFacing direction ) + public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) { switch( verb ) { @@ -97,7 +97,7 @@ public class TurtleTool extends AbstractTurtleUpgrade } } - protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) + protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player ) { Block block = state.getBlock(); return !state.isAir( world, pos ) @@ -111,7 +111,7 @@ public class TurtleTool extends AbstractTurtleUpgrade return 3.0f; } - private TurtleCommandResult attack( final ITurtleAccess turtle, EnumFacing direction, TurtleSide side ) + private TurtleCommandResult attack( final ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Create a fake player, and orient it appropriately final World world = turtle.getWorld(); @@ -154,7 +154,7 @@ public class TurtleTool extends AbstractTurtleUpgrade if( damage > 0.0f ) { DamageSource source = DamageSource.causePlayerDamage( turtlePlayer ); - if( hitEntity instanceof EntityArmorStand ) + if( hitEntity instanceof ArmorStandEntity ) { // Special case for armor stands: attack twice to guarantee destroy hitEntity.attackEntityFrom( source, damage ); @@ -188,7 +188,7 @@ public class TurtleTool extends AbstractTurtleUpgrade return TurtleCommandResult.failure( "Nothing to attack here" ); } - private TurtleCommandResult dig( ITurtleAccess turtle, EnumFacing direction, TurtleSide side ) + private TurtleCommandResult dig( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Get ready to dig World world = turtle.getWorld(); @@ -200,7 +200,7 @@ public class TurtleTool extends AbstractTurtleUpgrade return TurtleCommandResult.failure( "Nothing to dig here" ); } - IBlockState state = world.getBlockState( blockPosition ); + BlockState state = world.getBlockState( blockPosition ); IFluidState fluidState = world.getFluidState( blockPosition ); TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); diff --git a/src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java b/src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java deleted file mode 100644 index a6908bbee..000000000 --- a/src/main/java/dan200/computercraft/shared/util/AbstractRecipe.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.util; - -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipe; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; - -public abstract class AbstractRecipe implements IRecipe -{ - private final ResourceLocation id; - - public AbstractRecipe( ResourceLocation id ) - { - this.id = id; - } - - @Nonnull - @Override - public ItemStack getRecipeOutput() - { - return ItemStack.EMPTY; - } - - @Nonnull - @Override - public ResourceLocation getId() - { - return id; - } - - @Override - public boolean isDynamic() - { - return true; - } -} diff --git a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java index 41152fb4c..ae0c9f403 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java @@ -6,8 +6,10 @@ package dan200.computercraft.shared.util; +import net.minecraft.item.crafting.ArmorDyeRecipe; + /** - * A reimplementation of the colour system in {@link net.minecraft.item.crafting.RecipesArmorDyes}, but + * A reimplementation of the colour system in {@link ArmorDyeRecipe}, but * bundled together as an object. */ public class ColourTracker diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 22d47f827..dcf0ee2b0 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.util; -import net.minecraft.item.EnumDyeColor; +import net.minecraft.item.DyeColor; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tags.Tag; @@ -39,12 +39,12 @@ public final class ColourUtils @Nullable private ColourUtils() {} - public static EnumDyeColor getStackColour( ItemStack stack ) + public static DyeColor getStackColour( ItemStack stack ) { for( int i = 0; i < DYES.length; i++ ) { Tag dye = DYES[i]; - if( dye.contains( stack.getItem() ) ) return EnumDyeColor.byId( i ); + if( dye.contains( stack.getItem() ) ) return DyeColor.byId( i ); } return null; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java b/src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java deleted file mode 100644 index 878f2951a..000000000 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInteractionObject.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.util; - -import dan200.computercraft.shared.network.container.ContainerType; -import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.entity.player.InventoryPlayer; -import net.minecraft.inventory.Container; -import net.minecraft.world.IInteractionObject; - -import javax.annotation.Nonnull; - -public interface DefaultInteractionObject extends IInteractionObject -{ - @Nonnull - @Override - T createContainer( @Nonnull InventoryPlayer inventory, @Nonnull EntityPlayer player ); - - @Nonnull - ContainerType getContainerType(); - - @Nonnull - @Override - default String getGuiID() - { - return getContainerType().getId().toString(); - } -} diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index dbaf26825..0a369e72b 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -6,13 +6,11 @@ package dan200.computercraft.shared.util; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; -import net.minecraft.util.text.ITextComponent; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public interface DefaultInventory extends IInventory { @@ -23,12 +21,12 @@ public interface DefaultInventory extends IInventory } @Override - default void openInventory( @Nonnull EntityPlayer player ) + default void openInventory( @Nonnull PlayerEntity player ) { } @Override - default void closeInventory( @Nonnull EntityPlayer player ) + default void closeInventory( @Nonnull PlayerEntity player ) { } @@ -37,34 +35,4 @@ public interface DefaultInventory extends IInventory { return true; } - - @Override - default int getField( int field ) - { - return 0; - } - - @Override - default void setField( int field, int value ) - { - } - - @Override - default int getFieldCount() - { - return 0; - } - - @Override - default boolean hasCustomName() - { - return getCustomName() != null; - } - - @Nullable - @Override - default ITextComponent getCustomName() - { - return null; - } } diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index 2c1f0bc24..e02ea273b 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.util; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -16,13 +16,13 @@ import javax.annotation.Nullable; public interface DefaultSidedInventory extends DefaultInventory, ISidedInventory { @Override - default boolean canInsertItem( int slot, @Nonnull ItemStack stack, @Nullable EnumFacing side ) + default boolean canInsertItem( int slot, @Nonnull ItemStack stack, @Nullable Direction side ) { return isItemValidForSlot( slot, stack ); } @Override - default boolean canExtractItem( int slot, @Nonnull ItemStack stack, @Nonnull EnumFacing side ) + default boolean canExtractItem( int slot, @Nonnull ItemStack stack, @Nonnull Direction side ) { return true; } diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java index cee516e4c..6c6de1087 100644 --- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java @@ -7,27 +7,27 @@ package dan200.computercraft.shared.util; import dan200.computercraft.core.computer.ComputerSide; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; public final class DirectionUtil { private DirectionUtil() {} - public static final EnumFacing[] FACINGS = EnumFacing.values(); + public static final Direction[] FACINGS = Direction.values(); - public static ComputerSide toLocal( EnumFacing front, EnumFacing dir ) + public static ComputerSide toLocal( Direction front, Direction dir ) { - if( front.getAxis() == EnumFacing.Axis.Y ) front = EnumFacing.NORTH; + if( front.getAxis() == Direction.Axis.Y ) front = Direction.NORTH; if( dir == front ) return ComputerSide.FRONT; if( dir == front.getOpposite() ) return ComputerSide.BACK; if( dir == front.rotateYCCW() ) return ComputerSide.LEFT; if( dir == front.rotateY() ) return ComputerSide.RIGHT; - if( dir == EnumFacing.UP ) return ComputerSide.TOP; + if( dir == Direction.UP ) return ComputerSide.TOP; return ComputerSide.BOTTOM; } - public static float toPitchAngle( EnumFacing dir ) + public static float toPitchAngle( Direction dir ) { switch( dir ) { diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 701dc8dbd..ca28204bf 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; import net.minecraft.entity.Entity; -import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -69,10 +69,10 @@ public final class DropConsumer Entity entity = dropEntity.get(); if( entity != null ) { - Collection dropped = entity.captureDrops( null ); + Collection dropped = entity.captureDrops( null ); if( dropped != null ) { - for( EntityItem entityItem : dropped ) handleDrops( entityItem.getItem() ); + for( ItemEntity entityItem : dropped ) handleDrops( entityItem.getItem() ); } } } @@ -101,8 +101,8 @@ public final class DropConsumer // Capture any mob drops for the current entity if( dropEntity != null && event.getEntity() == dropEntity.get() ) { - Collection drops = event.getDrops(); - for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() ); + Collection drops = event.getDrops(); + for( ItemEntity entityItem : drops ) handleDrops( entityItem.getItem() ); drops.clear(); } } @@ -126,10 +126,10 @@ public final class DropConsumer public static void onEntitySpawn( EntityJoinWorldEvent event ) { // Capture any nearby item spawns - if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem + if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof ItemEntity && dropBounds.contains( event.getEntity().getPositionVector() ) ) { - handleDrops( ((EntityItem) event.getEntity()).getItem() ); + handleDrops( ((ItemEntity) event.getEntity()).getItem() ); event.setCanceled( true ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index fa388a76f..1c12f20cc 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -43,7 +43,7 @@ public final class IDAssigner public static File getDir() { MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).getSaveHandler().getWorldDirectory(); + File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).func_217485_w().getWorldDirectory(); // getSaveHandler return new File( worldDirectory, ComputerCraft.MOD_ID ); } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index dd4d0d86e..8a582f341 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -7,15 +7,13 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonObject; -import dan200.computercraft.ComputerCraft; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.item.crafting.RecipeSerializers; import net.minecraft.item.crafting.ShapedRecipe; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.JsonUtils; +import net.minecraft.util.JSONUtils; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; @@ -41,14 +39,14 @@ public final class ImpostorRecipe extends ShapedRecipe } @Override - public boolean matches( @Nonnull IInventory inv, World world ) + public boolean matches( @Nonnull CraftingInventory inv, World world ) { return false; } @Nonnull @Override - public ItemStack getCraftingResult( @Nonnull IInventory inventory ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory ) { return ItemStack.EMPTY; } @@ -60,15 +58,14 @@ public final class ImpostorRecipe extends ShapedRecipe return SERIALIZER; } - private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ); public static final IRecipeSerializer SERIALIZER = new IRecipeSerializer() { @Override public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { - String group = JsonUtils.getString( json, "group", "" ); - ShapedRecipe recipe = RecipeSerializers.CRAFTING_SHAPED.read( identifier, json ); - ItemStack result = CraftingHelper.getItemStack( JsonUtils.getJsonObject( json, "result" ), true ); + String group = JSONUtils.getString( json, "group", "" ); + ShapedRecipe recipe = IRecipeSerializer.field_222157_a.read( identifier, json ); + ItemStack result = CraftingHelper.getItemStack( JSONUtils.getJsonObject( json, "result" ), true ); return new ImpostorRecipe( identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result ); } @@ -93,12 +90,5 @@ public final class ImpostorRecipe extends ShapedRecipe for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buf ); buf.writeItemStack( recipe.getRecipeOutput() ); } - - @Nonnull - @Override - public ResourceLocation getName() - { - return ID; - } }; } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index 889ed2869..779f7e470 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -9,14 +9,13 @@ package dan200.computercraft.shared.util; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; -import dan200.computercraft.ComputerCraft; -import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.CraftingInventory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.ShapelessRecipe; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.JsonUtils; +import net.minecraft.util.JSONUtils; import net.minecraft.util.NonNullList; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; @@ -42,14 +41,14 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe } @Override - public boolean matches( IInventory inv, World world ) + public boolean matches( CraftingInventory inv, World world ) { return false; } @Nonnull @Override - public ItemStack getCraftingResult( IInventory inventory ) + public ItemStack getCraftingResult( CraftingInventory inventory ) { return ItemStack.EMPTY; } @@ -61,15 +60,13 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe return SERIALIZER; } - private static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ); - public static final IRecipeSerializer SERIALIZER = new IRecipeSerializer() { @Override public ImpostorShapelessRecipe read( @Nonnull ResourceLocation id, @Nonnull JsonObject json ) { - String s = JsonUtils.getString( json, "group", "" ); - NonNullList ingredients = readIngredients( JsonUtils.getJsonArray( json, "ingredients" ) ); + String s = JSONUtils.getString( json, "group", "" ); + NonNullList ingredients = readIngredients( JSONUtils.getJsonArray( json, "ingredients" ) ); if( ingredients.isEmpty() ) throw new JsonParseException( "No ingredients for shapeless recipe" ); if( ingredients.size() > 9 ) @@ -77,7 +74,7 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe throw new JsonParseException( "Too many ingredients for shapeless recipe the max is 9" ); } - ItemStack itemstack = CraftingHelper.getItemStack( JsonUtils.getJsonObject( json, "result" ), true ); + ItemStack itemstack = CraftingHelper.getItemStack( JSONUtils.getJsonObject( json, "result" ), true ); return new ImpostorShapelessRecipe( id, s, itemstack, ingredients ); } @@ -115,12 +112,5 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buffer ); buffer.writeItemStack( recipe.getRecipeOutput() ); } - - @Nonnull - @Override - public ResourceLocation getName() - { - return ID; - } }; } diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index d67223e24..3cd4d006e 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -10,9 +10,9 @@ import net.minecraft.entity.Entity; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -62,8 +62,8 @@ public final class InventoryUtil // A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a // null one. - NBTTagCompound shareTagA = a.getItem().getShareTag( a ); - NBTTagCompound shareTagB = b.getItem().getShareTag( b ); + CompoundNBT shareTagA = a.getItem().getShareTag( a ); + CompoundNBT shareTagB = b.getItem().getShareTag( b ); if( shareTagA == shareTagB ) return true; if( shareTagA == null ) return shareTagB.isEmpty(); if( shareTagB == null ) return shareTagA.isEmpty(); @@ -78,7 +78,7 @@ public final class InventoryUtil // Methods for finding inventories: - public static IItemHandler getInventory( World world, BlockPos pos, EnumFacing side ) + public static IItemHandler getInventory( World world, BlockPos pos, Direction side ) { // Look for tile with inventory TileEntity tileEntity = world.getTileEntity( pos ); @@ -105,7 +105,7 @@ public final class InventoryUtil pos.getY() + 0.5 + 0.6 * side.getYOffset(), pos.getZ() + 0.5 + 0.6 * side.getZOffset() ); - EnumFacing dir = side.getOpposite(); + Direction dir = side.getOpposite(); Vec3d vecDir = new Vec3d( dir.getXOffset(), dir.getYOffset(), dir.getZOffset() ); diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 9a115002b..7dfbbb540 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -18,21 +18,21 @@ public final class NBTUtil { private NBTUtil() {} - private static INBTBase toNBTTag( Object object ) + private static INBT toNBTTag( Object object ) { if( object == null ) return null; - if( object instanceof Boolean ) return new NBTTagByte( (byte) ((boolean) (Boolean) object ? 1 : 0) ); - if( object instanceof Number ) return new NBTTagDouble( ((Number) object).doubleValue() ); - if( object instanceof String ) return new NBTTagString( object.toString() ); + if( object instanceof Boolean ) return new ByteNBT( (byte) ((boolean) (Boolean) object ? 1 : 0) ); + if( object instanceof Number ) return new DoubleNBT( ((Number) object).doubleValue() ); + if( object instanceof String ) return new StringNBT( object.toString() ); if( object instanceof Map ) { Map m = (Map) object; - NBTTagCompound nbt = new NBTTagCompound(); + CompoundNBT nbt = new CompoundNBT(); int i = 0; for( Map.Entry entry : m.entrySet() ) { - INBTBase key = toNBTTag( entry.getKey() ); - INBTBase value = toNBTTag( entry.getKey() ); + INBT key = toNBTTag( entry.getKey() ); + INBT value = toNBTTag( entry.getKey() ); if( key != null && value != null ) { nbt.put( "k" + i, key ); @@ -47,35 +47,35 @@ public final class NBTUtil return null; } - public static NBTTagCompound encodeObjects( Object[] objects ) + public static CompoundNBT encodeObjects( Object[] objects ) { if( objects == null || objects.length <= 0 ) return null; - NBTTagCompound nbt = new NBTTagCompound(); + CompoundNBT nbt = new CompoundNBT(); nbt.putInt( "len", objects.length ); for( int i = 0; i < objects.length; i++ ) { - INBTBase child = toNBTTag( objects[i] ); + INBT child = toNBTTag( objects[i] ); if( child != null ) nbt.put( Integer.toString( i ), child ); } return nbt; } - private static Object fromNBTTag( INBTBase tag ) + private static Object fromNBTTag( INBT tag ) { if( tag == null ) return null; switch( tag.getId() ) { case TAG_BYTE: - return ((NBTTagByte) tag).getByte() > 0; + return ((ByteNBT) tag).getByte() > 0; case TAG_DOUBLE: - return ((NBTTagDouble) tag).getDouble(); + return ((DoubleNBT) tag).getDouble(); default: case TAG_STRING: return tag.getString(); case TAG_COMPOUND: { - NBTTagCompound c = (NBTTagCompound) tag; + CompoundNBT c = (CompoundNBT) tag; int len = c.getInt( "len" ); Map map = new HashMap<>( len ); for( int i = 0; i < len; i++ ) @@ -89,7 +89,7 @@ public final class NBTUtil } } - public static Object toLua( INBTBase tag ) + public static Object toLua( INBT tag ) { if( tag == null ) return null; @@ -100,15 +100,15 @@ public final class NBTUtil case Constants.NBT.TAG_SHORT: case Constants.NBT.TAG_INT: case Constants.NBT.TAG_LONG: - return ((NBTPrimitive) tag).getLong(); + return ((NumberNBT) tag).getLong(); case Constants.NBT.TAG_FLOAT: case Constants.NBT.TAG_DOUBLE: - return ((NBTPrimitive) tag).getDouble(); + return ((NumberNBT) tag).getDouble(); case Constants.NBT.TAG_STRING: // String return tag.getString(); case Constants.NBT.TAG_COMPOUND: // Compound { - NBTTagCompound compound = (NBTTagCompound) tag; + CompoundNBT compound = (CompoundNBT) tag; Map map = new HashMap<>( compound.size() ); for( String key : compound.keySet() ) { @@ -119,21 +119,21 @@ public final class NBTUtil } case Constants.NBT.TAG_LIST: { - NBTTagList list = (NBTTagList) tag; + ListNBT list = (ListNBT) tag; Map map = new HashMap<>( list.size() ); for( int i = 0; i < list.size(); i++ ) map.put( i, toLua( list.get( i ) ) ); return map; } case Constants.NBT.TAG_BYTE_ARRAY: { - byte[] array = ((NBTTagByteArray) tag).getByteArray(); + byte[] array = ((ByteArrayNBT) tag).getByteArray(); Map map = new HashMap<>( array.length ); for( int i = 0; i < array.length; i++ ) map.put( i + 1, array[i] ); return map; } case Constants.NBT.TAG_INT_ARRAY: { - int[] array = ((NBTTagIntArray) tag).getIntArray(); + int[] array = ((IntArrayNBT) tag).getIntArray(); Map map = new HashMap<>( array.length ); for( int i = 0; i < array.length; i++ ) map.put( i + 1, array[i] ); return map; @@ -144,7 +144,7 @@ public final class NBTUtil } } - public static Object[] decodeObjects( NBTTagCompound tag ) + public static Object[] decodeObjects( CompoundNBT tag ) { int len = tag.getInt( "len" ); if( len <= 0 ) return null; diff --git a/src/main/java/dan200/computercraft/shared/util/NamedBlockEntityType.java b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java similarity index 58% rename from src/main/java/dan200/computercraft/shared/util/NamedBlockEntityType.java rename to src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java index db4c0caad..42f292495 100644 --- a/src/main/java/dan200/computercraft/shared/util/NamedBlockEntityType.java +++ b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java @@ -9,6 +9,7 @@ package dan200.computercraft.shared.util; import com.mojang.datafixers.DataFixUtils; import com.mojang.datafixers.types.Type; import dan200.computercraft.ComputerCraft; +import net.minecraft.block.Block; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; @@ -16,36 +17,52 @@ import net.minecraft.util.SharedConstants; import net.minecraft.util.datafix.DataFixesManager; import net.minecraft.util.datafix.TypeReferences; +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Objects; import java.util.function.Function; import java.util.function.Supplier; -public final class NamedBlockEntityType extends TileEntityType +public final class NamedTileEntityType extends TileEntityType { private final ResourceLocation identifier; + private Block block; - private NamedBlockEntityType( ResourceLocation identifier, Supplier supplier ) + private NamedTileEntityType( ResourceLocation identifier, Supplier supplier ) { - super( supplier, getDatafixer( identifier ) ); + super( supplier, Collections.emptySet(), getDatafixer( identifier ) ); this.identifier = identifier; setRegistryName( identifier ); } - public static NamedBlockEntityType create( ResourceLocation identifier, Supplier supplier ) + public static NamedTileEntityType create( ResourceLocation identifier, Supplier supplier ) { - return new NamedBlockEntityType<>( identifier, supplier ); + return new NamedTileEntityType<>( identifier, supplier ); } - public static NamedBlockEntityType create( ResourceLocation identifier, Function, ? extends T> builder ) + public static NamedTileEntityType create( ResourceLocation identifier, Function, ? extends T> builder ) { return new FixedPointSupplier<>( identifier, builder ).factory; } + public void setBlock( @Nonnull Block block ) + { + if( this.block != null ) throw new IllegalStateException( "Cannot change block once set" ); + this.block = Objects.requireNonNull( block, "block cannot be null" ); + } + + @Override + public boolean isValidBlock( @Nonnull Block block ) + { + return block == this.block; + } + public ResourceLocation getId() { return identifier; } - public static Type getDatafixer( ResourceLocation id ) + private static Type getDatafixer( ResourceLocation id ) { try { @@ -63,10 +80,10 @@ public final class NamedBlockEntityType extends TileEntity private static final class FixedPointSupplier implements Supplier { - final NamedBlockEntityType factory; - private final Function, ? extends T> builder; + final NamedTileEntityType factory; + private final Function, ? extends T> builder; - private FixedPointSupplier( ResourceLocation identifier, Function, ? extends T> builder ) + private FixedPointSupplier( ResourceLocation identifier, Function, ? extends T> builder ) { factory = create( identifier, this ); this.builder = builder; diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index 3174a2d0b..16f474d4e 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -6,7 +6,7 @@ package dan200.computercraft.shared.util; -import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.CompoundNBT; public class Palette { @@ -79,7 +79,7 @@ public class Palette }; } - public NBTTagCompound writeToNBT( NBTTagCompound nbt ) + public CompoundNBT writeToNBT( CompoundNBT nbt ) { int[] rgb8 = new int[colours.length]; @@ -92,7 +92,7 @@ public class Palette return nbt; } - public void readFromNBT( NBTTagCompound nbt ) + public void readFromNBT( CompoundNBT nbt ) { if( !nbt.contains( "term_palette" ) ) return; int[] rgb8 = nbt.getIntArray( "term_palette" ); diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index 332c9e161..7e4568cec 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -11,7 +11,7 @@ import com.google.common.collect.Sets; import com.google.gson.*; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.item.crafting.Ingredient; -import net.minecraft.util.JsonUtils; +import net.minecraft.util.JSONUtils; import net.minecraft.util.NonNullList; import java.util.Map; @@ -40,7 +40,7 @@ public final class RecipeUtil public static ShapedTemplate getTemplate( JsonObject json ) { Map ingMap = Maps.newHashMap(); - for( Map.Entry entry : JsonUtils.getJsonObject( json, "key" ).entrySet() ) + for( Map.Entry entry : JSONUtils.getJsonObject( json, "key" ).entrySet() ) { if( entry.getKey().length() != 1 ) { @@ -56,7 +56,7 @@ public final class RecipeUtil ingMap.put( ' ', Ingredient.EMPTY ); - JsonArray patternJ = JsonUtils.getJsonArray( json, "pattern" ); + JsonArray patternJ = JSONUtils.getJsonArray( json, "pattern" ); if( patternJ.size() == 0 ) { @@ -66,7 +66,7 @@ public final class RecipeUtil String[] pattern = new String[patternJ.size()]; for( int x = 0; x < pattern.length; x++ ) { - String line = JsonUtils.getString( patternJ.get( x ), "pattern[" + x + "]" ); + String line = JSONUtils.getString( patternJ.get( x ), "pattern[" + x + "]" ); if( x > 0 && pattern[0].length() != line.length() ) { throw new JsonSyntaxException( "Invalid pattern: each row must be the same width" ); @@ -107,7 +107,7 @@ public final class RecipeUtil public static NonNullList getIngredients( JsonObject json ) { NonNullList ingredients = NonNullList.create(); - for( JsonElement ele : JsonUtils.getJsonArray( json, "ingredients" ) ) + for( JsonElement ele : JSONUtils.getJsonArray( json, "ingredients" ) ) { ingredients.add( Ingredient.deserialize( ele ) ); } @@ -118,7 +118,7 @@ public final class RecipeUtil public static ComputerFamily getFamily( JsonObject json, String name ) { - String familyName = JsonUtils.getString( json, name ); + String familyName = JSONUtils.getString( json, name ); try { return ComputerFamily.valueOf( familyName ); diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index f5ff089e9..ba04109ce 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -10,12 +10,12 @@ import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.PlayRecordClientMessage; import net.minecraft.item.Item; -import net.minecraft.item.ItemRecord; import net.minecraft.item.ItemStack; +import net.minecraft.item.MusicDiscItem; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -33,8 +33,8 @@ public final class RecordUtil public static String getRecordInfo( @Nonnull ItemStack recordStack ) { Item item = recordStack.getItem(); - if( !(item instanceof ItemRecord) ) return null; + if( !(item instanceof MusicDiscItem) ) return null; - return new TextComponentTranslation( item.getTranslationKey() + ".desc" ).getString(); + return new TranslationTextComponent( item.getTranslationKey() + ".desc" ).getString(); } } diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java index 86ed53269..66c7a092f 100644 --- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.util; -import net.minecraft.block.state.IBlockState; -import net.minecraft.util.EnumFacing; +import net.minecraft.block.BlockState; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.ForgeEventFactory; @@ -16,10 +16,10 @@ import java.util.EnumSet; public final class RedstoneUtil { - public static void propagateRedstoneOutput( World world, BlockPos pos, EnumFacing side ) + public static void propagateRedstoneOutput( World world, BlockPos pos, Direction side ) { // Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors - IBlockState block = world.getBlockState( pos ); + BlockState block = world.getBlockState( pos ); if( ForgeEventFactory.onNeighborNotify( world, pos, block, EnumSet.of( side ), false ).isCanceled() ) return; BlockPos neighbourPos = pos.offset( side ); diff --git a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java new file mode 100644 index 000000000..8d4b4c3a4 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java @@ -0,0 +1,33 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.util.IIntArray; + +@FunctionalInterface +public interface SingleIntArray extends IIntArray +{ + int get(); + + @Override + default int func_221476_a( int property ) + { + return property == 0 ? get() : 0; + } + + @Override + default void func_221477_a( int i, int i1 ) + { + + } + + @Override + default int func_221478_a() + { + return 1; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index eaed69114..f890b34e4 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.util; import net.minecraft.inventory.IInventory; -import net.minecraft.inventory.Slot; +import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; public class ValidatingSlot extends Slot diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java deleted file mode 100644 index 4c0f593c5..000000000 --- a/src/main/java/dan200/computercraft/shared/util/WaterloggableBlock.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.util; - -import net.minecraft.block.IBucketPickupHandler; -import net.minecraft.block.ILiquidContainer; -import net.minecraft.block.state.IBlockState; -import net.minecraft.fluid.Fluid; -import net.minecraft.fluid.IFluidState; -import net.minecraft.init.Fluids; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.BooleanProperty; -import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorld; - -import javax.annotation.Nonnull; - -/** - * Represents a block which can be filled with water - * - * I'm fairly sure this exists on 1.14, but it's a useful convenience wrapper to have on 1.13. - */ -public interface WaterloggableBlock extends IBucketPickupHandler, ILiquidContainer -{ - BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; - - /** - * Call from {@link net.minecraft.block.Block#getFluidState(IBlockState)} - * - * @param state The current state - * @return This waterlogged block's current fluid - */ - default IFluidState getWaterloggedFluidState( IBlockState state ) - { - return state.get( WATERLOGGED ) ? Fluids.WATER.getStillFluidState( false ) : Fluids.EMPTY.getDefaultState(); - } - - @Nonnull - @Override - default Fluid pickupFluid( @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull IBlockState state ) - { - if( state.get( WATERLOGGED ) ) - { - world.setBlockState( pos, state.with( WATERLOGGED, false ), 3 ); - return Fluids.WATER; - } - else - { - return Fluids.EMPTY; - } - } - - @Override - default boolean canContainFluid( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Fluid fluid ) - { - return !state.get( WATERLOGGED ) && fluid == Fluids.WATER; - } - - @Override - default boolean receiveFluid( @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull IFluidState fluid ) - { - if( !canContainFluid( world, pos, state, fluid.getFluid() ) ) return false; - - if( !world.isRemote() ) - { - world.setBlockState( pos, state.with( WATERLOGGED, true ), 3 ); - world.getPendingFluidTicks().scheduleTick( pos, fluid.getFluid(), fluid.getFluid().getTickRate( world ) ); - } - - return true; - } - - /** - * Call from {@link net.minecraft.block.Block#updatePostPlacement(IBlockState, EnumFacing, IBlockState, IWorld, BlockPos, BlockPos)} - * - * @param state The current state - * @param world The position of this block - * @param pos The world this block exists in - */ - default void updateWaterloggedPostPlacement( IBlockState state, IWorld world, BlockPos pos ) - { - if( state.get( WATERLOGGED ) ) - { - world.getPendingFluidTicks().scheduleTick( pos, Fluids.WATER, Fluids.WATER.getTickRate( world ) ); - } - } - - default boolean getWaterloggedStateForPlacement( BlockItemUseContext context ) - { - return context.getWorld().getFluidState( context.getPos() ).getFluid() == Fluids.WATER; - } -} diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java new file mode 100644 index 000000000..71770017b --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java @@ -0,0 +1,62 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.block.BlockState; +import net.minecraft.fluid.Fluids; +import net.minecraft.fluid.IFluidState; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.BooleanProperty; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; + +/** + * Represents a block which can be filled with water + * + * I'm fairly sure this exists on 1.14, but it's a useful convenience wrapper to have on 1.13. + */ +public final class WaterloggableHelpers +{ + public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; + + private WaterloggableHelpers() + { + } + + /** + * Call from {@link net.minecraft.block.Block#getFluidState(BlockState)} + * + * @param state The current state + * @return This waterlogged block's current fluid + */ + public static IFluidState getWaterloggedFluidState( BlockState state ) + { + return state.get( WATERLOGGED ) ? Fluids.WATER.getStillFluidState( false ) : Fluids.EMPTY.getDefaultState(); + } + + /** + * Call from {@link net.minecraft.block.Block#updatePostPlacement(BlockState, Direction, BlockState, IWorld, BlockPos, BlockPos)} + * + * @param state The current state + * @param world The position of this block + * @param pos The world this block exists in + */ + public static void updateWaterloggedPostPlacement( BlockState state, IWorld world, BlockPos pos ) + { + if( state.get( WATERLOGGED ) ) + { + world.getPendingFluidTicks().scheduleTick( pos, Fluids.WATER, Fluids.WATER.getTickRate( world ) ); + } + } + + public static boolean getWaterloggedStateForPlacement( BlockItemUseContext context ) + { + return context.getWorld().getFluidState( context.getPos() ).getFluid() == Fluids.WATER; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index cc1cac870..b37c1534a 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -7,17 +7,13 @@ package dan200.computercraft.shared.util; import com.google.common.base.Predicate; -import net.minecraft.block.state.IBlockState; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityLivingBase; -import net.minecraft.entity.item.EntityItem; -import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.block.BlockState; +import net.minecraft.entity.*; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.Direction; +import net.minecraft.util.math.*; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; import org.apache.commons.lang3.tuple.Pair; @@ -30,10 +26,25 @@ public final class WorldUtil @SuppressWarnings( "Guava" ) private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.canBeCollidedWith(); + private static final Entity ENTITY = new ItemEntity( EntityType.ITEM, null ) + { + @Override + public EntitySize getSize( Pose pose ) + { + return EntitySize.fixed( 0, 0 ); + } + }; + + static + { + ENTITY.noClip = true; + ENTITY.recalculateSize(); + } + public static boolean isLiquidBlock( World world, BlockPos pos ) { if( !World.isValid( pos ) ) return false; - IBlockState state = world.getBlockState( pos ); + BlockState state = world.getBlockState( pos ); return !state.getFluidState().isEmpty(); } @@ -50,10 +61,12 @@ public final class WorldUtil Vec3d vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); // Raycast for blocks - RayTraceResult result = world.rayTraceBlocks( vecStart, vecEnd ); - if( result != null && result.type == RayTraceResult.Type.BLOCK ) + ENTITY.setPosition( vecStart.x, vecStart.y, vecStart.z ); + RayTraceContext context = new RayTraceContext( vecStart, vecEnd, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, ENTITY ); + RayTraceResult result = world.func_217299_a( context ); + if( result != null && result.getType() == RayTraceResult.Type.BLOCK ) { - distance = vecStart.distanceTo( result.hitVec ); + distance = vecStart.distanceTo( result.getHitVec() ); vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); } @@ -76,15 +89,6 @@ public final class WorldUtil for( Entity entity : list ) { AxisAlignedBB littleBox = entity.getBoundingBox(); - if( littleBox == null ) - { - littleBox = entity.getCollisionBoundingBox(); - if( littleBox == null ) - { - continue; - } - } - if( littleBox.contains( vecStart ) ) { closest = entity; @@ -92,10 +96,10 @@ public final class WorldUtil continue; } - RayTraceResult littleBoxResult = littleBox.calculateIntercept( vecStart, vecEnd ); + Vec3d littleBoxResult = littleBox.func_216365_b( vecStart, vecEnd ).orElse( null ); // rayTrace if( littleBoxResult != null ) { - double dist = vecStart.distanceTo( littleBoxResult.hitVec ); + double dist = vecStart.distanceTo( littleBoxResult ); if( closest == null || dist <= closestDist ) { closest = entity; @@ -119,14 +123,14 @@ public final class WorldUtil return null; } - public static Vec3d getRayStart( EntityLivingBase entity ) + public static Vec3d getRayStart( LivingEntity entity ) { return entity.getEyePosition( 1 ); } - public static Vec3d getRayEnd( EntityPlayer player ) + public static Vec3d getRayEnd( PlayerEntity player ) { - double reach = player.getAttribute( EntityPlayer.REACH_DISTANCE ).getValue(); + double reach = player.getAttribute( PlayerEntity.REACH_DISTANCE ).getValue(); Vec3d look = player.getLookVec(); return getRayStart( player ).add( look.x * reach, look.y * reach, look.z * reach ); } @@ -136,7 +140,7 @@ public final class WorldUtil dropItemStack( stack, world, pos, null ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, BlockPos pos, EnumFacing direction ) + public static void dropItemStack( @Nonnull ItemStack stack, World world, BlockPos pos, Direction direction ) { double xDir; double yDir; @@ -167,11 +171,13 @@ public final class WorldUtil public static void dropItemStack( @Nonnull ItemStack stack, World world, double xPos, double yPos, double zPos, double xDir, double yDir, double zDir ) { - EntityItem item = new EntityItem( world, xPos, yPos, zPos, stack.copy() ); - item.motionX = xDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1; - item.motionY = yDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1; - item.motionZ = zDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1; + ItemEntity item = new ItemEntity( world, xPos, yPos, zPos, stack.copy() ); + item.setVelocity( + xDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1, + yDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1, + zDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1 + ); item.setDefaultPickupDelay(); - world.spawnEntity( item ); + world.func_217376_c( item ); } } diff --git a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java index d484f94bb..deadafe09 100644 --- a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java +++ b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java @@ -8,8 +8,8 @@ package dan200.computercraft.shared.wired; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; -import net.minecraft.nbt.INBTBase; -import net.minecraft.util.EnumFacing; +import net.minecraft.nbt.INBT; +import net.minecraft.util.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; @@ -66,13 +66,13 @@ public final class CapabilityWiredElement private static class NullStorage implements Capability.IStorage { @Override - public INBTBase writeNBT( Capability capability, IWiredElement instance, EnumFacing side ) + public INBT writeNBT( Capability capability, IWiredElement instance, Direction side ) { return null; } @Override - public void readNBT( Capability capability, IWiredElement instance, EnumFacing side, INBTBase base ) + public void readNBT( Capability capability, IWiredElement instance, Direction side, INBT base ) { } } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 83b686667..ab5165580 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,5 +1,10 @@ # ItemPocketRenderer/ItemPrintoutRenderer public net.minecraft.client.renderer.FirstPersonRenderer func_187466_c()V # renderArms public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch -public net.minecraft.client.renderer.FirstPersonRenderer func_187456_a(FFLnet/minecraft/util/EnumHandSide;)V # renderArmFirstPerson +public net.minecraft.client.renderer.FirstPersonRenderer func_187456_a(FFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson +# Containers +public net.minecraft.inventory.container.ContainerType$IFactory +public net.minecraft.inventory.container.ContainerType (Lnet/minecraft/inventory/container/ContainerType$IFactory;)V +public net.minecraft.client.gui.ScreenManager$IScreenFactory +public net.minecraft.client.gui.ScreenManager func_216911_a(Lnet/minecraft/inventory/container/ContainerType;Lnet/minecraft/client/gui/ScreenManager$IScreenFactory;)V # registerFactory diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index f9d4254ed..ff246ba74 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[25,)" +loaderVersion="[26,)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[25,)" + versionRange="[26,)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json index 8b01925bb..a27ee37c6 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:ink_sac" } + { "item": "minecraft:black_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 1118481 } } } diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json index 7920fc6dd..505066e7a 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:dandelion_yellow" } + { "item": "minecraft:yellow_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 14605932 } } } diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json index c3c6f193d..2fa82adad 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:bone_meal" } + { "item": "minecraft:white_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 15790320 } } } diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json index 53f78a99a..21ab48568 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:rose_red" } + { "item": "minecraft:red_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 13388876 } } } diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json index 452e4c348..a164af6cb 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:cactus_green" } + { "item": "minecraft:green_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 5744206 } } } diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json index 457bba1ed..7109021e3 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:cocoa_beans" } + { "item": "minecraft:brown_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 8349260 } } } diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json index 94520e185..538f14349 100644 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json +++ b/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json @@ -4,7 +4,7 @@ "ingredients": [ { "tag": "forge:dusts/redstone" }, { "item": "minecraft:paper" }, - { "item": "minecraft:lapis_lazuli" } + { "item": "minecraft:blue_dye" } ], "result": { "item": "computercraft:disk", "nbt": { "color": 3368652 } } } diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 2e35df025..880b3c4e9 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -18,7 +18,7 @@ import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.util.EnumFacing; +import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -261,7 +261,7 @@ public class NetworkTest long start = System.nanoTime(); grid.forEach( ( existing, pos ) -> { - for( EnumFacing facing : DirectionUtil.FACINGS ) + for( Direction facing : DirectionUtil.FACINGS ) { BlockPos offset = pos.offset( facing ); if( offset.getX() > BRUTE_SIZE / 2 == pos.getX() > BRUTE_SIZE / 2 ) diff --git a/tools/recipes.lua b/tools/recipes.lua index 53c619f45..d2c007523 100644 --- a/tools/recipes.lua +++ b/tools/recipes.lua @@ -30,22 +30,22 @@ local pocket_upgrades = { --- All dye/disk colours local colours = { - { 0x111111, "minecraft:ink_sac" }, - { 0xcc4c4c, "minecraft:rose_red" }, - { 0x57A64E, "minecraft:cactus_green" }, - { 0x7f664c, "minecraft:cocoa_beans" }, - { 0x3366cc, "minecraft:lapis_lazuli" }, + { 0x111111, "minecraft:black_dye" }, + { 0xcc4c4c, "minecraft:red_dye" }, + { 0x57A64E, "minecraft:green_dye" }, + { 0x7f664c, "minecraft:brown_dye" }, + { 0x3366cc, "minecraft:blue_dye" }, { 0xb266e5, "minecraft:purple_dye" }, { 0x4c99b2, "minecraft:cyan_dye" }, { 0x999999, "minecraft:light_gray_dye" }, { 0x4c4c4c, "minecraft:gray_dye" }, { 0xf2b2cc, "minecraft:pink_dye" }, { 0x7fcc19, "minecraft:lime_dye" }, - { 0xdede6c, "minecraft:dandelion_yellow" }, + { 0xdede6c, "minecraft:yellow_dye" }, { 0x99b2f2, "minecraft:light_blue_dye" }, { 0xe57fd8, "minecraft:magenta_dye" }, { 0xf2b233, "minecraft:orange_dye" }, - { 0xf0f0f0, "minecraft:bone_meal" }, + { 0xf0f0f0, "minecraft:white_dye" }, } --- Read the provided file into a string, exiting the program if not found. From 309cbdb8be2ee9a616b1fd8dd474d366987432ce Mon Sep 17 00:00:00 2001 From: JakobDev Date: Sat, 8 Jun 2019 15:49:42 +0200 Subject: [PATCH 009/711] Add `wget run` (#218) Equivalent to `pastebin run`, but allows running arbitrary URLs instead. Is this a little questionable? Yes - people shouldn't be downloading and running code from the internet. But hey, people do that already, so we might as well make it convenient. --- .../computercraft/lua/rom/help/wget.txt | 1 + .../assets/computercraft/lua/rom/motd.txt | 4 +- .../lua/rom/programs/http/wget.lua | 58 +++++++++++++------ .../assets/computercraft/lua/rom/startup.lua | 7 +++ .../test-rom/spec/http/wget_spec.lua | 53 +++++++++++++++++ 5 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 src/test/resources/test-rom/spec/http/wget_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/help/wget.txt b/src/main/resources/assets/computercraft/lua/rom/help/wget.txt index 428ed5bab..65e580c08 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/wget.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/wget.txt @@ -5,3 +5,4 @@ ex: "wget http://pastebin.com/raw/CxaWmPrX test" will download the file from the URL http://pastebin.com/raw/CxaWmPrX, and save it as "test". "wget http://example.org/test.lua/?foo=bar#qzu" will download the file from the URL http://example.org/test.lua/?foo=bar#qzu and save it as "test.lua" "wget http://example.org/" will download the file from the URL http://example.org and save it as "example.org" +"wget run http://pastebin.com/raw/CxaWmPrX" will download the file from the URL http://pastebin.com/raw/CxaWmPrX and run it immediately. diff --git a/src/main/resources/assets/computercraft/lua/rom/motd.txt b/src/main/resources/assets/computercraft/lua/rom/motd.txt index afb322c11..d81dc2fd0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/motd.txt +++ b/src/main/resources/assets/computercraft/lua/rom/motd.txt @@ -8,6 +8,8 @@ Run "list" or "ls" to see all files in a directory. You can delete files and directories with "delete" or "rm". Use "pastebin put" to upload a program to pastebin. Use "pastebin get" to download a program from pastebin. -Use "pastebin run" to run a program from pastebin without saving it. +Use "pastebin run" to run a program from pastebin. Use the "edit" program to create and edit your programs. You can copy files with "copy" or "cp". +You can use "wget run " to run a program from the internet. +You can use "wget" to download a file from the internet. diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua index 08063c640..e05def30e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua @@ -2,14 +2,24 @@ local function printUsage() print( "Usage:" ) print( "wget [filename]" ) + print( "wget run " ) end local tArgs = { ... } + +local run = false +if tArgs[1] == "run" then + table.remove( tArgs, 1 ) + run = true +end + if #tArgs < 1 then printUsage() return end +local url = table.remove( tArgs, 1 ) + if not http then printError( "wget requires http API" ) printError( "Set http_enable to true in ComputerCraft.cfg" ) @@ -22,6 +32,13 @@ local function getFilename( sUrl ) end local function get( sUrl ) + -- Check if the URL is valid + local ok, err = http.checkURL( url ) + if not ok then + printError( err or "Invalid URL." ) + return + end + write( "Connecting to " .. sUrl .. "... " ) local response = http.get( sUrl , nil , true ) @@ -37,29 +54,34 @@ local function get( sUrl ) return sResponse end --- Determine file to download -local sUrl = tArgs[1] +if run then + local res = get(url) + if not res then return end ---Check if the URL is valid -local ok, err = http.checkURL( sUrl ) -if not ok then - printError( err or "Invalid URL." ) - return -end + local func, err = load(res, getFilename(url), "t", _ENV) + if not func then + printError(err) + return + end -local sFile = tArgs[2] or getFilename( sUrl ) -local sPath = shell.resolve( sFile ) -if fs.exists( sPath ) then - print( "File already exists" ) - return -end + local ok, err = pcall(func, table.unpack(tArgs)) + if not ok then + printError( err ) + end +else + local sFile = tArgs[1] or getFilename( url ) + local sPath = shell.resolve( sFile ) + if fs.exists( sPath ) then + print( "File already exists" ) + return + end + + local res = get(url) + if not res then return end --- Do the get -local res = get( sUrl ) -if res then local file = fs.open( sPath, "wb" ) file.write( res ) file.close() - print( "Downloaded as "..sFile ) + print( "Downloaded as " .. sFile ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/startup.lua b/src/main/resources/assets/computercraft/lua/rom/startup.lua index 9f6d74ade..2bc19adca 100644 --- a/src/main/resources/assets/computercraft/lua/rom/startup.lua +++ b/src/main/resources/assets/computercraft/lua/rom/startup.lua @@ -183,6 +183,12 @@ local function completeExec( shell, nIndex, sText, tPreviousText ) return completeMultipleChoice( sText, tCommands, true ) end end +local tWgetOptions = { "run" } +local function completeWget( shell, nIndex, sText, tPreviousText ) + if nIndex == 1 then + return completeMultipleChoice( sText, tWgetOptions, true ) + end +end shell.setCompletionFunction( "rom/programs/alias.lua", completeAlias ) shell.setCompletionFunction( "rom/programs/cd.lua", completeDir ) shell.setCompletionFunction( "rom/programs/copy.lua", completeEitherEither ) @@ -210,6 +216,7 @@ shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completeFile shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completePastebin ) shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completeChat ) shell.setCompletionFunction( "rom/programs/command/exec.lua", completeExec ) +shell.setCompletionFunction( "rom/programs/http/wget.lua", completeWget ) if turtle then local tGoOptions = { "left", "right", "forward", "back", "down", "up" } diff --git a/src/test/resources/test-rom/spec/http/wget_spec.lua b/src/test/resources/test-rom/spec/http/wget_spec.lua new file mode 100644 index 000000000..b6b88b34b --- /dev/null +++ b/src/test/resources/test-rom/spec/http/wget_spec.lua @@ -0,0 +1,53 @@ +local capture = require "test_helpers".capture_program + +describe("The wget program", function() + local function setup_request() + stub(_G, "http", { + checkURL = function() + return true + end, + get = function() + return { + readAll = function() + return [[print("Hello", ...)]] + end, + close = function() + end, + } + end + }) + end + + it("downloads one file", function() + setup_request() + capture(stub, "wget", "https://example.com") + + expect(fs.exists("/example.com")):eq(true) + end) + + it("downloads one file with given filename", function() + setup_request() + capture(stub, "wget", "https://example.com /test-files/download") + + expect(fs.exists("/test-files/download")):eq(true) + end) + + it("runs a program from the internet", function() + setup_request() + + expect(capture(stub, "wget", "run", "http://test.com", "a", "b", "c")) + :matches { ok = true, output = "Connecting to http://test.com... Success.\nHello a b c\n", error = "" } + end) + + it("displays its usage when given no arguments", function() + setup_request() + + expect(capture(stub, "wget")) + :matches { ok = true, output = "Usage:\nwget [filename]\nwget run \n", error = "" } + end) + + it("can be completed", function() + local complete = shell.getCompletionInfo()["rom/programs/http/wget.lua"].fnComplete + expect(complete(shell, 1, "", {})):same { "run " } + end) +end) From 15d4a55cd83370fa735e647b4b90d5aa7aca868c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 9 Jun 2019 08:58:49 +0100 Subject: [PATCH 010/711] Bump mappings and Forge versions Things are shaping up nicely! --- gradle.properties | 4 +- .../client/ClientTableFormatter.java | 4 +- .../computercraft/client/gui/GuiComputer.java | 35 ++++++++++++-- .../client/gui/GuiPocketComputer.java | 36 --------------- .../computercraft/client/gui/GuiTurtle.java | 7 ++- .../proxy/ComputerCraftProxyClient.java | 18 +++++--- .../render/TileEntityTurtleRenderer.java | 2 +- .../core/filesystem/ResourceMount.java | 2 +- .../dan200/computercraft/shared/Registry.java | 24 ++++++++++ .../arguments/ArgumentSerializers.java | 4 +- .../shared/common/ColourableRecipe.java | 2 +- .../computer/blocks/BlockComputerBase.java | 2 +- .../computer/inventory/ContainerComputer.java | 12 ++++- .../client/PlayRecordClientMessage.java | 2 +- .../peripheral/diskdrive/TileDiskDrive.java | 2 +- .../peripheral/modem/wired/BlockCable.java | 6 +-- .../modem/wireless/BlockWirelessModem.java | 2 +- .../wireless/WirelessModemPeripheral.java | 2 +- .../peripheral/printer/ContainerPrinter.java | 4 +- .../peripheral/printer/TilePrinter.java | 1 - .../proxy/ComputerCraftProxyCommon.java | 30 ++++-------- .../shared/turtle/FurnaceRefuelHandler.java | 2 +- .../turtle/inventory/ContainerTurtle.java | 46 ++++++++++++------- .../upgrades/TurtleInventoryCrafting.java | 2 +- .../computercraft/shared/util/IDAssigner.java | 2 +- .../shared/util/ImpostorRecipe.java | 2 +- .../shared/util/SingleIntArray.java | 7 ++- .../computercraft/shared/util/WorldUtil.java | 6 +-- .../resources/META-INF/accesstransformer.cfg | 6 --- 29 files changed, 147 insertions(+), 127 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java diff --git a/gradle.properties b/gradle.properties index 75c81b3d1..3f0302f1b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.83.1 # Minecraft properties mc_version=1.14.2 -forge_version=26.0.5 -mappings_version=20190608-1.14.2 +forge_version=26.0.10 +mappings_version=20190609-1.14.2 diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 888bf6ad3..cb99d7d57 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -65,7 +65,7 @@ public class ClientTableFormatter implements TableFormatter public void writeLine( int id, ITextComponent component ) { Minecraft mc = Minecraft.getInstance(); - NewChatGui chat = mc.field_71456_v.getChatGUI(); // ingameGUI + NewChatGui chat = mc.ingameGUI.getChatGUI(); // Trim the text if it goes over the allowed length int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); @@ -76,7 +76,7 @@ public class ClientTableFormatter implements TableFormatter @Override public int display( TableBuilder table ) { - NewChatGui chat = Minecraft.getInstance().field_71456_v.getChatGUI(); + NewChatGui chat = Minecraft.getInstance().ingameGUI.getChatGUI(); int lastHeight = lastHeights.get( table.getId() ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index f23162d81..a95e6e31a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -10,14 +10,17 @@ import com.mojang.blaze3d.platform.GlStateManager; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; -import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; +import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; +import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; @@ -49,17 +52,39 @@ public class GuiComputer extends Conta terminal = null; } - public static GuiComputer create( int id, TileComputer computer, PlayerInventory inventory, ITextComponent component ) + public static GuiComputer create( ContainerComputer container, PlayerInventory inventory, ITextComponent component ) { return new GuiComputer<>( - new ContainerComputer( id, computer ), inventory, component, - computer.getFamily(), - computer.createClientComputer(), + container, inventory, component, + container.getFamily(), + (ClientComputer) container.getComputer(), ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); } + public static GuiComputer createPocket( ContainerPocketComputer container, PlayerInventory inventory, ITextComponent component ) + { + Item item = container.getStack().getItem(); + return new GuiComputer<>( + container, inventory, component, + item instanceof ItemPocketComputer ? ((ItemPocketComputer) item).getFamily() : ComputerFamily.Normal, + (ClientComputer) container.getComputer(), + ComputerCraft.terminalWidth_computer, + ComputerCraft.terminalHeight_computer + ); + } + + public static GuiComputer createView( ContainerViewComputer container, PlayerInventory inventory, ITextComponent component ) + { + return new GuiComputer<>( + container, inventory, component, + // TODO: Waiting to see how Forge handles this before implementing anything else. + null, (ClientComputer) container.getComputer(), 0, 0 + ); + } + + @Override protected void init() { diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java deleted file mode 100644 index a075e1d5f..000000000 --- a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.client.gui; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; -import dan200.computercraft.shared.pocket.items.ItemPocketComputer; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.util.text.ITextComponent; - -public class GuiPocketComputer extends GuiComputer -{ - public GuiPocketComputer( ContainerPocketComputer container, PlayerInventory player, ITextComponent title ) - { - super( - container, player, title, - getFamily( container.getStack() ), - ItemPocketComputer.createClientComputer( container.getStack() ), - ComputerCraft.terminalWidth_pocketComputer, - ComputerCraft.terminalHeight_pocketComputer - ); - } - - private static ComputerFamily getFamily( ItemStack stack ) - { - Item item = stack.getItem(); - return item instanceof ItemPocketComputer ? ((ItemPocketComputer) item).getFamily() : ComputerFamily.Normal; - } -} diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index cdbdd28b9..e285d9209 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -12,7 +12,6 @@ import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; @@ -32,13 +31,13 @@ public class GuiTurtle extends ContainerScreen private WidgetTerminal terminal; private WidgetWrapper terminalWrapper; - public GuiTurtle( TileTurtle turtle, ContainerTurtle container, PlayerInventory player, ITextComponent title ) + public GuiTurtle( ContainerTurtle container, PlayerInventory player, ITextComponent title ) { super( container, player, title ); m_container = container; - m_family = turtle.getFamily(); - m_computer = turtle.getClientComputer(); + m_family = null; // TODO + m_computer = (ClientComputer) container.getComputer(); xSize = 254; ySize = 217; diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 28f2affbc..c9ff620ad 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -7,14 +7,13 @@ package dan200.computercraft.client.proxy; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.client.gui.GuiDiskDrive; -import dan200.computercraft.client.gui.GuiPocketComputer; -import dan200.computercraft.client.gui.GuiPrinter; -import dan200.computercraft.client.gui.GuiPrintout; +import dan200.computercraft.client.gui.*; import dan200.computercraft.client.render.TileEntityCableRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.shared.common.ContainerHeldItem; +import dan200.computercraft.shared.computer.inventory.ContainerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.modem.wired.TileCable; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; @@ -22,6 +21,7 @@ import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.client.gui.ScreenManager; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.world.WorldEvent; @@ -46,11 +46,17 @@ public final class ComputerCraftProxyClient private static void registerContainers() { + // My IDE doesn't think so, but we do actually need these generics. + + ScreenManager.>registerFactory( ContainerComputer.TYPE, GuiComputer::create ); + ScreenManager.>registerFactory( ContainerPocketComputer.TYPE, GuiComputer::createPocket ); + ScreenManager.registerFactory( ContainerTurtle.TYPE, GuiTurtle::new ); + ScreenManager.registerFactory( ContainerPrinter.TYPE, GuiPrinter::new ); ScreenManager.registerFactory( ContainerDiskDrive.TYPE, GuiDiskDrive::new ); - ScreenManager.registerFactory( ContainerPocketComputer.TYPE, GuiPocketComputer::new ); ScreenManager.registerFactory( ContainerHeldItem.PRINTOUT_TYPE, GuiPrintout::new ); - // TODO: ScreenManager.registerFactory( ContainerViewComputer.TYPE, GuiComputer::new ); + + ScreenManager.>registerFactory( ContainerViewComputer.TYPE, GuiComputer::createView ); } @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index f7f77076b..4c6fe4de6 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -91,7 +91,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) ) { setLightmapDisabled( true ); - GameRenderer.func_215307_a( + GameRenderer.drawNameplate( getFontRenderer(), label, (float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, rendererDispatcher.field_217666_g.func_216778_f(), rendererDispatcher.field_217666_g.func_216777_e(), false diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index 433497ba2..81d71f9eb 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -267,7 +267,7 @@ public class ResourceMount implements IMount synchronized void add( IReloadableResourceManager manager, ResourceMount mount ) { - if( managers.add( manager ) ) manager.func_219534_a( this ); // addReloadListener + if( managers.add( manager ) ) manager.addReloadListener( this ); mounts.add( mount ); } } diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index 5786a543b..31512adc1 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -8,15 +8,19 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.inventory.ContainerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.items.ItemComputer; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemTreasureDisk; import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; +import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; import dan200.computercraft.shared.peripheral.modem.wired.*; import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem; @@ -24,21 +28,25 @@ import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem; import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.printer.BlockPrinter; +import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.peripheral.printer.TilePrinter; import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; import dan200.computercraft.shared.peripheral.speaker.TileSpeaker; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.upgrades.*; import dan200.computercraft.shared.util.CreativeTabMain; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityType; +import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; @@ -311,4 +319,20 @@ public final class Registry { registry.getRegistry().register( TurtlePlayer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" ) ) ); } + + @SubscribeEvent + public static void registerContainers( RegistryEvent.Register> event ) + { + event.getRegistry().registerAll( + ContainerComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ), + ContainerPocketComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer" ) ), + ContainerTurtle.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ), + + ContainerDiskDrive.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ) ), + ContainerPrinter.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ) ), + ContainerHeldItem.PRINTOUT_TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ), + + ContainerViewComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "view_computer" ) ) + ); + } } diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java index 20af81c37..85e99bdfa 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java @@ -18,12 +18,12 @@ public final class ArgumentSerializers @SuppressWarnings( "unchecked" ) private static > void registerUnsafe( ResourceLocation id, Class type, IArgumentSerializer serializer ) { - ArgumentTypes.func_218136_a( id.toString(), type, (IArgumentSerializer) serializer ); + ArgumentTypes.register( id.toString(), type, (IArgumentSerializer) serializer ); } private static > void register( ResourceLocation id, Class type, IArgumentSerializer serializer ) { - ArgumentTypes.func_218136_a( id.toString(), type, serializer ); + ArgumentTypes.register( id.toString(), type, serializer ); } private static > void register( ResourceLocation id, T instance ) diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index 738ff499a..e58aca821 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -20,7 +20,7 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; -public class ColourableRecipe extends SpecialRecipe +public final class ColourableRecipe extends SpecialRecipe { private ColourableRecipe( ResourceLocation id ) { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 0050377bd..fb738a8d4 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -148,7 +148,7 @@ public abstract class BlockComputerBase extends Bloc if( tile instanceof TileComputerBase ) { TileComputerBase computer = (TileComputerBase) tile; - if( !player.playerAbilities.isCreativeMode || computer.getLabel() != null ) + if( !player.abilities.isCreativeMode || computer.getLabel() != null ) { spawnAsEntity( world, pos, getItem( computer ) ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java index 28faa109d..c3ef181d5 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java @@ -7,23 +7,27 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.shared.computer.blocks.TileComputer; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ContainerComputer extends Container implements IContainerComputer { + public static final ContainerType TYPE = new ContainerType<>( ( id, player ) -> null ); + private final TileComputer computer; private final InputState input = new InputState( this ); public ContainerComputer( int id, TileComputer computer ) { - super( null, id ); + super( TYPE, id ); this.computer = computer; } @@ -33,6 +37,12 @@ public class ContainerComputer extends Container implements IContainerComputer return computer.isUsableByPlayer( player ); } + @Nonnull + public ComputerFamily getFamily() + { + return computer.getFamily(); + } + @Nullable @Override public IComputer getComputer() diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 822d6fe29..96351f3ef 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -83,6 +83,6 @@ public class PlayRecordClientMessage implements NetworkMessage { Minecraft mc = Minecraft.getInstance(); mc.worldRenderer.playRecord( soundEvent, pos ); - if( name != null ) mc.field_71456_v.setRecordPlayingMessage( name ); + if( name != null ) mc.ingameGUI.setRecordPlayingMessage( name ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 2eb317d78..43ae07488 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -504,7 +504,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory ItemEntity entityitem = new ItemEntity( getWorld(), x, y, z, disks ); entityitem.setVelocity( xOff * 0.15, 0, zOff * 0.15 ); - getWorld().func_217376_c( entityitem ); + getWorld().addEntity( entityitem ); if( !destroyed ) getWorld().playBroadcastSound( 1000, getPos(), 0 ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index e0f5d8e83..7b3d2b7cc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -105,7 +105,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable { if( state.get( CABLE ) && state.get( MODEM ).getFacing() != null ) { - BlockRayTraceResult hit = world.func_217299_a( new RayTraceContext( + BlockRayTraceResult hit = world.rayTraceBlocks( new RayTraceContext( WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ), RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player ) ); @@ -134,7 +134,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable cable.modemChanged(); cable.connectionsChanged(); - if( !world.isRemote && !player.playerAbilities.isCreativeMode ) + if( !world.isRemote && !player.abilities.isCreativeMode ) { Block.spawnAsEntity( world, pos, item ); } @@ -210,7 +210,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable BlockPos offsetPos = pos.offset( facing ); BlockState offsetState = world.getBlockState( offsetPos ); - return Block.func_220056_d( offsetState, world, offsetPos, facing.getOpposite() ); // hasSolidTop ?? + return Block.hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index d5f643868..c5ae80392 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -85,7 +85,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable Direction facing = state.get( FACING ); BlockPos offsetPos = pos.offset( facing ); BlockState offsetState = world.getBlockState( offsetPos ); - return func_220056_d( offsetState, world, offsetPos, facing.getOpposite() ); + return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index f924fb530..2ff323829 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -51,7 +51,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } if( position.y > 96.0 && maxRange > minRange ) { - return minRange + (position.y - 96.0) * ((maxRange - minRange) / ((world.func_217301_I() - 1) - 96.0)); + return minRange + (position.y - 96.0) * ((maxRange - minRange) / ((world.getHeight() - 1) - 96.0)); } return minRange; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index 9ae869156..93fb661dd 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -63,7 +63,7 @@ public class ContainerPrinter extends Container private ContainerPrinter( int id, PlayerInventory player ) { - this( id, player, new Inventory( TilePrinter.SLOTS ), new IntArray( TilePrinter.PROPERTIES ) ); + this( id, player, new Inventory( TilePrinter.SLOTS ), new IntArray( 1 ) ); } public ContainerPrinter( int id, PlayerInventory player, TilePrinter printer ) @@ -73,7 +73,7 @@ public class ContainerPrinter extends Container public boolean isPrinting() { - return properties.func_221476_a( 0 ) != 0; + return properties.get( 0 ) != 0; } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 16c99504c..b9feeea41 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -53,7 +53,6 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private static final String NBT_PAGE_TITLE = "PageTitle"; static final int SLOTS = 13; - static final int PROPERTIES = 1; private static final int[] BOTTOM_SLOTS = new int[] { 7, 8, 9, 10, 11, 12 }; private static final int[] TOP_SLOTS = new int[] { 1, 2, 3, 4, 5, 6 }; diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index cde8638db..65f1747d1 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -16,22 +16,17 @@ import dan200.computercraft.shared.Config; import dan200.computercraft.shared.command.CommandComputerCraft; import dan200.computercraft.shared.command.arguments.ArgumentSerializers; import dan200.computercraft.shared.common.ColourableRecipe; -import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.media.recipes.DiskRecipe; import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; -import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; -import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; -import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; @@ -44,7 +39,6 @@ import net.minecraft.item.MusicDiscItem; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.registry.Registry; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; @@ -66,21 +60,15 @@ public final class ComputerCraftProxyCommon registerProviders(); // Eww, eww, eww - can we move this to an event? - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":colour", ColourableRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":computer_upgrade", ComputerUpgradeRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":pocket_computer_upgrade", PocketComputerUpgradeRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":disk", DiskRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":printout", PrintoutRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":turtle", TurtleRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":turtle_upgrade", TurtleUpgradeRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":impostor_shapeless", ImpostorShapelessRecipe.SERIALIZER ); - IRecipeSerializer.func_222156_a( ComputerCraft.MOD_ID + ":impostor_shaped", ImpostorRecipe.SERIALIZER ); - - Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":printer", ContainerPrinter.TYPE ); - Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":disk_drive", ContainerDiskDrive.TYPE ); - Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":pocket_computer", ContainerPocketComputer.TYPE ); - Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":printout", ContainerHeldItem.PRINTOUT_TYPE ); - Registry.register( Registry.field_218366_G, ComputerCraft.MOD_ID + ":view_computer", ContainerViewComputer.TYPE ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":colour", ColourableRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":computer_upgrade", ComputerUpgradeRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":pocket_computer_upgrade", PocketComputerUpgradeRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":disk", DiskRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":printout", PrintoutRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":turtle", TurtleRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":turtle_upgrade", TurtleUpgradeRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":impostor_shapeless", ImpostorShapelessRecipe.SERIALIZER ); + IRecipeSerializer.register( ComputerCraft.MOD_ID + ":impostor_shaped", ImpostorRecipe.SERIALIZER ); ArgumentSerializers.register(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index 7927934f7..714eb4e69 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -54,7 +54,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler int basicBurnTime = stack.getBurnTime(); int burnTime = ForgeEventFactory.getItemBurnTime( stack, - basicBurnTime == -1 ? FurnaceTileEntity.func_214001_f().getOrDefault( stack.getItem(), 0 ) : basicBurnTime + basicBurnTime == -1 ? FurnaceTileEntity.getBurnTimes().getOrDefault( stack.getItem(), 0 ) : basicBurnTime ); return (burnTime * 5) / 100; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 61713a0af..52ddad2f4 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -6,47 +6,53 @@ package dan200.computercraft.shared.turtle.inventory; -import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.InputState; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtleBrain; +import dan200.computercraft.shared.util.SingleIntArray; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Inventory; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; +import net.minecraft.util.IIntArray; +import net.minecraft.util.IntArray; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class ContainerTurtle extends Container implements IContainerComputer { - public static final ContainerType TYPE = null; + public static final ContainerType TYPE = new ContainerType<>( ContainerTurtle::new ); public static final int PLAYER_START_Y = 134; public static final int TURTLE_START_X = 175; - private final ITurtleAccess m_turtle; - private IComputer m_computer; - private final InputState input = new InputState( this ); - private int selectedSlot; + private final IIntArray properties; - protected ContainerTurtle( int id, PlayerInventory playerInventory, ITurtleAccess turtle ) + private IComputer computer; + private TurtleBrain turtle; + + private final InputState input = new InputState( this ); + + protected ContainerTurtle( int id, PlayerInventory playerInventory, IInventory inventory, IIntArray properties ) { super( TYPE, id ); + this.properties = properties; - m_turtle = turtle; - selectedSlot = m_turtle.getWorld().isRemote ? 0 : m_turtle.getSelectedSlot(); + func_216961_a( properties ); // Turtle inventory for( int y = 0; y < 4; y++ ) { for( int x = 0; x < 4; x++ ) { - addSlot( new Slot( m_turtle.getInventory(), x + y * 4, TURTLE_START_X + 1 + x * 18, PLAYER_START_Y + 1 + y * 18 ) ); + addSlot( new Slot( inventory, x + y * 4, TURTLE_START_X + 1 + x * 18, PLAYER_START_Y + 1 + y * 18 ) ); } } @@ -66,22 +72,28 @@ public class ContainerTurtle extends Container implements IContainerComputer } } - public ContainerTurtle( int id, PlayerInventory playerInventory, ITurtleAccess turtle, IComputer computer ) + public ContainerTurtle( int id, PlayerInventory playerInventory, TurtleBrain turtle, IComputer computer ) { - this( id, playerInventory, turtle ); - m_computer = computer; + this( id, playerInventory, turtle.getInventory(), (SingleIntArray) turtle::getSelectedSlot ); + this.turtle = turtle; + this.computer = computer; + } + + private ContainerTurtle( int id, PlayerInventory playerInventory ) + { + this( id, playerInventory, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) ); } public int getSelectedSlot() { - return selectedSlot; + return properties.get( 0 ); } @Override public boolean canInteractWith( @Nonnull PlayerEntity player ) { - TileTurtle turtle = ((TurtleBrain) m_turtle).getOwner(); - return turtle != null && turtle.isUsableByPlayer( player ); + // If we've no turtle, we'll be on the client. + return turtle == null || (turtle.getOwner() != null && turtle.getOwner().isUsableByPlayer( player )); } @Nonnull @@ -138,7 +150,7 @@ public class ContainerTurtle extends Container implements IContainerComputer @Override public IComputer getComputer() { - return m_computer; + return computer; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 85fe72fea..218e5254c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -66,7 +66,7 @@ public class TurtleInventoryCrafting extends CraftingInventory } // Check the actual crafting - return m_turtle.getWorld().getRecipeManager().func_215371_a( IRecipeType.field_222149_a, this, m_turtle.getWorld() ).orElse( null ); + return m_turtle.getWorld().getRecipeManager().getRecipe( IRecipeType.CRAFTING, this, m_turtle.getWorld() ).orElse( null ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 1c12f20cc..fa388a76f 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -43,7 +43,7 @@ public final class IDAssigner public static File getDir() { MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).func_217485_w().getWorldDirectory(); // getSaveHandler + File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).getSaveHandler().getWorldDirectory(); return new File( worldDirectory, ComputerCraft.MOD_ID ); } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index 8a582f341..9d73fa54e 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -64,7 +64,7 @@ public final class ImpostorRecipe extends ShapedRecipe public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) { String group = JSONUtils.getString( json, "group", "" ); - ShapedRecipe recipe = IRecipeSerializer.field_222157_a.read( identifier, json ); + ShapedRecipe recipe = IRecipeSerializer.CRAFTING_SHAPED.read( identifier, json ); ItemStack result = CraftingHelper.getItemStack( JSONUtils.getJsonObject( json, "result" ), true ); return new ImpostorRecipe( identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result ); } diff --git a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java index 8d4b4c3a4..11151ff72 100644 --- a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java +++ b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java @@ -14,19 +14,18 @@ public interface SingleIntArray extends IIntArray int get(); @Override - default int func_221476_a( int property ) + default int get( int property ) { return property == 0 ? get() : 0; } @Override - default void func_221477_a( int i, int i1 ) + default void set( int property, int value ) { - } @Override - default int func_221478_a() + default int size() { return 1; } diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index b37c1534a..85d881f95 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -63,7 +63,7 @@ public final class WorldUtil // Raycast for blocks ENTITY.setPosition( vecStart.x, vecStart.y, vecStart.z ); RayTraceContext context = new RayTraceContext( vecStart, vecEnd, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, ENTITY ); - RayTraceResult result = world.func_217299_a( context ); + RayTraceResult result = world.rayTraceBlocks( context ); if( result != null && result.getType() == RayTraceResult.Type.BLOCK ) { distance = vecStart.distanceTo( result.getHitVec() ); @@ -96,7 +96,7 @@ public final class WorldUtil continue; } - Vec3d littleBoxResult = littleBox.func_216365_b( vecStart, vecEnd ).orElse( null ); // rayTrace + Vec3d littleBoxResult = littleBox.rayTrace( vecStart, vecEnd ).orElse( null ); if( littleBoxResult != null ) { double dist = vecStart.distanceTo( littleBoxResult ); @@ -178,6 +178,6 @@ public final class WorldUtil zDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1 ); item.setDefaultPickupDelay(); - world.func_217376_c( item ); + world.addEntity( item ); } } diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index ab5165580..63fe86547 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -2,9 +2,3 @@ public net.minecraft.client.renderer.FirstPersonRenderer func_187466_c()V # renderArms public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch public net.minecraft.client.renderer.FirstPersonRenderer func_187456_a(FFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson - -# Containers -public net.minecraft.inventory.container.ContainerType$IFactory -public net.minecraft.inventory.container.ContainerType (Lnet/minecraft/inventory/container/ContainerType$IFactory;)V -public net.minecraft.client.gui.ScreenManager$IScreenFactory -public net.minecraft.client.gui.ScreenManager func_216911_a(Lnet/minecraft/inventory/container/ContainerType;Lnet/minecraft/client/gui/ScreenManager$IScreenFactory;)V # registerFactory From d9cadf64e8e7fb60fb60820af4c196d2fb738937 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 9 Jun 2019 09:07:31 +0100 Subject: [PATCH 011/711] Get the build working I guess? --- config/checkstyle/checkstyle.xml | 2 +- src/main/java/dan200/computercraft/client/ClientRegistry.java | 4 ++-- .../computercraft/client/render/TileEntityTurtleRenderer.java | 2 +- .../shared/peripheral/modem/wired/TileCable.java | 2 +- .../shared/peripheral/modem/wired/TileWiredModemFull.java | 2 +- .../computercraft/shared/peripheral/monitor/TileMonitor.java | 2 +- .../dan200/computercraft/shared/turtle/core/TurtleBrain.java | 2 +- .../computercraft/shared/turtle/core/TurtleMoveCommand.java | 2 +- .../java/dan200/computercraft/shared/util/TickScheduler.java | 2 +- .../dan200/computercraft/core/filesystem/FileSystemTest.java | 4 ++-- .../computercraft/core/filesystem/ResourceMountTest.java | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 3dcaa94a2..d0b5b6d0c 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -149,7 +149,7 @@ - + diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index d32af07ff..d8cd382a6 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -12,12 +12,10 @@ import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ColorHandlerEvent; @@ -79,11 +77,13 @@ public final class ClientRegistry @SubscribeEvent public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) { + /* IResourceManager manager = Minecraft.getInstance().getResourceManager(); for( String extra : EXTRA_TEXTURES ) { // TODO: event.getMap().registerSprite( manager, new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); } + */ } @SubscribeEvent diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 4c6fe4de6..72ba67090 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -94,8 +94,8 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer GameRenderer.drawNameplate( getFontRenderer(), label, (float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, - rendererDispatcher.field_217666_g.func_216778_f(), rendererDispatcher.field_217666_g.func_216777_e(), false // yaw, pitch + rendererDispatcher.field_217666_g.func_216778_f(), rendererDispatcher.field_217666_g.func_216777_e(), false ); setLightmapDisabled( false ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 53fc60e7b..247eb75e0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -333,7 +333,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile for( Direction facing : DirectionUtil.FACINGS ) { BlockPos offset = current.offset( facing ); - if( !world.isBlockLoaded( offset ) ) continue; + if( !world.isAreaLoaded( offset, 0 ) ) continue; LazyOptional element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() ); if( !element.isPresent() ) continue; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index d7199e837..13b68cb18 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -286,7 +286,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile for( Direction facing : DirectionUtil.FACINGS ) { BlockPos offset = current.offset( facing ); - if( !world.isBlockLoaded( offset ) ) continue; + if( !world.isAreaLoaded( offset, 0 ) ) continue; LazyOptional element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() ); if( !element.isPresent() ) continue; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index f461fb7a1..923fb0c0e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -362,7 +362,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile int y = pos.getY(); World world = getWorld(); - if( world == null || !world.isBlockLoaded( pos ) ) return null; + if( world == null || !world.isAreaLoaded( pos, 0 ) ) return null; TileEntity tile = world.getTileEntity( pos ); if( !(tile instanceof TileMonitor) ) return null; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 0920f28b5..5612b5884 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -306,7 +306,7 @@ public class TurtleBrain implements ITurtleAccess } // Ensure the chunk is loaded - if( !world.isBlockLoaded( pos ) ) return false; + if( !world.isAreaLoaded( pos, 0 ) ) return false; // Ensure we're inside the world border if( !world.getWorldBorder().contains( pos ) ) return false; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index d6d639523..da10a199f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -146,7 +146,7 @@ public class TurtleMoveCommand implements ITurtleCommand return TurtleCommandResult.failure( "Cannot enter protected area" ); } - if( !world.isBlockLoaded( position ) ) return TurtleCommandResult.failure( "Cannot leave loaded world" ); + if( !world.isAreaLoaded( position, 0 ) ) return TurtleCommandResult.failure( "Cannot leave loaded world" ); if( !world.getWorldBorder().contains( position ) ) { return TurtleCommandResult.failure( "Cannot pass the world border" ); diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 6a367da98..50a3bcad6 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -59,7 +59,7 @@ public final class TickScheduler World world = tile.getWorld(); BlockPos pos = tile.getPos(); - if( world != null && pos != null && world.isBlockLoaded( pos ) && world.getTileEntity( pos ) == tile ) + if( world != null && pos != null && world.isAreaLoaded( pos, 0 ) && world.getTileEntity( pos ) == tile ) { world.getPendingBlockTicks().scheduleTick( pos, tile.getBlockState().getBlock(), 0 ); } diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java index abff129e8..95c3cf66c 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -40,7 +40,7 @@ public class FileSystemTest wrapper.call( "close" ); } - assertEquals( "This is a long line", Files.toString( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ) ); + assertEquals( "This is a long line", Files.asCharSource( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ).read() ); { FileSystemWrapper writer = fs.openForWrite( "out.txt", false, EncodedWritableHandle::openUtf8 ); @@ -49,6 +49,6 @@ public class FileSystemTest wrapper.call( "close" ); } - assertEquals( "Tiny line", Files.toString( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ) ); + assertEquals( "Tiny line", Files.asCharSource( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ).read() ); } } diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java index f4f074f52..00ea5fa2f 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -28,7 +28,7 @@ public class ResourceMountTest @BeforeEach public void before() { - SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA ); + SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA, null ); manager.addResourcePack( new FolderPack( new File( "src/main/resources" ) ) ); mount = new ResourceMount( "computercraft", "lua/rom", manager ); From f90da739ebb5ed684ae59bbe937a6c1ee82828c5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 9 Jun 2019 09:46:52 +0100 Subject: [PATCH 012/711] And bump Forge again --- gradle.properties | 2 +- .../dan200/computercraft/shared/Registry.java | 27 +++++++++++++++++++ .../computer/recipe/ComputerFamilyRecipe.java | 4 +-- .../proxy/ComputerCraftProxyCommon.java | 21 --------------- .../shared/util/BasicRecipeSerializer.java | 20 ++++++++++++++ .../shared/util/ImpostorRecipe.java | 2 +- .../shared/util/ImpostorShapelessRecipe.java | 2 +- 7 files changed, 52 insertions(+), 26 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java diff --git a/gradle.properties b/gradle.properties index 3f0302f1b..e3246dfd7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.83.1 # Minecraft properties mc_version=1.14.2 -forge_version=26.0.10 +forge_version=26.0.12 mappings_version=20190609-1.14.2 diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index 31512adc1..938bd30e0 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; @@ -16,9 +17,12 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.computer.items.ItemComputer; +import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemTreasureDisk; +import dan200.computercraft.shared.media.recipes.DiskRecipe; +import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; @@ -36,13 +40,18 @@ import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; +import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; import dan200.computercraft.shared.turtle.blocks.BlockTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.turtle.items.ItemTurtle; +import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; +import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.turtle.upgrades.*; import dan200.computercraft.shared.util.CreativeTabMain; +import dan200.computercraft.shared.util.ImpostorRecipe; +import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.entity.EntityType; @@ -51,6 +60,7 @@ import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.Items; +import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; @@ -335,4 +345,21 @@ public final class Registry ContainerViewComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "view_computer" ) ) ); } + + @SubscribeEvent + public static void regsterRecipeSerializers( RegistryEvent.Register> event ) + { + + event.getRegistry().registerAll( + ColourableRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "colour" ) ), + ComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ) ), + PocketComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_upgrade" ) ), + DiskRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ), + PrintoutRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ), + TurtleRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ), + TurtleUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_upgrade" ) ), + ImpostorShapelessRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shapeless" ) ), + ImpostorRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ) ) + ); + } } diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index fee97cd68..4a1e5879c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -8,9 +8,9 @@ package dan200.computercraft.shared.computer.recipe; import com.google.gson.JsonObject; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.util.BasicRecipeSerializer; import dan200.computercraft.shared.util.RecipeUtil; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.item.crafting.Ingredient; import net.minecraft.network.PacketBuffer; import net.minecraft.util.JSONUtils; @@ -34,7 +34,7 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe return family; } - public abstract static class Serializer implements IRecipeSerializer + public abstract static class Serializer extends BasicRecipeSerializer { protected abstract T create( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family ); diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 65f1747d1..06ad4fec8 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -15,28 +15,18 @@ import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.command.CommandComputerCraft; import dan200.computercraft.shared.command.arguments.ArgumentSerializers; -import dan200.computercraft.shared.common.ColourableRecipe; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe; import dan200.computercraft.shared.media.items.RecordMedia; -import dan200.computercraft.shared.media.recipes.DiskRecipe; -import dan200.computercraft.shared.media.recipes.PrintoutRecipe; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; -import dan200.computercraft.shared.pocket.recipes.PocketComputerUpgradeRecipe; -import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; -import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; -import dan200.computercraft.shared.util.ImpostorRecipe; -import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import dan200.computercraft.shared.wired.CapabilityWiredElement; import net.minecraft.inventory.container.Container; import net.minecraft.item.Item; import net.minecraft.item.MusicDiscItem; -import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraftforge.event.entity.player.PlayerContainerEvent; @@ -59,17 +49,6 @@ public final class ComputerCraftProxyCommon registerProviders(); - // Eww, eww, eww - can we move this to an event? - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":colour", ColourableRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":computer_upgrade", ComputerUpgradeRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":pocket_computer_upgrade", PocketComputerUpgradeRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":disk", DiskRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":printout", PrintoutRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":turtle", TurtleRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":turtle_upgrade", TurtleUpgradeRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":impostor_shapeless", ImpostorShapelessRecipe.SERIALIZER ); - IRecipeSerializer.register( ComputerCraft.MOD_ID + ":impostor_shaped", ImpostorRecipe.SERIALIZER ); - ArgumentSerializers.register(); // if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register(); diff --git a/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java b/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java new file mode 100644 index 000000000..6c54dff49 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java @@ -0,0 +1,20 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraftforge.registries.ForgeRegistryEntry; + +/** + * A {@link IRecipeSerializer} which implements all the Forge registry entries. + * + * @param The reciep serializer + */ +public abstract class BasicRecipeSerializer> extends ForgeRegistryEntry> implements IRecipeSerializer +{ +} diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index 9d73fa54e..8227831b7 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -58,7 +58,7 @@ public final class ImpostorRecipe extends ShapedRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new IRecipeSerializer() + public static final IRecipeSerializer SERIALIZER = new BasicRecipeSerializer() { @Override public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json ) diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index 779f7e470..16cad7f6d 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -60,7 +60,7 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe return SERIALIZER; } - public static final IRecipeSerializer SERIALIZER = new IRecipeSerializer() + public static final IRecipeSerializer SERIALIZER = new BasicRecipeSerializer() { @Override public ImpostorShapelessRecipe read( @Nonnull ResourceLocation id, @Nonnull JsonObject json ) From d10b657a54a735a586416f3df5e3a61451376316 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 11 Jun 2019 21:03:40 +0100 Subject: [PATCH 013/711] Initial work on GUIs Needs a bit of a cleanup, but it's a start! --- gradle.properties | 2 +- .../computercraft/client/gui/GuiComputer.java | 15 ++-- .../computercraft/client/gui/GuiTurtle.java | 2 +- .../shared/command/CommandComputerCraft.java | 3 +- .../shared/common/ContainerHeldItem.java | 2 +- .../shared/computer/blocks/TileComputer.java | 19 +++-- .../computer/blocks/TileComputerBase.java | 15 +++- .../computer/inventory/ContainerComputer.java | 56 +++---------- .../inventory/ContainerComputerBase.java | 80 +++++++++++++++++++ .../inventory/ContainerViewComputer.java | 76 ++++++++---------- .../shared/media/items/ItemPrintout.java | 3 +- .../container/ComputerContainerData.java | 46 +++++++++++ .../network/container/ContainerData.java | 26 +++--- .../PocketComputerContainerData.java | 12 +-- .../container/PrintoutContainerData.java | 12 +-- .../container/ViewComputerContainerData.java | 37 ++------- .../peripheral/diskdrive/TileDiskDrive.java | 3 +- .../peripheral/printer/TilePrinter.java | 2 +- .../inventory/ContainerPocketComputer.java | 2 +- .../pocket/items/ItemPocketComputer.java | 3 +- .../shared/turtle/blocks/TileTurtle.java | 16 ++-- .../turtle/inventory/ContainerTurtle.java | 72 ++++++----------- .../loot_tables/blocks/cable.json | 36 +++++++++ .../loot_tables/blocks/computer_advanced.json | 11 +++ .../loot_tables/blocks/computer_command.json | 11 +++ .../loot_tables/blocks/computer_normal.json | 9 +++ .../loot_tables/blocks/disk_drive.json | 15 ++++ .../loot_tables/blocks/monitor_advanced.json | 12 +++ .../loot_tables/blocks/monitor_normal.json | 12 +++ .../loot_tables/blocks/printer.json | 15 ++++ .../loot_tables/blocks/speaker.json | 12 +++ .../loot_tables/blocks/turtle_advanced.json | 16 ++++ .../loot_tables/blocks/turtle_normal.json | 14 ++++ .../loot_tables/blocks/wired_modem_full.json | 12 +++ .../blocks/wireless_modem_advanced.json | 12 +++ .../blocks/wireless_modem_normal.json | 12 +++ 36 files changed, 468 insertions(+), 235 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java create mode 100644 src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/cable.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/printer.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/speaker.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json create mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json diff --git a/gradle.properties b/gradle.properties index e3246dfd7..01a29a377 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.83.1 # Minecraft properties mc_version=1.14.2 -forge_version=26.0.12 +forge_version=26.0.16 mappings_version=20190609-1.14.2 diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index a95e6e31a..19f7d3a95 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -24,7 +24,7 @@ import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; -public class GuiComputer extends ContainerScreen +public final class GuiComputer extends ContainerScreen { public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); @@ -39,7 +39,7 @@ public class GuiComputer extends Conta private WidgetTerminal terminal; private WidgetWrapper terminalWrapper; - public GuiComputer( + private GuiComputer( T container, PlayerInventory player, ITextComponent title, ComputerFamily family, ClientComputer computer, int termWidth, int termHeight ) @@ -58,8 +58,7 @@ public class GuiComputer extends Conta container, inventory, component, container.getFamily(), (ClientComputer) container.getComputer(), - ComputerCraft.terminalWidth_computer, - ComputerCraft.terminalHeight_computer + ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); } @@ -70,8 +69,7 @@ public class GuiComputer extends Conta container, inventory, component, item instanceof ItemPocketComputer ? ((ItemPocketComputer) item).getFamily() : ComputerFamily.Normal, (ClientComputer) container.getComputer(), - ComputerCraft.terminalWidth_computer, - ComputerCraft.terminalHeight_computer + ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); } @@ -79,8 +77,9 @@ public class GuiComputer extends Conta { return new GuiComputer<>( container, inventory, component, - // TODO: Waiting to see how Forge handles this before implementing anything else. - null, (ClientComputer) container.getComputer(), 0, 0 + container.getFamily(), + (ClientComputer) container.getComputer(), + container.getWidth(), container.getHeight() ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index e285d9209..98ec8b647 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -36,7 +36,7 @@ public class GuiTurtle extends ContainerScreen super( container, player, title ); m_container = container; - m_family = null; // TODO + m_family = container.getFamily(); m_computer = (ClientComputer) container.getComputer(); xSize = 254; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 03314d6fd..9703ea029 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -20,7 +20,6 @@ import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.container.ViewComputerContainerData; import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -217,7 +216,7 @@ public final class CommandComputerCraft .executes( context -> { ServerPlayerEntity player = context.getSource().asPlayer(); ServerComputer computer = getComputerArgument( context, "computer" ); - new ViewComputerContainerData( computer ).open( player ); + // TODO: new ViewComputerContainerData( computer ).open( player ); return 1; } ) ) diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index d6dec3d36..1376ed56a 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -19,7 +19,7 @@ import javax.annotation.Nonnull; public class ContainerHeldItem extends Container { - public static final ContainerType PRINTOUT_TYPE = ContainerData.create( PrintoutContainerData::new ); + public static final ContainerType PRINTOUT_TYPE = ContainerData.toType( PrintoutContainerData::new, null /* TODO */ ); private final ItemStack m_stack; private final Hand m_hand; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index ab1826888..b5443cfaf 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -11,13 +11,19 @@ import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + public class TileComputer extends TileComputerBase { public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( @@ -67,12 +73,6 @@ public class TileComputer extends TileComputerBase return m_proxy; } - @Override - public void openGUI( PlayerEntity player ) - { - // TODO: Containers.openComputerGUI( player, this ); - } - public boolean isUsableByPlayer( PlayerEntity player ) { return isUsable( player, false ); @@ -103,4 +103,11 @@ public class TileComputer extends TileComputerBase if( localSide == ComputerSide.LEFT ) return ComputerSide.RIGHT; return localSide; } + + @Nullable + @Override + public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerComputer( id, this ); + } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index b54c99551..e57ecfdf2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -17,6 +17,7 @@ import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.RedstoneUtil; import joptsimple.internal.Strings; @@ -25,6 +26,7 @@ import net.minecraft.block.Blocks; import net.minecraft.block.RedstoneDiodeBlock; import net.minecraft.block.RedstoneWireBlock; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.nbt.CompoundNBT; @@ -43,7 +45,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; -public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickableTileEntity, IPeripheralTile, INameable +public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickableTileEntity, IPeripheralTile, INameable, INamedContainerProvider { private static final String NBT_ID = "ComputerId"; private static final String NBT_LABEL = "Label"; @@ -97,8 +99,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT super.remove(); } - public abstract void openGUI( PlayerEntity player ); - protected boolean canNameWithTag( PlayerEntity player ) { return false; @@ -124,7 +124,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( !getWorld().isRemote && isUsable( player, false ) ) { createServerComputer().turnOn(); - openGUI( player ); + new ComputerContainerData( createServerComputer() ).open( player, this ); } return true; } @@ -455,4 +455,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { return hasCustomName() ? new StringTextComponent( m_label ) : null; } + + @Nonnull + @Override + public ITextComponent getDisplayName() + { + return INameable.super.getDisplayName(); + } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java index c3ef181d5..aaaa0779d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java @@ -7,60 +7,22 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.shared.computer.blocks.TileComputer; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.InputState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.container.Container; +import dan200.computercraft.shared.network.container.ComputerContainerData; +import dan200.computercraft.shared.network.container.ContainerData; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ContainerType; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public class ContainerComputer extends Container implements IContainerComputer +public class ContainerComputer extends ContainerComputerBase { - public static final ContainerType TYPE = new ContainerType<>( ( id, player ) -> null ); + public static final ContainerType TYPE = ContainerData.toType( ComputerContainerData::new, ContainerComputer::new ); - private final TileComputer computer; - private final InputState input = new InputState( this ); - - public ContainerComputer( int id, TileComputer computer ) + public ContainerComputer( int id, TileComputer tile ) { - super( TYPE, id ); - this.computer = computer; + super( TYPE, id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() ); } - @Override - public boolean canInteractWith( @Nonnull PlayerEntity player ) + private ContainerComputer( int id, PlayerInventory player, ComputerContainerData data ) { - return computer.isUsableByPlayer( player ); - } - - @Nonnull - public ComputerFamily getFamily() - { - return computer.getFamily(); - } - - @Nullable - @Override - public IComputer getComputer() - { - return computer.getServerComputer(); - } - - @Nonnull - @Override - public InputState getInput() - { - return input; - } - - @Override - public void onContainerClosed( PlayerEntity player ) - { - super.onContainerClosed( player ); - input.close(); + super( TYPE, id, player, data ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java new file mode 100644 index 000000000..76813cfd4 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -0,0 +1,80 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.computer.inventory; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.IComputer; +import dan200.computercraft.shared.computer.core.IContainerComputer; +import dan200.computercraft.shared.computer.core.InputState; +import dan200.computercraft.shared.network.container.ComputerContainerData; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.function.Predicate; + +public class ContainerComputerBase extends Container implements IContainerComputer +{ + private final Predicate canUse; + private final IComputer computer; + private final ComputerFamily family; + private final InputState input = new InputState( this ); + + protected ContainerComputerBase( ContainerType type, int id, Predicate canUse, IComputer computer, ComputerFamily family ) + { + super( type, id ); + this.canUse = canUse; + this.computer = computer; + this.family = family; + } + + protected ContainerComputerBase( ContainerType type, int id, PlayerInventory player, ComputerContainerData data ) + { + this( type, id, x -> true, + (player.player.world.isRemote + ? ComputerCraft.clientComputerRegistry + : ComputerCraft.serverComputerRegistry).get( data.getInstanceId() ), + data.getFamily() ); + } + + @Override + public boolean canInteractWith( @Nonnull PlayerEntity player ) + { + return canUse.test( player ); + } + + @Nonnull + public ComputerFamily getFamily() + { + return family; + } + + @Nullable + @Override + public IComputer getComputer() + { + return computer; + } + + @Nonnull + @Override + public InputState getInput() + { + return input; + } + + @Override + public void onContainerClosed( PlayerEntity player ) + { + super.onContainerClosed( player ); + input.close(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index c6f7d8576..4196d41bc 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -7,82 +7,72 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.*; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.IContainerComputer; +import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.network.container.ViewComputerContainerData; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.container.Container; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ContainerType; import net.minecraft.server.MinecraftServer; import net.minecraft.util.text.TranslationTextComponent; import javax.annotation.Nonnull; -import javax.annotation.Nullable; -public class ContainerViewComputer extends Container implements IContainerComputer +public class ContainerViewComputer extends ContainerComputerBase implements IContainerComputer { - public static final ContainerType TYPE = ContainerData.create( ViewComputerContainerData::new ); + public static final ContainerType TYPE = ContainerData.toType( ViewComputerContainerData::new, ContainerViewComputer::new ); - private final IComputer computer; - private final InputState input = new InputState( this ); + private final int width; + private final int height; - public ContainerViewComputer( int id, IComputer computer ) + public ContainerViewComputer( int id, ServerComputer computer ) { - super( TYPE, id ); - this.computer = computer; + super( TYPE, id, player -> canInteractWith( computer, player ), computer, computer.getFamily() ); + this.width = this.height = 0; } - @Nullable - @Override - public IComputer getComputer() + public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data ) { - return computer; + super( TYPE, id, player, data ); + this.width = data.getWidth(); + this.height = data.getHeight(); } - @Override - public boolean canInteractWith( @Nonnull PlayerEntity player ) + private static boolean canInteractWith( @Nonnull ServerComputer computer, @Nonnull PlayerEntity player ) { - if( computer instanceof ServerComputer ) + // If this computer no longer exists then discard it. + if( ComputerCraft.serverComputerRegistry.get( computer.getInstanceID() ) != computer ) { - ServerComputer serverComputer = (ServerComputer) computer; + return false; + } - // If this computer no longer exists then discard it. - if( ComputerCraft.serverComputerRegistry.get( serverComputer.getInstanceID() ) != serverComputer ) + // If we're a command computer then ensure we're in creative + if( computer.getFamily() == ComputerFamily.Command ) + { + MinecraftServer server = player.getServer(); + if( server == null || !server.isCommandBlockEnabled() ) { return false; } - - // If we're a command computer then ensure we're in creative - if( serverComputer.getFamily() == ComputerFamily.Command ) + else if( !player.canUseCommandBlock() ) { - MinecraftServer server = player.getServer(); - if( server == null || !server.isCommandBlockEnabled() ) - { - player.sendStatusMessage( new TranslationTextComponent( "advMode.notEnabled" ), false ); - return false; - } - else if( !player.canUseCommandBlock() ) - { - player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), false ); - return false; - } + player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), false ); + return false; } } - return computer != null; + return true; } - @Nonnull - @Override - public InputState getInput() + public int getWidth() { - return input; + return width; } - @Override - public void onContainerClosed( PlayerEntity player ) + public int getHeight() { - super.onContainerClosed( player ); - input.close(); + return height; } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index b0a38d1a6..1c8dfe5f1 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.network.container.PrintoutContainerData; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; @@ -60,7 +59,7 @@ public class ItemPrintout extends Item @Override public ActionResult onItemRightClick( World world, PlayerEntity player, @Nonnull Hand hand ) { - if( !world.isRemote ) new PrintoutContainerData( hand ).open( player ); + // TODO: if( !world.isRemote ) new PrintoutContainerData( hand ).open( player ); return new ActionResult<>( ActionResultType.SUCCESS, player.getHeldItem( hand ) ); } diff --git a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java new file mode 100644 index 000000000..fadf0189d --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java @@ -0,0 +1,46 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.container; + +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ServerComputer; +import net.minecraft.network.PacketBuffer; + +public class ComputerContainerData implements ContainerData +{ + private final int id; + private final ComputerFamily family; + + public ComputerContainerData( ServerComputer computer ) + { + this.id = computer.getInstanceID(); + this.family = computer.getFamily(); + } + + public ComputerContainerData( PacketBuffer buf ) + { + this.id = buf.readInt(); + this.family = buf.readEnumValue( ComputerFamily.class ); + } + + @Override + public void toBytes( PacketBuffer buf ) + { + buf.writeInt( id ); + buf.writeEnumValue( family ); + } + + public int getInstanceId() + { + return id; + } + + public ComputerFamily getFamily() + { + return family; + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index edfa91965..842f97957 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -10,32 +10,36 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.network.PacketBuffer; +import net.minecraftforge.common.extensions.IForgeContainerType; import net.minecraftforge.fml.network.NetworkHooks; import javax.annotation.Nonnull; +import java.util.function.Consumer; import java.util.function.Function; /** - * A horrible hack to allow opening GUIs until Forge adds a built-in system. + * An extension over the basic {@link IForgeContainerType}/{@link NetworkHooks#openGui(ServerPlayerEntity, INamedContainerProvider, Consumer)} + * hooks, with a more convenient way of reading and writing data. */ -public interface ContainerData extends INamedContainerProvider +public interface ContainerData { void toBytes( PacketBuffer buf ); - default void open( PlayerEntity player ) + default void open( PlayerEntity player, INamedContainerProvider owner ) { - NetworkHooks.openGui( (ServerPlayerEntity) player, this, this::toBytes ); + NetworkHooks.openGui( (ServerPlayerEntity) player, owner, this::toBytes ); } - @Nonnull - T createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ); - - static > net.minecraft.inventory.container.ContainerType create( Function reader ) + static ContainerType toType( Function reader, Factory factory ) { - return new net.minecraft.inventory.container.ContainerType<>( - ( id, player ) -> reader.apply( null ).createMenu( id, player, player.player ) - ); + return IForgeContainerType.create( ( id, player, data ) -> factory.create( id, player, reader.apply( data ) ) ); + } + + interface Factory + { + C create( int id, @Nonnull PlayerInventory inventory, T data ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java index b1cc11093..c0c512577 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java @@ -11,8 +11,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.network.PacketBuffer; import net.minecraft.util.Hand; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TranslationTextComponent; import javax.annotation.Nonnull; @@ -21,7 +19,7 @@ import javax.annotation.Nonnull; * * @see dan200.computercraft.shared.pocket.items.ItemPocketComputer */ -public class PocketComputerContainerData implements ContainerData +public class PocketComputerContainerData implements ContainerData { private final Hand hand; @@ -42,14 +40,6 @@ public class PocketComputerContainerData implements ContainerData +public class PrintoutContainerData implements ContainerData { private final Hand hand; @@ -42,14 +40,6 @@ public class PrintoutContainerData implements ContainerData } @Nonnull - @Override - public ITextComponent getDisplayName() - { - return new TranslationTextComponent( "gui.computercraft.printout" ); - } - - @Nonnull - @Override public ContainerHeldItem createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) { return new ContainerHeldItem( ContainerHeldItem.PRINTOUT_TYPE, id, player, hand ); diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index adadcc8e7..1fa3edcea 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -6,18 +6,9 @@ package dan200.computercraft.shared.network.container; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.text.TranslationTextComponent; import javax.annotation.Nonnull; @@ -26,18 +17,14 @@ import javax.annotation.Nonnull; * * @see dan200.computercraft.shared.command.CommandComputerCraft */ -public class ViewComputerContainerData implements ContainerData +public class ViewComputerContainerData extends ComputerContainerData { - public static final ResourceLocation ID = new ResourceLocation( ComputerCraft.MOD_ID, "view_computer_gui" ); - - private final int instanceId; private final int width; private final int height; - private final ComputerFamily family; public ViewComputerContainerData( ServerComputer computer ) { - instanceId = computer.getInstanceID(); + super( computer ); Terminal terminal = computer.getTerminal(); if( terminal != null ) { @@ -48,38 +35,30 @@ public class ViewComputerContainerData implements ContainerData TYPE = ContainerData.create( PocketComputerContainerData::new ); + public static final ContainerType TYPE = ContainerData.toType( PocketComputerContainerData::new, null /* TODO */ ); private final InputState input = new InputState( this ); diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index f81ac140e..933e6db2a 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -20,7 +20,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.network.container.PocketComputerContainerData; import dan200.computercraft.shared.pocket.apis.PocketAPI; import dan200.computercraft.shared.pocket.core.PocketServerComputer; import net.minecraft.client.util.ITooltipFlag; @@ -154,7 +153,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I } } - if( !stop ) new PocketComputerContainerData( hand ).open( player ); + // TODO: if( !stop ) new PocketComputerContainerData( hand ).open( player ); } return new ActionResult<>( ActionResultType.SUCCESS, stack ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 31933762e..cdb7207a1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -22,8 +22,11 @@ import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.apis.TurtleAPI; import dan200.computercraft.shared.turtle.core.TurtleBrain; +import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.util.*; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; import net.minecraft.item.DyeColor; import net.minecraft.item.DyeItem; import net.minecraft.item.ItemStack; @@ -223,12 +226,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default return true; } - @Override - public void openGUI( PlayerEntity player ) - { - // TODO: Containers.openTurtleGUI( player, this ); - } - @Override protected double getInteractRange( PlayerEntity player ) { @@ -622,4 +619,11 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } return super.getCapability( cap, side ); } + + @Nullable + @Override + public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerTurtle( id, inventory, m_brain ); + } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 52ddad2f4..27330cdeb 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -6,9 +6,12 @@ package dan200.computercraft.shared.turtle.inventory; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.InputState; +import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; +import dan200.computercraft.shared.network.container.ComputerContainerData; +import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.util.SingleIntArray; @@ -16,7 +19,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; @@ -24,25 +26,23 @@ import net.minecraft.util.IIntArray; import net.minecraft.util.IntArray; import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.function.Predicate; -public class ContainerTurtle extends Container implements IContainerComputer +public class ContainerTurtle extends ContainerComputerBase { - public static final ContainerType TYPE = new ContainerType<>( ContainerTurtle::new ); + public static final ContainerType TYPE = ContainerData.toType( ComputerContainerData::new, ContainerTurtle::new ); public static final int PLAYER_START_Y = 134; public static final int TURTLE_START_X = 175; private final IIntArray properties; - private IComputer computer; - private TurtleBrain turtle; - - private final InputState input = new InputState( this ); - - protected ContainerTurtle( int id, PlayerInventory playerInventory, IInventory inventory, IIntArray properties ) + private ContainerTurtle( + int id, Predicate canUse, IComputer computer, ComputerFamily family, + PlayerInventory playerInventory, IInventory inventory, IIntArray properties + ) { - super( TYPE, id ); + super( TYPE, id, canUse, computer, family ); this.properties = properties; func_216961_a( properties ); @@ -72,16 +72,22 @@ public class ContainerTurtle extends Container implements IContainerComputer } } - public ContainerTurtle( int id, PlayerInventory playerInventory, TurtleBrain turtle, IComputer computer ) + public ContainerTurtle( int id, PlayerInventory player, TurtleBrain turtle ) { - this( id, playerInventory, turtle.getInventory(), (SingleIntArray) turtle::getSelectedSlot ); - this.turtle = turtle; - this.computer = computer; + this( + id, p -> turtle.getOwner().isUsableByPlayer( p ), turtle.getOwner().createServerComputer(), turtle.getFamily(), + player, turtle.getInventory(), (SingleIntArray) turtle::getSelectedSlot + ); } - private ContainerTurtle( int id, PlayerInventory playerInventory ) + private ContainerTurtle( int id, PlayerInventory player, ComputerContainerData data ) { - this( id, playerInventory, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) ); + this( id, x -> true, + (player.player.world.isRemote + ? ComputerCraft.clientComputerRegistry + : ComputerCraft.serverComputerRegistry).get( data.getInstanceId() ), + data.getFamily(), + player, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) ); } public int getSelectedSlot() @@ -89,13 +95,6 @@ public class ContainerTurtle extends Container implements IContainerComputer return properties.get( 0 ); } - @Override - public boolean canInteractWith( @Nonnull PlayerEntity player ) - { - // If we've no turtle, we'll be on the client. - return turtle == null || (turtle.getOwner() != null && turtle.getOwner().isUsableByPlayer( player )); - } - @Nonnull private ItemStack tryItemMerge( PlayerEntity player, int slotNum, int firstSlot, int lastSlot, boolean reverse ) { @@ -145,25 +144,4 @@ public class ContainerTurtle extends Container implements IContainerComputer } return ItemStack.EMPTY; } - - @Nullable - @Override - public IComputer getComputer() - { - return computer; - } - - @Nonnull - @Override - public InputState getInput() - { - return input; - } - - @Override - public void onContainerClosed( PlayerEntity player ) - { - super.onContainerClosed( player ); - input.close(); - } } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/cable.json b/src/main/resources/data/computercraft/loot_tables/blocks/cable.json new file mode 100644 index 000000000..464c823b5 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/cable.json @@ -0,0 +1,36 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:cable" } + ], + "conditions": [ + { "condition": "minecraft:survives_explosion" }, + { + "condition": "minecraft:block_state_property", + "block": "computercraft:cable", + "properties": { "cable": "true" } + } + ] + }, + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:wired_modem" } + ], + "conditions": [ + { "condition": "minecraft:survives_explosion" }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "minecraft:block_state_property", + "block": "computercraft:cable", + "properties": { "modem": "none" } + } + } + ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json new file mode 100644 index 000000000..7e55bfbab --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:dynamic", "name": "computercraft:computer" } + ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json new file mode 100644 index 000000000..7e55bfbab --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:dynamic", "name": "computercraft:computer" } + ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json new file mode 100644 index 000000000..888d1a551 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json new file mode 100644 index 000000000..0cdc589b6 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ { "type": "minecraft:item", "name": "computercraft:disk_drive" } ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + }, + { + "rolls": 1, + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json new file mode 100644 index 000000000..0862a0591 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:monitor_advanced" } + ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json new file mode 100644 index 000000000..f487890e4 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:monitor_normal" } + ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json new file mode 100644 index 000000000..00e2d6be4 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ { "type": "minecraft:item", "name": "computercraft:printer" } ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + }, + { + "rolls": 1, + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json b/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json new file mode 100644 index 000000000..6beed7b85 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:speaker" } + ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json new file mode 100644 index 000000000..53be1b400 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:dynamic", "name": "computercraft:computer" } + ] + }, + { + "rolls": 1, + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json new file mode 100644 index 000000000..e7c25eb99 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] + }, + { + "rolls": 1, + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json b/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json new file mode 100644 index 000000000..fa6b9de17 --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:wired_modem_full" } + ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json new file mode 100644 index 000000000..0672f78cf --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:wireless_modem_advanced" } + ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json new file mode 100644 index 000000000..dad3722ec --- /dev/null +++ b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json @@ -0,0 +1,12 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { "type": "minecraft:item", "name": "computercraft:wireless_modem_normal" } + ], + "conditions": [ { "condition": "minecraft:survives_explosion" } ] + } + ] +} From 8dd1c2a6cc9002f19389337484d79f11b448b149 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 12 Jun 2019 08:40:20 +0100 Subject: [PATCH 014/711] Finish off containers, somewhat fix block drops - Add Forge's "name" field to the loot tables. This doesn't resolve all our missing loot providers, but it's a start. - Add back GUIs for pocket computers, printouts, view computer, etc... --- .../computercraft/client/gui/GuiComputer.java | 23 ++---- .../shared/command/CommandComputerCraft.java | 23 +++++- .../shared/common/ContainerHeldItem.java | 55 +++++++++++--- .../computer/blocks/TileComputerBase.java | 26 ------- .../shared/computer/core/ClientComputer.java | 20 ------ .../computer/core/ClientComputerRegistry.java | 8 --- .../inventory/ContainerComputerBase.java | 21 +++--- .../shared/media/items/ItemPrintout.java | 8 ++- ...erData.java => HeldItemContainerData.java} | 13 ++-- .../PocketComputerContainerData.java | 47 ------------ .../inventory/ContainerPocketComputer.java | 71 ++++++++++++------- .../pocket/items/ItemPocketComputer.java | 9 ++- .../proxy/ComputerCraftProxyCommon.java | 9 --- .../turtle/inventory/ContainerTurtle.java | 11 ++- .../loot_tables/blocks/cable.json | 2 + .../loot_tables/blocks/computer_advanced.json | 1 + .../loot_tables/blocks/computer_command.json | 1 + .../loot_tables/blocks/computer_normal.json | 1 + .../loot_tables/blocks/disk_drive.json | 2 + .../loot_tables/blocks/monitor_advanced.json | 1 + .../loot_tables/blocks/monitor_normal.json | 1 + .../loot_tables/blocks/printer.json | 2 + .../loot_tables/blocks/speaker.json | 1 + .../loot_tables/blocks/turtle_advanced.json | 2 + .../loot_tables/blocks/turtle_normal.json | 2 + .../loot_tables/blocks/wired_modem_full.json | 1 + .../blocks/wireless_modem_advanced.json | 1 + .../blocks/wireless_modem_normal.json | 1 + 28 files changed, 173 insertions(+), 190 deletions(-) rename src/main/java/dan200/computercraft/shared/network/container/{PrintoutContainerData.java => HeldItemContainerData.java} (63%) delete mode 100644 src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 19f7d3a95..159aba7c0 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -12,19 +12,16 @@ import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; -import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.container.Container; -import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; -public final class GuiComputer extends ContainerScreen +public final class GuiComputer extends ContainerScreen { public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); @@ -40,13 +37,12 @@ public final class GuiComputer extends private WidgetWrapper terminalWrapper; private GuiComputer( - T container, PlayerInventory player, ITextComponent title, - ComputerFamily family, ClientComputer computer, int termWidth, int termHeight + T container, PlayerInventory player, ITextComponent title, int termWidth, int termHeight ) { super( container, player, title ); - m_family = family; - m_computer = computer; + m_family = container.getFamily(); + m_computer = (ClientComputer) container.getComputer(); m_termWidth = termWidth; m_termHeight = termHeight; terminal = null; @@ -56,20 +52,15 @@ public final class GuiComputer extends { return new GuiComputer<>( container, inventory, component, - container.getFamily(), - (ClientComputer) container.getComputer(), ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); } public static GuiComputer createPocket( ContainerPocketComputer container, PlayerInventory inventory, ITextComponent component ) { - Item item = container.getStack().getItem(); return new GuiComputer<>( container, inventory, component, - item instanceof ItemPocketComputer ? ((ItemPocketComputer) item).getFamily() : ComputerFamily.Normal, - (ClientComputer) container.getComputer(), - ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer + ComputerCraft.terminalWidth_pocketComputer, ComputerCraft.terminalHeight_pocketComputer ); } @@ -77,8 +68,6 @@ public final class GuiComputer extends { return new GuiComputer<>( container, inventory, component, - container.getFamily(), - (ClientComputer) container.getComputer(), container.getWidth(), container.getHeight() ); } diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 9703ea029..17b333ec3 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -20,14 +20,20 @@ import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; +import dan200.computercraft.shared.network.container.ViewComputerContainerData; import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.network.play.server.SPlayerPositionLookPacket; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.ServerWorld; import net.minecraft.world.World; @@ -216,7 +222,22 @@ public final class CommandComputerCraft .executes( context -> { ServerPlayerEntity player = context.getSource().asPlayer(); ServerComputer computer = getComputerArgument( context, "computer" ); - // TODO: new ViewComputerContainerData( computer ).open( player ); + new ViewComputerContainerData( computer ).open( player, new INamedContainerProvider() + { + @Nonnull + @Override + public ITextComponent getDisplayName() + { + return new TranslationTextComponent( "gui.computercraft.view_computer" ); + } + + @Nonnull + @Override + public Container createMenu( int id, @Nonnull PlayerInventory player, @Nonnull PlayerEntity entity ) + { + return new ContainerViewComputer( id, computer ); + } + } ); return 1; } ) ) diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index 1376ed56a..649c95d4a 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -7,35 +7,44 @@ package dan200.computercraft.shared.common; import dan200.computercraft.shared.network.container.ContainerData; -import dan200.computercraft.shared.network.container.PrintoutContainerData; +import dan200.computercraft.shared.network.container.HeldItemContainerData; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; +import net.minecraft.util.text.ITextComponent; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class ContainerHeldItem extends Container { - public static final ContainerType PRINTOUT_TYPE = ContainerData.toType( PrintoutContainerData::new, null /* TODO */ ); + public static final ContainerType PRINTOUT_TYPE = ContainerData.toType( HeldItemContainerData::new, ContainerHeldItem::createPrintout ); - private final ItemStack m_stack; - private final Hand m_hand; + private final ItemStack stack; + private final Hand hand; public ContainerHeldItem( ContainerType type, int id, PlayerEntity player, Hand hand ) { super( type, id ); - m_hand = hand; - m_stack = InventoryUtil.copyItem( player.getHeldItem( hand ) ); + this.hand = hand; + stack = InventoryUtil.copyItem( player.getHeldItem( hand ) ); + } + + private static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) + { + return new ContainerHeldItem( PRINTOUT_TYPE, id, inventory.player, data.getHand() ); } @Nonnull public ItemStack getStack() { - return m_stack; + return stack; } @Override @@ -43,7 +52,35 @@ public class ContainerHeldItem extends Container { if( !player.isAlive() ) return false; - ItemStack stack = player.getHeldItem( m_hand ); - return stack == m_stack || !stack.isEmpty() && !m_stack.isEmpty() && stack.getItem() == m_stack.getItem(); + ItemStack stack = player.getHeldItem( hand ); + return stack == this.stack || !stack.isEmpty() && !this.stack.isEmpty() && stack.getItem() == this.stack.getItem(); + } + + public static class Factory implements INamedContainerProvider + { + private final ContainerType type; + private final ITextComponent name; + private final Hand hand; + + public Factory( ContainerType type, ItemStack stack, Hand hand ) + { + this.type = type; + this.name = stack.getDisplayName(); + this.hand = hand; + } + + @Nonnull + @Override + public ITextComponent getDisplayName() + { + return name; + } + + @Nullable + @Override + public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + { + return new ContainerHeldItem( type, id, player, hand ); + } } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index e57ecfdf2..ee30ff3c6 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -13,7 +13,6 @@ import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.BundledRedstone; import dan200.computercraft.shared.Peripherals; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; @@ -49,7 +48,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { private static final String NBT_ID = "ComputerId"; private static final String NBT_LABEL = "Label"; - private static final String NBT_INSTANCE = "InstanceId"; private static final String NBT_ON = "On"; private int m_instanceID = -1; @@ -173,11 +171,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( computer.hasOutputChanged() ) updateOutput(); } - else - { - ClientComputer computer = createClientComputer(); - if( computer != null && computer.hasOutputChanged() ) updateBlock(); - } } protected abstract void updateBlockState( ComputerState newState ); @@ -376,23 +369,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT return getWorld().isRemote ? null : ComputerCraft.serverComputerRegistry.get( m_instanceID ); } - public ClientComputer createClientComputer() - { - if( !getWorld().isRemote || m_instanceID < 0 ) return null; - - ClientComputer computer = ComputerCraft.clientComputerRegistry.get( m_instanceID ); - if( computer == null ) - { - ComputerCraft.clientComputerRegistry.add( m_instanceID, computer = new ClientComputer( m_instanceID ) ); - } - return computer; - } - - public ClientComputer getClientComputer() - { - return getWorld().isRemote ? ComputerCraft.clientComputerRegistry.get( m_instanceID ) : null; - } - // Networking stuff @Override @@ -402,14 +378,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); if( m_label != null ) nbt.putString( NBT_LABEL, m_label ); - nbt.putInt( NBT_INSTANCE, createServerComputer().getInstanceID() ); } @Override protected void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); - m_instanceID = nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; m_label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null; m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index 6675f6b4d..43eb6b39d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.computer.core; -import com.google.common.base.Objects; import dan200.computercraft.shared.common.ClientTerminal; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.server.*; @@ -18,10 +17,8 @@ public class ClientComputer extends ClientTerminal implements IComputer private boolean m_on = false; private boolean m_blinking = false; - private boolean m_changed = true; private CompoundNBT m_userData = null; - private boolean m_changedLastFrame = false; public ClientComputer( int instanceID ) { @@ -29,17 +26,6 @@ public class ClientComputer extends ClientTerminal implements IComputer m_instanceID = instanceID; } - public void update() - { - m_changedLastFrame = m_changed; - m_changed = false; - } - - public boolean hasOutputChanged() - { - return m_changedLastFrame; - } - public CompoundNBT getUserData() { return m_userData; @@ -137,14 +123,8 @@ public class ClientComputer extends ClientTerminal implements IComputer public void setState( ComputerState state, CompoundNBT userData ) { - boolean oldOn = m_on; - boolean oldBlinking = m_blinking; - CompoundNBT oldUserData = m_userData; - m_on = state != ComputerState.OFF; m_blinking = state == ComputerState.BLINKING; m_userData = userData; - - m_changed |= m_on != oldOn || m_blinking != oldBlinking || !Objects.equal( m_userData, oldUserData ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java index 8d6b510ba..fc7fc46c6 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java @@ -8,14 +8,6 @@ package dan200.computercraft.shared.computer.core; public class ClientComputerRegistry extends ComputerRegistry { - public void update() - { - for( ClientComputer computer : getComputers() ) - { - computer.update(); - } - } - @Override public void add( int instanceID, ClientComputer computer ) { diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index 76813cfd4..e88b15b09 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -7,10 +7,7 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.InputState; +import dan200.computercraft.shared.computer.core.*; import dan200.computercraft.shared.network.container.ComputerContainerData; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; @@ -38,11 +35,17 @@ public class ContainerComputerBase extends Container implements IContainerComput protected ContainerComputerBase( ContainerType type, int id, PlayerInventory player, ComputerContainerData data ) { - this( type, id, x -> true, - (player.player.world.isRemote - ? ComputerCraft.clientComputerRegistry - : ComputerCraft.serverComputerRegistry).get( data.getInstanceId() ), - data.getFamily() ); + this( type, id, x -> true, getComputer( player, data ), data.getFamily() ); + } + + protected static IComputer getComputer( PlayerInventory player, ComputerContainerData data ) + { + int id = data.getInstanceId(); + if( !player.player.world.isRemote ) return ComputerCraft.serverComputerRegistry.get( id ); + + ClientComputer computer = ComputerCraft.clientComputerRegistry.get( id ); + if( computer == null ) ComputerCraft.clientComputerRegistry.add( id, computer = new ClientComputer( id ) ); + return computer; } @Override diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index 1c8dfe5f1..48e633a4b 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -7,6 +7,8 @@ package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.common.ContainerHeldItem; +import dan200.computercraft.shared.network.container.HeldItemContainerData; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.Item; @@ -59,7 +61,11 @@ public class ItemPrintout extends Item @Override public ActionResult onItemRightClick( World world, PlayerEntity player, @Nonnull Hand hand ) { - // TODO: if( !world.isRemote ) new PrintoutContainerData( hand ).open( player ); + if( !world.isRemote ) + { + new HeldItemContainerData( hand ) + .open( player, new ContainerHeldItem.Factory( ContainerHeldItem.PRINTOUT_TYPE, player.getHeldItem( hand ), hand ) ); + } return new ActionResult<>( ActionResultType.SUCCESS, player.getHeldItem( hand ) ); } diff --git a/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java similarity index 63% rename from src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java rename to src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index 094caca88..51e679a3f 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/PrintoutContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -7,8 +7,6 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.common.ContainerHeldItem; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; import net.minecraft.network.PacketBuffer; import net.minecraft.util.Hand; @@ -17,18 +15,19 @@ import javax.annotation.Nonnull; /** * Opens a printout GUI based on the currently held item * + * @see ContainerHeldItem * @see dan200.computercraft.shared.media.items.ItemPrintout */ -public class PrintoutContainerData implements ContainerData +public class HeldItemContainerData implements ContainerData { private final Hand hand; - public PrintoutContainerData( Hand hand ) + public HeldItemContainerData( Hand hand ) { this.hand = hand; } - public PrintoutContainerData( PacketBuffer buffer ) + public HeldItemContainerData( PacketBuffer buffer ) { hand = buffer.readEnumValue( Hand.class ); } @@ -40,8 +39,8 @@ public class PrintoutContainerData implements ContainerData } @Nonnull - public ContainerHeldItem createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) + public Hand getHand() { - return new ContainerHeldItem( ContainerHeldItem.PRINTOUT_TYPE, id, player, hand ); + return hand; } } diff --git a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java deleted file mode 100644 index c0c512577..000000000 --- a/src/main/java/dan200/computercraft/shared/network/container/PocketComputerContainerData.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.network.container; - -import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.network.PacketBuffer; -import net.minecraft.util.Hand; - -import javax.annotation.Nonnull; - -/** - * Opens a pocket computer GUI based on the held item - * - * @see dan200.computercraft.shared.pocket.items.ItemPocketComputer - */ -public class PocketComputerContainerData implements ContainerData -{ - private final Hand hand; - - public PocketComputerContainerData( Hand hand ) - { - this.hand = hand; - } - - public PocketComputerContainerData( PacketBuffer buffer ) - { - hand = buffer.readEnumValue( Hand.class ); - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - buf.writeEnumValue( hand ); - } - - @Nonnull - public ContainerPocketComputer createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) - { - return new ContainerPocketComputer( id, player, hand ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java index 65be978d8..d4667ccbe 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java @@ -6,52 +6,69 @@ package dan200.computercraft.shared.pocket.inventory; -import dan200.computercraft.shared.common.ContainerHeldItem; -import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.InputState; +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; +import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ContainerData; -import dan200.computercraft.shared.network.container.PocketComputerContainerData; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; +import net.minecraft.util.text.ITextComponent; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class ContainerPocketComputer extends ContainerHeldItem implements IContainerComputer +public final class ContainerPocketComputer extends ContainerComputerBase { - public static final ContainerType TYPE = ContainerData.toType( PocketComputerContainerData::new, null /* TODO */ ); + public static final ContainerType TYPE = ContainerData.toType( ComputerContainerData::new, ContainerPocketComputer::new ); - private final InputState input = new InputState( this ); - - public ContainerPocketComputer( int id, @Nonnull PlayerEntity player, Hand hand ) + private ContainerPocketComputer( int id, ServerComputer computer, ItemPocketComputer item, Hand hand ) { - super( TYPE, id, player, hand ); + super( TYPE, id, p -> { + ItemStack stack = p.getHeldItem( hand ); + return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer; + }, computer, item.getFamily() ); } - @Nullable - @Override - public IComputer getComputer() + private ContainerPocketComputer( int id, PlayerInventory player, ComputerContainerData data ) { - ItemStack stack = getStack(); - return !stack.isEmpty() && stack.getItem() instanceof ItemPocketComputer - ? ItemPocketComputer.getServerComputer( stack ) : null; + super( TYPE, id, player, data ); } - @Nonnull - @Override - public InputState getInput() + public static class Factory implements INamedContainerProvider { - return input; - } - @Override - public void onContainerClosed( PlayerEntity player ) - { - super.onContainerClosed( player ); - input.close(); + private final ServerComputer computer; + private final ITextComponent name; + private final ItemPocketComputer item; + private final Hand hand; + + public Factory( ServerComputer computer, ItemStack stack, ItemPocketComputer item, Hand hand ) + { + this.computer = computer; + this.name = stack.getDisplayName(); + this.item = item; + this.hand = hand; + } + + + @Nonnull + @Override + public ITextComponent getDisplayName() + { + return name; + } + + @Nullable + @Override + public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity entity ) + { + return new ContainerPocketComputer( id, computer, item, hand ); + } } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 933e6db2a..547cba9d1 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -20,8 +20,10 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; +import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.pocket.apis.PocketAPI; import dan200.computercraft.shared.pocket.core.PocketServerComputer; +import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -153,7 +155,10 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I } } - // TODO: if( !stop ) new PocketComputerContainerData( hand ).open( player ); + if( !stop && computer != null ) + { + new ComputerContainerData( computer ).open( player, new ContainerPocketComputer.Factory( computer, stack, this, hand ) ); + } } return new ActionResult<>( ActionResultType.SUCCESS, stack ); } @@ -207,7 +212,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I return super.getCreatorModId( stack ); } - private PocketServerComputer createServerComputer( final World world, IInventory inventory, Entity entity, @Nonnull ItemStack stack ) + public PocketServerComputer createServerComputer( final World world, IInventory inventory, Entity entity, @Nonnull ItemStack stack ) { if( world.isRemote ) return null; diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 06ad4fec8..45a641ca3 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -103,15 +103,6 @@ public final class ComputerCraftProxyCommon } */ - @SubscribeEvent - public static void onClientTick( TickEvent.ClientTickEvent event ) - { - if( event.phase == TickEvent.Phase.START ) - { - ComputerCraft.clientComputerRegistry.update(); - } - } - @SubscribeEvent public static void onServerTick( TickEvent.ServerTickEvent event ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 27330cdeb..c294a7d7e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.inventory; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; @@ -82,12 +81,10 @@ public class ContainerTurtle extends ContainerComputerBase private ContainerTurtle( int id, PlayerInventory player, ComputerContainerData data ) { - this( id, x -> true, - (player.player.world.isRemote - ? ComputerCraft.clientComputerRegistry - : ComputerCraft.serverComputerRegistry).get( data.getInstanceId() ), - data.getFamily(), - player, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) ); + this( + id, x -> true, getComputer( player, data ), data.getFamily(), + player, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) + ); } public int getSelectedSlot() diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/cable.json b/src/main/resources/data/computercraft/loot_tables/blocks/cable.json index 464c823b5..0bc4cd077 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/cable.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/cable.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "cable", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:cable" } @@ -16,6 +17,7 @@ ] }, { + "name": "wired_modem", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:wired_modem" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json index 7e55bfbab..4e5d283e1 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json index 7e55bfbab..4e5d283e1 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json index 888d1a551..53f9a6cfe 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json index 0cdc589b6..74fbfa470 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json @@ -2,11 +2,13 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:disk_drive" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] }, { + "name": "contents", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json index 0862a0591..f6f9710c5 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:monitor_advanced" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json index f487890e4..bff665f73 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:monitor_normal" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json index 00e2d6be4..11fb6a8fc 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json @@ -2,11 +2,13 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:printer" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] }, { + "name": "contents", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json b/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json index 6beed7b85..735c12a91 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:speaker" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json index 53be1b400..ed51e388f 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -2,12 +2,14 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] }, { + "name": "contents", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json index e7c25eb99..e44c9cbc7 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -2,10 +2,12 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] }, { + "name": "contents", "rolls": 1, "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json b/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json index fa6b9de17..9a8a883df 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:wired_modem_full" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json index 0672f78cf..00dae5bc8 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:wireless_modem_advanced" } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json index dad3722ec..cb88adee4 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json @@ -2,6 +2,7 @@ "type": "minecraft:block", "pools": [ { + "name": "main", "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:wireless_modem_normal" } From bc07dfad2ecb86853feaa92de7769d43f2c01c68 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 12 Jun 2019 21:03:11 +0100 Subject: [PATCH 015/711] Make sure all writeDescription methods are pure We don't want to be firing block updates or anything from here! That runs the ricks of causing CMEs and the like. Fixes #245 --- .../computercraft/shared/computer/blocks/TileComputerBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index c6f796ee4..f049ef940 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -453,7 +453,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT protected void writeDescription( @Nonnull NBTTagCompound nbt ) { super.writeDescription( nbt ); - nbt.setInteger( "instanceID", createServerComputer().getInstanceID() ); + if( m_instanceID >= 0 ) nbt.setInteger( "instanceID", m_instanceID ); if( m_label != null ) nbt.setString( "label", m_label ); if( m_computerID >= 0 ) nbt.setInteger( "computerID", m_computerID ); } From f3798bfb639192d50831e39a91c3f93a27b3f048 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 10 Jun 2019 15:31:38 +0200 Subject: [PATCH 016/711] Improve rename.lua's argument validation --- .../computercraft/lua/rom/programs/rename.lua | 9 ++++- .../test-rom/spec/programs/rename_spec.lua | 40 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/test-rom/spec/programs/rename_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua index f22561c26..4583adf62 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua @@ -7,8 +7,15 @@ end local sSource = shell.resolve( tArgs[1] ) local sDest = shell.resolve( tArgs[2] ) -if fs.exists( sDest ) then +if not fs.exists( sSource ) then + printError( "No matching files" ) + return +elseif fs.exists( sDest ) then printError( "Destination exists" ) + return +elseif fs.isReadOnly( sDest ) then + printError( "Destination is read-only" ) + return end fs.move( sSource, sDest ) diff --git a/src/test/resources/test-rom/spec/programs/rename_spec.lua b/src/test/resources/test-rom/spec/programs/rename_spec.lua new file mode 100644 index 000000000..2ab955dab --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/rename_spec.lua @@ -0,0 +1,40 @@ +local capture = require "test_helpers".capture_program + +describe("The rename program", function() + local function touch(file) + io.open(file, "w"):close() + end + + it("can rename a file", function() + touch("/test-files/rename/a.txt") + + shell.run("rename /test-files/rename/a.txt /test-files/rename/b.txt") + + expect(fs.exists("/test-files/rename/a.txt")):eq(false) + expect(fs.exists("/test-files/rename/b.txt")):eq(true) + end) + + it("fails when renaming a file which doesn't exist", function() + expect(capture(stub, "rename nothing destination")) + :matches { ok = true, output = "", error = "No matching files\n" } + end) + + it("fails when overwriting an existing file", function() + touch("/test-files/rename/c.txt") + + expect(capture(stub, "rename /test-files/rename/c.txt /test-files/rename/c.txt")) + :matches { ok = true, output = "", error = "Destination exists\n" } + end) + + it("fails when copying to read-only locations", function() + touch("/test-files/rename/d.txt") + + expect(capture(stub, "rename /test-files/rename/d.txt /rom/test.txt")) + :matches { ok = true, output = "", error = "Destination is read-only\n" } + end) + + it("displays the usage when given no arguments", function() + expect(capture(stub, "rename")) + :matches { ok = true, output = "Usage: rename \n", error = "" } + end) +end) From 81daf8264769b9c26b96f4b24b7b7144d173e9e7 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 10 Jun 2019 15:59:24 +0200 Subject: [PATCH 017/711] Add Checks to copy.lua --- .../computercraft/lua/rom/programs/copy.lua | 4 ++ .../test-rom/spec/programs/copy_spec.lua | 40 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/resources/test-rom/spec/programs/copy_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua index 8158b84a5..70cde52a1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua @@ -15,6 +15,10 @@ if #tFiles > 0 then elseif #tFiles == 1 then if fs.exists( sDest ) then printError( "Destination exists" ) + elseif fs.isReadOnly( sDest ) then + printError( "Destination is read-only" ) + elseif fs.getFreeSpace( sDest ) < fs.getSize( sFile ) then + printError( "Not enough space" ) else fs.copy( sFile, sDest ) end diff --git a/src/test/resources/test-rom/spec/programs/copy_spec.lua b/src/test/resources/test-rom/spec/programs/copy_spec.lua new file mode 100644 index 000000000..4ab043986 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/copy_spec.lua @@ -0,0 +1,40 @@ +local capture = require "test_helpers".capture_program + +describe("The copy program", function() + local function touch(file) + io.open(file, "w"):close() + end + + it("copies a file", function() + touch("/test-files/copy/a.txt") + + shell.run("copy /test-files/copy/a.txt /test-files/copy/b.txt") + + expect(fs.exists("/test-files/copy/a.txt")):eq(true) + expect(fs.exists("/test-files/copy/b.txt")):eq(true) + end) + + it("fails when copying a non-existent file", function() + expect(capture(stub, "copy nothing destination")) + :matches { ok = true, output = "", error = "No matching files\n" } + end) + + it("fails when overwriting an existing file", function() + touch("/test-files/copy/c.txt") + + expect(capture(stub, "copy /test-files/copy/c.txt /test-files/copy/c.txt")) + :matches { ok = true, output = "", error = "Destination exists\n" } + end) + + it("fails when copying into read-only locations", function() + touch("/test-files/copy/d.txt") + + expect(capture(stub, "copy /test-files/copy/d.txt /rom/test.txt")) + :matches { ok = true, output = "", error = "Destination is read-only\n" } + end) + + it("displays the usage when given no arguments", function() + expect(capture(stub, "copy")) + :matches { ok = true, output = "Usage: cp \n", error = "" } + end) +end) From 717ab690934276a2984cbe709550f960da932593 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Fri, 14 Jun 2019 09:15:12 +0200 Subject: [PATCH 018/711] Add a few Checks (#248) - Add some basic tests for several built-in programs. - Preserve the state of the shell between tests --- src/test/resources/test-rom/mcfly.lua | 4 + .../test-rom/spec/programs/cd_spec.lua | 20 +++++ .../test-rom/spec/programs/edit_spec.lua | 11 +++ .../spec/programs/http/pastebin_spec.lua | 77 +++++++++++++++++++ .../spec/{ => programs}/http/wget_spec.lua | 0 .../test-rom/spec/programs/id_spec.lua | 11 +++ .../test-rom/spec/programs/motd_spec.lua | 14 ++++ .../test-rom/spec/programs/move_spec.lua | 26 +++++++ .../test-rom/spec/programs/set_spec.lua | 29 +++++++ .../test-rom/spec/programs/shell_spec.lua | 4 + .../test-rom/spec/programs/time_spec.lua | 12 +++ .../test-rom/spec/programs/type_spec.lua | 26 +++++++ 12 files changed, 234 insertions(+) create mode 100644 src/test/resources/test-rom/spec/programs/cd_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/edit_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua rename src/test/resources/test-rom/spec/{ => programs}/http/wget_spec.lua (100%) create mode 100644 src/test/resources/test-rom/spec/programs/id_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/motd_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/move_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/set_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/time_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/type_spec.lua diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 02b4b26ed..38ebf9e83 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -49,6 +49,8 @@ local function push_state() term = term.current(), input = io.input(), output = io.output(), + dir = shell.dir(), + path = shell.path(), stubs = stubs, } end @@ -65,6 +67,8 @@ local function pop_state(state) term.redirect(state.term) io.input(state.input) io.output(state.output) + shell.setDir(state.dir) + shell.setPath(state.path) end local error_mt = { __tostring = function(self) return self.message end } diff --git a/src/test/resources/test-rom/spec/programs/cd_spec.lua b/src/test/resources/test-rom/spec/programs/cd_spec.lua new file mode 100644 index 000000000..2826b8007 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/cd_spec.lua @@ -0,0 +1,20 @@ +local capture = require "test_helpers".capture_program + +describe("The cd program", function() + + it("cd into a directory", function() + shell.run("cd /rom/programs") + + expect(shell.dir()):eq("rom/programs") + end) + + it("cd into a not existing directory", function() + expect(capture(stub, "cd /rom/nothing")) + :matches { ok = true, output = "Not a directory\n", error = "" } + end) + + it("displays the usage with no arguments", function() + expect(capture(stub, "cd")) + :matches { ok = true, output = "Usage: cd \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/edit_spec.lua b/src/test/resources/test-rom/spec/programs/edit_spec.lua new file mode 100644 index 000000000..dc8bcf9d0 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/edit_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The edit program", function() + + it("displays its usage when given no argument", function() + multishell = nil + + expect(capture(stub, "edit")) + :matches { ok = true, output = "Usage: edit \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua new file mode 100644 index 000000000..eb55f53d4 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -0,0 +1,77 @@ +local capture = require "test_helpers".capture_program + +describe("The pastebin program", function() + local function setup_request() + stub(_G, "http", { + checkURL = function() + return true + end, + get = function() + return { + readAll = function() + return [[print("Hello", ...)]] + end, + close = function() + end, + getResponseHeaders = function() + local tHeader = {} + tHeader["Content-Type"] = "text/plain; charset=utf-8" + return tHeader + end + } + end, + post = function() + return { + readAll = function() + return "https://pastebin.com/abcde" + end, + close = function() + end, + } + end + }) + end + + it("downloads one file", function() + setup_request() + capture(stub, "pastebin", "get", "abcde", "testdown") + + expect(fs.exists("/testdown")):eq(true) + end) + + it("runs a program from the internet", function() + setup_request() + + expect(capture(stub, "pastebin", "run", "abcde", "a", "b", "c")) + :matches { ok = true, output = "Connecting to pastebin.com... Success.\nHello a b c\n", error = "" } + end) + + it("upload a program to pastebin", function() + setup_request() + + local file = fs.open( "testup", "w" ) + file.close() + + expect(capture(stub, "pastebin", "put", "testup" )) + :matches { ok = true, output = "Connecting to pastebin.com... Success.\nUploaded as https://pastebin.com/abcde\nRun \"pastebin get abcde\" to download anywhere\n", error = "" } + end) + + it("upload a not existing program to pastebin", function() + setup_request() + + expect(capture(stub, "pastebin", "put", "nothing" )) + :matches { ok = true, output = "No such file\n", error = "" } + end) + + it("displays its usage when given no arguments", function() + setup_request() + + expect(capture(stub, "pastebin")) + :matches { ok = true, output = "Usages:\npastebin put \npastebin get \npastebin run \n", error = "" } + end) + + it("can be completed", function() + local complete = shell.getCompletionInfo()["rom/programs/http/pastebin.lua"].fnComplete + expect(complete(shell, 1, "", {})):same { "put ", "get ", "run " } + end) +end) diff --git a/src/test/resources/test-rom/spec/http/wget_spec.lua b/src/test/resources/test-rom/spec/programs/http/wget_spec.lua similarity index 100% rename from src/test/resources/test-rom/spec/http/wget_spec.lua rename to src/test/resources/test-rom/spec/programs/http/wget_spec.lua diff --git a/src/test/resources/test-rom/spec/programs/id_spec.lua b/src/test/resources/test-rom/spec/programs/id_spec.lua new file mode 100644 index 000000000..a4e4657d3 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/id_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The id program", function() + + it("displays computer id", function() + local id = os.getComputerID() + + expect(capture(stub, "id")) + :matches { ok = true, output = "This is computer #"..id.."\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/motd_spec.lua b/src/test/resources/test-rom/spec/programs/motd_spec.lua new file mode 100644 index 000000000..052cd8fa4 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/motd_spec.lua @@ -0,0 +1,14 @@ +local capture = require "test_helpers".capture_program + +describe("The motd program", function() + + it("displays MODT", function() + local file = fs.open("/modt_check.txt","w") + file.write("Hello World!") + file.close() + settings.set("motd.path","/modt_check.txt") + + expect(capture(stub, "motd")) + :matches { ok = true, output = "Hello World!\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/move_spec.lua b/src/test/resources/test-rom/spec/programs/move_spec.lua new file mode 100644 index 000000000..de1a36569 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/move_spec.lua @@ -0,0 +1,26 @@ +local capture = require "test_helpers".capture_program + +describe("The move program", function() + local function touch(file) + io.open(file, "w"):close() + end + + it("move a file", function() + touch("/test-files/move/a.txt") + + shell.run("move /test-files/move/a.txt /test-files/move/b.txt") + + expect(fs.exists("/test-files/move/a.txt")):eq(false) + expect(fs.exists("/test-files/move/b.txt")):eq(true) + end) + + it("try to move a not existing file", function() + expect(capture(stub, "move nothing destination")) + :matches { ok = true, output = "", error = "No matching files\n" } + end) + + it("displays the usage with no arguments", function() + expect(capture(stub, "move")) + :matches { ok = true, output = "Usage: mv \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/set_spec.lua b/src/test/resources/test-rom/spec/programs/set_spec.lua new file mode 100644 index 000000000..dc81dcfe3 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/set_spec.lua @@ -0,0 +1,29 @@ +local capture = require "test_helpers".capture_program + +describe("The set program", function() + + it("displays all settings", function() + settings.clear() + settings.set("Test","Hello World!") + settings.set("123",456) + + expect(capture(stub, "set")) + :matches { ok = true, output = '"123" is 456\n"Test" is "Hello World!"\n', error = "" } + end) + + it("displays a single settings", function() + settings.clear() + settings.set("Test","Hello World!") + settings.set("123",456) + + expect(capture(stub, "set Test")) + :matches { ok = true, output = '"Test" is "Hello World!"\n', error = "" } + end) + + it("set a setting", function() + expect(capture(stub, "set Test Hello")) + :matches { ok = true, output = '"Test" set to "Hello"\n', error = "" } + + expect(settings.get("Test")):eq("Hello") + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/shell_spec.lua b/src/test/resources/test-rom/spec/programs/shell_spec.lua index 9b9dc7188..cb35d70f6 100644 --- a/src/test/resources/test-rom/spec/programs/shell_spec.lua +++ b/src/test/resources/test-rom/spec/programs/shell_spec.lua @@ -27,6 +27,10 @@ describe("The shell", function() shell.setDir(shell.dir()) expect.error(shell.setDir, nil):eq("bad argument #1 (expected string, got nil)") end) + + it("not existing directory", function() + expect.error(shell.setDir, "/rom/nothing"):eq("Not a directory") + end) end) describe("shell.setPath", function() diff --git a/src/test/resources/test-rom/spec/programs/time_spec.lua b/src/test/resources/test-rom/spec/programs/time_spec.lua new file mode 100644 index 000000000..8ec10044e --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/time_spec.lua @@ -0,0 +1,12 @@ +local capture = require "test_helpers".capture_program + +describe("The time program", function() + + it("displays time", function() + local time = textutils.formatTime(os.time()) + local day = os.day() + + expect(capture(stub, "time")) + :matches { ok = true, output = "The time is "..time.." on Day "..day.."\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/type_spec.lua b/src/test/resources/test-rom/spec/programs/type_spec.lua new file mode 100644 index 000000000..78009c746 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/type_spec.lua @@ -0,0 +1,26 @@ +local capture = require "test_helpers".capture_program + +describe("The type program", function() + + it("displays the usage with no arguments", function() + expect(capture(stub, "type")) + :matches { ok = true, output = "Usage: type \n", error = "" } + end) + + it("displays the output for a file", function() + expect(capture(stub, "type /rom/startup.lua")) + :matches { ok = true, output = "file\n", error = "" } + end) + + it("displays the output for a directory", function() + expect(capture(stub, "type /rom")) + :matches { ok = true, output = "directory\n", error = "" } + end) + + it("displays the output for a not existing path", function() + expect(capture(stub, "type /rom/nothing")) + :matches { ok = true, output = "No such path\n", error = "" } + end) + +end) + From 29dce26bf62525ccca110c9c0dee91ec319be404 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 14 Jun 2019 20:55:32 +0100 Subject: [PATCH 019/711] Clean up checkstyle warning Fixes #251, closes #252 --- config/checkstyle/suppressions.xml | 4 --- .../shared/computer/blocks/TileComputer.java | 2 +- .../computer/blocks/TileComputerBase.java | 26 +++++++++---------- .../shared/turtle/blocks/TileTurtle.java | 2 +- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index a6dd2983d..0cafe14ef 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -3,10 +3,6 @@ "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" "https://checkstyle.org/dtds/suppressions_1_2.dtd"> - - - diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 210e15098..7769f174d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -32,7 +32,7 @@ public class TileComputer extends TileComputerBase ServerComputer computer = new ServerComputer( getWorld(), id, - m_label, + label, instanceID, family, ComputerCraft.terminalWidth_computer, diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index f049ef940..7034d91b7 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -47,7 +47,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { private int m_instanceID = -1; private int m_computerID = -1; - protected String m_label = null; + protected String label = null; private boolean m_on = false; boolean m_startOn = false; private boolean m_fresh = false; @@ -190,7 +190,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT m_fresh = false; m_computerID = computer.getID(); - m_label = computer.getLabel(); + label = computer.getLabel(); m_on = computer.isOn(); if( computer.hasOutputChanged() ) updateOutput(); @@ -212,9 +212,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { nbt.setInteger( "computerID", m_computerID ); } - if( m_label != null ) + if( label != null ) { - nbt.setString( "label", m_label ); + nbt.setString( "label", label ); } nbt.setBoolean( "on", m_on ); return super.writeToNBT( nbt ); @@ -248,7 +248,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT m_computerID = id; // Load label - m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; + label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; // Load power state m_startOn = nbt.getBoolean( "on" ); @@ -361,7 +361,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public final String getLabel() { - return m_label; + return label; } @Override @@ -378,9 +378,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public final void setLabel( String label ) { - if( getWorld().isRemote || Objects.equals( m_label, label ) ) return; + if( getWorld().isRemote || Objects.equals( this.label, label ) ) return; - m_label = label; + this.label = label; ServerComputer computer = getServerComputer(); if( computer != null ) computer.setLabel( label ); markDirty(); @@ -454,7 +454,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { super.writeDescription( nbt ); if( m_instanceID >= 0 ) nbt.setInteger( "instanceID", m_instanceID ); - if( m_label != null ) nbt.setString( "label", m_label ); + if( label != null ) nbt.setString( "label", label ); if( m_computerID >= 0 ) nbt.setInteger( "computerID", m_computerID ); } @@ -463,7 +463,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { super.readDescription( nbt ); m_instanceID = nbt.getInteger( "instanceID" ); - m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; + label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null; m_computerID = nbt.hasKey( "computerID" ) ? nbt.getInteger( "computerID" ) : -1; } @@ -474,7 +474,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT unload(); m_instanceID = copy.m_instanceID; m_computerID = copy.m_computerID; - m_label = copy.m_label; + label = copy.label; m_on = copy.m_on; m_startOn = copy.m_startOn; updateBlock(); @@ -493,13 +493,13 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public String getName() { - return hasCustomName() ? m_label : getBlockType().getTranslationKey(); + return hasCustomName() ? label : getBlockType().getTranslationKey(); } @Override public boolean hasCustomName() { - return !Strings.isNullOrEmpty( m_label ); + return !Strings.isNullOrEmpty( label ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index b96dd6868..353ce8d5d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -95,7 +95,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default protected ServerComputer createComputer( int instanceID, int id ) { ServerComputer computer = new ServerComputer( - getWorld(), id, m_label, instanceID, getFamily(), + getWorld(), id, label, instanceID, getFamily(), ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle ); computer.setPosition( getPos() ); From 761159aa9388202c8ec3c0d0999141c83e987479 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 15 Jun 2019 07:40:27 +0100 Subject: [PATCH 020/711] Bump Forge version --- gradle.properties | 4 ++-- .../computercraft/client/render/CableHighlightRenderer.java | 2 +- .../computercraft/client/render/MonitorHighlightRenderer.java | 2 +- .../computercraft/client/render/TileEntityTurtleRenderer.java | 3 +-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index 01a29a377..a77704960 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.83.1 # Minecraft properties mc_version=1.14.2 -forge_version=26.0.16 -mappings_version=20190609-1.14.2 +forge_version=26.0.25 +mappings_version=20190614-1.14.2 diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index f298a722b..ae73b59be 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -76,7 +76,7 @@ public final class CableHighlightRenderer ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); - Vec3d cameraPos = info.func_216785_c(); + Vec3d cameraPos = info.getProjectedView(); WorldRenderer.drawShape( shape, pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ(), 0.0F, 0.0F, 0.0F, 0.4F diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 8e313bb5a..326d5c81c 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -72,7 +72,7 @@ public final class MonitorHighlightRenderer GlStateManager.depthMask( false ); GlStateManager.pushMatrix(); - Vec3d cameraPos = event.getInfo().func_216785_c(); + Vec3d cameraPos = event.getInfo().getProjectedView(); GlStateManager.translated( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); Tessellator tessellator = Tessellator.getInstance(); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 72ba67090..76cd7d89f 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -94,8 +94,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer GameRenderer.drawNameplate( getFontRenderer(), label, (float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, - // yaw, pitch - rendererDispatcher.field_217666_g.func_216778_f(), rendererDispatcher.field_217666_g.func_216777_e(), false + rendererDispatcher.renderInfo.getYaw(), rendererDispatcher.renderInfo.getPitch(), false ); setLightmapDisabled( false ); } From 594bc4203c6470e624a5f5e5edb2436590d1706c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 15 Jun 2019 09:07:31 +0100 Subject: [PATCH 021/711] Fix block drops for computers and turtles --- .../computer/blocks/BlockComputerBase.java | 58 ++++++++++--------- .../data/BlockNamedEntityLootCondition.java | 44 ++++++++++++++ .../data/ConstantLootConditionSerializer.java | 43 ++++++++++++++ .../data/PlayerCreativeLootCondition.java | 44 ++++++++++++++ .../proxy/ComputerCraftProxyCommon.java | 17 ++++++ .../loot_tables/blocks/computer_advanced.json | 11 +++- .../loot_tables/blocks/computer_command.json | 11 +++- .../loot_tables/blocks/computer_normal.json | 11 +++- .../loot_tables/blocks/disk_drive.json | 6 -- .../loot_tables/blocks/printer.json | 6 -- .../loot_tables/blocks/turtle_advanced.json | 17 +++--- .../loot_tables/blocks/turtle_normal.json | 17 +++--- 12 files changed, 226 insertions(+), 59 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java create mode 100644 src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java create mode 100644 src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index fb738a8d4..975453553 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.computer.blocks; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.common.IBundledRedstoneBlock; @@ -16,19 +17,26 @@ import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.BlockState; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.IFluidState; import net.minecraft.item.ItemStack; +import net.minecraft.stats.Stats; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.IBlockReader; +import net.minecraft.world.ServerWorld; import net.minecraft.world.World; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.LootParameters; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public abstract class BlockComputerBase extends BlockGeneric implements IBundledRedstoneBlock { + private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" ); + private final ComputerFamily family; protected BlockComputerBase( Properties settings, ComputerFamily family, NamedTileEntityType type ) @@ -118,44 +126,40 @@ public abstract class BlockComputerBase extends Bloc return super.getPickBlock( state, target, world, pos, player ); } - /* TODO: THIS!! @Override - @Deprecated - public final void dropBlockAsItemWithChance( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, float change, int fortune ) + public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, BlockState state, @Nullable TileEntity tile, @Nonnull ItemStack tool ) { + // Don't drop blocks here - see onBlockHarvested. + player.addStat( Stats.BLOCK_MINED.get( this ) ); + player.addExhaustion( 0.005F ); } @Override - public final void getDrops( BlockState state, NonNullList drops, World world, BlockPos pos, int fortune ) + public void onBlockHarvested( World world, @Nonnull BlockPos pos, BlockState state, @Nonnull PlayerEntity player ) { + if( !(world instanceof ServerWorld) ) return; + + // We drop the item here instead of doing it in the harvest method, as we should + // drop computers for creative players too. + TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileComputerBase ) { - ItemStack stack = getItem( (TileComputerBase) tile ); - if( !stack.isEmpty() ) drops.add( stack ); - } - } - */ - - @Override - public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid ) - { - if( !world.isRemote ) - { - // We drop the item here instead of doing it in the harvest method, as we - // need to drop it for creative players too. - TileEntity tile = world.getTileEntity( pos ); - if( tile instanceof TileComputerBase ) + TileComputerBase computer = (TileComputerBase) tile; + LootContext.Builder context = new LootContext.Builder( (ServerWorld) world ) + .withRandom( world.rand ) + .withParameter( LootParameters.POSITION, pos ) + .withParameter( LootParameters.TOOL, player.getHeldItemMainhand() ) + .withParameter( LootParameters.THIS_ENTITY, player ) + .withNullableParameter( LootParameters.BLOCK_ENTITY, tile ) + .withDynamicDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) ); + for( ItemStack item : state.getDrops( context ) ) { - TileComputerBase computer = (TileComputerBase) tile; - if( !player.abilities.isCreativeMode || computer.getLabel() != null ) - { - spawnAsEntity( world, pos, getItem( computer ) ); - } + spawnAsEntity( world, pos, item ); } - } - return super.removedByPlayer( state, world, pos, player, willHarvest, fluid ); + state.spawnAdditionalDrops( world, pos, player.getHeldItemMainhand() ); + } } @Override diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java new file mode 100644 index 000000000..b8edf002c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -0,0 +1,44 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.data; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.INameable; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.LootParameter; +import net.minecraft.world.storage.loot.LootParameters; +import net.minecraft.world.storage.loot.conditions.ILootCondition; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Set; + +/** + * A loot condition which checks if the tile entity has a name. + */ +public final class BlockNamedEntityLootCondition implements ILootCondition +{ + public static final BlockNamedEntityLootCondition INSTANCE = new BlockNamedEntityLootCondition(); + + private BlockNamedEntityLootCondition() + { + } + + @Override + public boolean test( LootContext lootContext ) + { + TileEntity tile = lootContext.get( LootParameters.BLOCK_ENTITY ); + return tile instanceof INameable && ((INameable) tile).hasCustomName(); + } + + @Nonnull + @Override + public Set> getRequiredParameters() + { + return Collections.singleton( LootParameters.BLOCK_ENTITY ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java new file mode 100644 index 000000000..4649b4c08 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -0,0 +1,43 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.data; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.conditions.ILootCondition; + +import javax.annotation.Nonnull; + +public final class ConstantLootConditionSerializer extends ILootCondition.AbstractSerializer +{ + private final T instance; + + private ConstantLootConditionSerializer( ResourceLocation id, Class klass, T instance ) + { + super( id, klass ); + this.instance = instance; + } + + public static ILootCondition.AbstractSerializer of( ResourceLocation id, Class klass, T instance ) + { + return new ConstantLootConditionSerializer<>( id, klass, instance ); + } + + @Override + public void serialize( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context ) + { + } + + @Nonnull + @Override + public T deserialize( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context ) + { + return instance; + } +} diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java new file mode 100644 index 000000000..5c8d45c3b --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -0,0 +1,44 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.data; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.LootParameter; +import net.minecraft.world.storage.loot.LootParameters; +import net.minecraft.world.storage.loot.conditions.ILootCondition; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.Set; + +/** + * A loot condition which checks if the entity is in creative mode. + */ +public final class PlayerCreativeLootCondition implements ILootCondition +{ + public static final PlayerCreativeLootCondition INSTANCE = new PlayerCreativeLootCondition(); + + private PlayerCreativeLootCondition() + { + } + + @Override + public boolean test( LootContext lootContext ) + { + Entity entity = lootContext.get( LootParameters.THIS_ENTITY ); + return entity instanceof PlayerEntity && ((PlayerEntity) entity).abilities.isCreativeMode; + } + + @Nonnull + @Override + public Set> getRequiredParameters() + { + return Collections.singleton( LootParameters.THIS_ENTITY ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 45a641ca3..67fdc4b88 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -19,6 +19,9 @@ import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; +import dan200.computercraft.shared.data.ConstantLootConditionSerializer; +import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; @@ -29,6 +32,8 @@ import net.minecraft.item.Item; import net.minecraft.item.MusicDiscItem; import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.conditions.LootConditionManager; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; @@ -51,6 +56,18 @@ public final class ComputerCraftProxyCommon ArgumentSerializers.register(); + LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( + new ResourceLocation( ComputerCraft.MOD_ID, "block_named" ), + BlockNamedEntityLootCondition.class, + BlockNamedEntityLootCondition.INSTANCE + ) ); + + LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( + new ResourceLocation( ComputerCraft.MOD_ID, "player_creative" ), + PlayerCreativeLootCondition.class, + PlayerCreativeLootCondition.INSTANCE + ) ); + // if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register(); } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json index 4e5d283e1..26cde0f50 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -4,8 +4,15 @@ { "name": "main", "rolls": 1, - "entries": [ - { "type": "minecraft:dynamic", "name": "computercraft:computer" } + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], + "conditions": [ + { + "condition": "alternative", + "terms": [ + { "condition": "computercraft:block_named" }, + { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } + ] + } ] } ] diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json index 4e5d283e1..26cde0f50 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json @@ -4,8 +4,15 @@ { "name": "main", "rolls": 1, - "entries": [ - { "type": "minecraft:dynamic", "name": "computercraft:computer" } + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], + "conditions": [ + { + "condition": "alternative", + "terms": [ + { "condition": "computercraft:block_named" }, + { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } + ] + } ] } ] diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json index 53f9a6cfe..26cde0f50 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -4,7 +4,16 @@ { "name": "main", "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], + "conditions": [ + { + "condition": "alternative", + "terms": [ + { "condition": "computercraft:block_named" }, + { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } + ] + } + ] } ] } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json index 74fbfa470..6575281bb 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json @@ -6,12 +6,6 @@ "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:disk_drive" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] - }, - { - "name": "contents", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] } ] } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json index 11fb6a8fc..fff10863c 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json @@ -6,12 +6,6 @@ "rolls": 1, "entries": [ { "type": "minecraft:item", "name": "computercraft:printer" } ], "conditions": [ { "condition": "minecraft:survives_explosion" } ] - }, - { - "name": "contents", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] } ] } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json index ed51e388f..26cde0f50 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -4,15 +4,16 @@ { "name": "main", "rolls": 1, - "entries": [ - { "type": "minecraft:dynamic", "name": "computercraft:computer" } + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], + "conditions": [ + { + "condition": "alternative", + "terms": [ + { "condition": "computercraft:block_named" }, + { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } + ] + } ] - }, - { - "name": "contents", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] } ] } diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json index e44c9cbc7..26cde0f50 100644 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -4,13 +4,16 @@ { "name": "main", "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ] - }, - { - "name": "contents", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:contents" } ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] + "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], + "conditions": [ + { + "condition": "alternative", + "terms": [ + { "condition": "computercraft:block_named" }, + { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } + ] + } + ] } ] } From 68542aca3a6539a3dd1940722315f3f5baef476d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 15 Jun 2019 09:19:37 +0100 Subject: [PATCH 022/711] Fix cable breaking rendering Texture locations have changed a little --- .../render/TileEntityCableRenderer.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java index a6d7e6027..61b4844e5 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java @@ -24,6 +24,7 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.BlockRenderLayer; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; @@ -40,8 +41,17 @@ import java.util.Random; */ public class TileEntityCableRenderer extends TileEntityRenderer { + private static final ResourceLocation[] DESTROY_STAGES = new ResourceLocation[10]; private static final Random random = new Random(); + static + { + for( int i = 0; i < DESTROY_STAGES.length; i++ ) + { + DESTROY_STAGES[i] = new ResourceLocation( "block/destroy_stage_" + i ); + } + } + @Override public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage ) { @@ -57,8 +67,6 @@ public class TileEntityCableRenderer extends TileEntityRenderer return; } - if( ForgeHooksClient.getWorldRenderPass() != 0 ) return; - World world = te.getWorld(); BlockState state = world.getBlockState( pos ); Block block = state.getBlock(); @@ -72,15 +80,16 @@ public class TileEntityCableRenderer extends TileEntityRenderer preRenderDamagedBlocks(); + ForgeHooksClient.setRenderLayer( block.getRenderLayer() ); + + // See BlockRendererDispatcher#renderBlockDamage + TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] ); + BufferBuilder buffer = Tessellator.getInstance().getBuffer(); buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.BLOCK ); buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() ); buffer.noColor(); - ForgeHooksClient.setRenderLayer( block.getRenderLayer() ); - - // See BlockRendererDispatcher#renderBlockDamage - TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] ); mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel( world, ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos, 0 ), From f68ab3edd1cff3e0d4dd21a4c0c00cda684b8f07 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 15 Jun 2019 11:05:45 +0100 Subject: [PATCH 023/711] Minor tweaks to build script Mostly just rearranging. Bump JUnit version in an attempt to fix test outputs, but it appears this is a mix of gradle/gradle#5975 and gradle/gradle#4438. --- build.gradle | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/build.gradle b/build.gradle index 793175ac9..c5947bf18 100644 --- a/build.gradle +++ b/build.gradle @@ -78,12 +78,14 @@ dependencies { shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.0' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" } +// Compile tasks + javadoc { include "dan200/computercraft/api/**/*.java" } @@ -102,6 +104,14 @@ jar { from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) } } +[compileJava, compileTestJava].forEach { + it.configure { + options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror" + } +} + + + import java.nio.charset.StandardCharsets import java.nio.file.* import java.util.zip.* @@ -233,7 +243,14 @@ task compressJson(dependsOn: extractAnnotationsJar) { assemble.dependsOn compressJson -/* Check tasks */ +// Check tasks + +test { + useJUnitPlatform() + testLogging { + events "skipped", "failed" + } +} license { mapping("java", "SLASHSTAR_STYLE") @@ -257,6 +274,13 @@ license { } } +gradle.projectsEvaluated { + tasks.withType(LicenseFormat) { + outputs.upToDateWhen { false } + } +} + + task licenseAPI(type: LicenseCheck); task licenseFormatAPI(type: LicenseFormat); [licenseAPI, licenseFormatAPI].forEach { @@ -267,7 +291,7 @@ task licenseFormatAPI(type: LicenseFormat); } } -/* Upload tasks */ +// Upload tasks task checkRelease { group "upload" @@ -399,22 +423,5 @@ task uploadAll(dependsOn: uploadTasks) { description "Uploads to all repositories (Maven, Curse, GitHub release)" } -test { - useJUnitPlatform() - testLogging { - events "passed", "skipped", "failed" - } -} - -gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror" - } - - tasks.withType(LicenseFormat) { - outputs.upToDateWhen { false } - } -} - runClient.outputs.upToDateWhen { false } runServer.outputs.upToDateWhen { false } From 724441eddc7732cf50df17f7d30747ac11bb399c Mon Sep 17 00:00:00 2001 From: JakobDev Date: Fri, 21 Jun 2019 17:51:55 +0200 Subject: [PATCH 024/711] Change URLs in build.gradle to https (#259) --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index c5947bf18..e627e1959 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() maven { name = "forge" - url = "http://files.minecraftforge.net/maven" + url = "https://files.minecraftforge.net/maven" } } dependencies { @@ -45,7 +45,7 @@ minecraft { repositories { maven { name "JEI" - url "http://dvs1.progwml6.com/files/maven" + url "https://dvs1.progwml6.com/files/maven" } maven { name "SquidDev" @@ -57,7 +57,7 @@ repositories { } maven { name "Amadornes" - url "http://maven.amadornes.com/" + url "https://maven.amadornes.com/" } } From 904a168d5c1c4adc6a0ef3026a2570ea0dab9965 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 18:53:14 +0100 Subject: [PATCH 025/711] Fix incorrect explosion check We should block explosions if the turtle is advanced /or/ if it's from a fireball or entity, not if both. Fixes #257 --- .../dan200/computercraft/shared/turtle/blocks/BlockTurtle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 20a7de977..3e7a80698 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -218,7 +218,7 @@ public class BlockTurtle extends BlockComputerBase @Deprecated public float getExplosionResistance( Entity exploder ) { - if( getFamily() == ComputerFamily.Advanced && (exploder instanceof EntityLivingBase || exploder instanceof EntityFireball) ) + if( getFamily() == ComputerFamily.Advanced || exploder instanceof EntityLivingBase || exploder instanceof EntityFireball ) { return 2000; } From 5af789ae1133237c9837fcf38bd3e21a0300ca0b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 20:31:17 +0100 Subject: [PATCH 026/711] Bump Forge version --- README.md | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8ae888343..283cd4591 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Any contribution is welcome, be that using the mod, reporting bugs or contributi develop CC:T, you'll need to follow these steps: - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` - - **Setup Forge:** `./gradlew setupDecompWorkspace` + - **Setup Forge:** `./gradlew build` - **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE). If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`. diff --git a/gradle.properties b/gradle.properties index a77704960..2624b6173 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.83.1 # Minecraft properties mc_version=1.14.2 -forge_version=26.0.25 -mappings_version=20190614-1.14.2 +forge_version=26.0.35 +mappings_version=20190621-1.14.2 From 8fe2abe0aec53a40d9e68b8390652a5e4e530e83 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 20:31:28 +0100 Subject: [PATCH 027/711] Forward tab key directly to the terminal Fixes #256 --- .../computercraft/client/gui/GuiComputer.java | 13 +++++++++++++ .../dan200/computercraft/client/gui/GuiTurtle.java | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 159aba7c0..13a01b0ce 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -20,6 +20,7 @@ import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; +import org.lwjgl.glfw.GLFW; public final class GuiComputer extends ContainerScreen { @@ -109,6 +110,18 @@ public final class GuiComputer extends Containe terminal.update(); } + @Override + public boolean keyPressed( int key, int scancode, int modifiers ) + { + // Forward the tab key to the terminal, rather than moving between controls. + if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper ) + { + return getFocused().keyPressed( key, scancode, modifiers ); + } + + return super.keyPressed( key, scancode, modifiers ); + } + @Override public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 98ec8b647..7e80b05aa 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -17,6 +17,7 @@ import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; +import org.lwjgl.glfw.GLFW; public class GuiTurtle extends ContainerScreen { @@ -80,6 +81,18 @@ public class GuiTurtle extends ContainerScreen terminal.update(); } + @Override + public boolean keyPressed( int key, int scancode, int modifiers ) + { + // Forward the tab key to the terminal, rather than moving between controls. + if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper ) + { + return getFocused().keyPressed( key, scancode, modifiers ); + } + + return super.keyPressed( key, scancode, modifiers ); + } + private void drawSelectionSlot( boolean advanced ) { // Draw selection slot From b4aa554279afb1d24800be112d31bc2fee7f2163 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 20:57:38 +0100 Subject: [PATCH 028/711] Do not fetch the current block within onLoad The chunk has not been fully loaded when onLoad is called, which means we try to load it again, and so the server deadlocks. --- .../shared/peripheral/modem/wired/TileCable.java | 6 +----- .../shared/peripheral/modem/wired/TileWiredModemFull.java | 2 +- .../shared/peripheral/modem/wireless/TileWirelessModem.java | 3 +-- .../shared/peripheral/monitor/TileMonitor.java | 3 ++- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 247eb75e0..9d69e2c72 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -170,11 +170,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile public void onLoad() { super.onLoad(); - if( !world.isRemote ) - { - updateDirection(); - world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 ); - } + TickScheduler.schedule( this ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 13b68cb18..7a87978e8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -251,7 +251,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile public void onLoad() { super.onLoad(); - if( !world.isRemote ) world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 ); + TickScheduler.schedule( this ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 9da297f52..8778e13d7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -87,8 +87,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile public void onLoad() { super.onLoad(); - updateDirection(); - world.getPendingBlockTicks().scheduleTick( getPos(), getBlockState().getBlock(), 0 ); + TickScheduler.schedule( this ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 923fb0c0e..aebf63543 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -14,6 +14,7 @@ import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.util.NamedTileEntityType; +import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -78,7 +79,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile public void onLoad() { super.onLoad(); - world.getPendingBlockTicks().scheduleTick( getPos(), getBlockState().getBlock(), 0 ); + TickScheduler.schedule( this ); } @Override From 0741daa7ebbdb368ab723cc5e2d7cbc0ffbef054 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 21:01:40 +0100 Subject: [PATCH 029/711] Fix usage of a client-only method Should probably run forge-lint on this at some point, but it's a good start. Fixes #255 --- .../shared/computer/blocks/TileComputerBase.java | 5 ++++- .../shared/peripheral/diskdrive/TileDiskDrive.java | 3 ++- .../computercraft/shared/peripheral/printer/TilePrinter.java | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index a5c1c6cbc..e0a6da47d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -38,6 +38,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -413,7 +414,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public ITextComponent getName() { - return hasCustomName() ? new StringTextComponent( label ) : getBlockState().getBlock().getNameTextComponent(); + return hasCustomName() + ? new StringTextComponent( label ) + : new TranslationTextComponent(getBlockState().getBlock().getTranslationKey()); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index e98d812d4..c650decfc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -33,6 +33,7 @@ import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fml.network.NetworkHooks; @@ -580,7 +581,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Override public ITextComponent getName() { - return customName != null ? customName : getBlockState().getBlock().getNameTextComponent(); + return customName != null ? customName : new TranslationTextComponent(getBlockState().getBlock().getTranslationKey()); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index bfeed2829..206040c81 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -29,6 +29,7 @@ import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fml.network.NetworkHooks; @@ -573,7 +574,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Override public ITextComponent getName() { - return customName != null ? customName : getBlockState().getBlock().getNameTextComponent(); + return customName != null ? customName : new TranslationTextComponent(getBlockState().getBlock().getTranslationKey()); } @Override From 3052506e2ee9319ec02e128476614e5245d0f3f9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 21:32:02 +0100 Subject: [PATCH 030/711] Reload configs from the file --- src/main/java/dan200/computercraft/shared/Config.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 0a24dc502..c5a93c2a5 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared; +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.google.common.base.CaseFormat; import com.google.common.base.Converter; import dan200.computercraft.ComputerCraft; @@ -325,6 +327,10 @@ public final class Config @SubscribeEvent public static void sync( ModConfig.ConfigReloading event ) { + // Ensure file configs are reloaded. Forge should probably do this, so worth checking in the future. + CommentedConfig config = event.getConfig().getConfigData(); + if( config instanceof CommentedFileConfig ) ((CommentedFileConfig) config).load(); + sync(); } From 42220c4268682a14d800be150670db208ba390d0 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 21:32:15 +0100 Subject: [PATCH 031/711] Fix several other client-only methods --- .../shared/peripheral/diskdrive/TileDiskDrive.java | 2 +- .../shared/peripheral/speaker/SpeakerPeripheral.java | 2 +- src/main/java/dan200/computercraft/shared/util/WorldUtil.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index c650decfc..a2715d432 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -503,7 +503,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory double y = pos.getY() + 0.75; double z = pos.getZ() + 0.5 + zOff * 0.5; ItemEntity entityitem = new ItemEntity( getWorld(), x, y, z, disks ); - entityitem.setVelocity( xOff * 0.15, 0, zOff * 0.15 ); + entityitem.setMotion( xOff * 0.15, 0, zOff * 0.15 ); getWorld().addEntity( entityitem ); if( !destroyed ) getWorld().playBroadcastSound( 1000, getPos(), 0 ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 1bb93aa84..766a17eee 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -120,7 +120,7 @@ public abstract class SpeakerPeripheral implements IPeripheral } // If the resource location for note block notes changes, this method call will need to be updated - boolean success = playSound( context, instrument.getSound().getName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); + boolean success = playSound( context, instrument.getSound().getRegistryName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); if( success ) m_notesThisTick.incrementAndGet(); return new Object[] { success }; diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 85d881f95..7f7e77981 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -172,7 +172,7 @@ public final class WorldUtil public static void dropItemStack( @Nonnull ItemStack stack, World world, double xPos, double yPos, double zPos, double xDir, double yDir, double zDir ) { ItemEntity item = new ItemEntity( world, xPos, yPos, zPos, stack.copy() ); - item.setVelocity( + item.setMotion( xDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1, yDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1, zDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1 From 13cb789c18d35171c4cb6980e22f796fb337a367 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 21:51:22 +0100 Subject: [PATCH 032/711] Fix "can deploy" check being entirely incorrect Closes #258 --- .../shared/turtle/core/TurtlePlaceCommand.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index b1896cec2..7fb8e3a43 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -290,9 +290,8 @@ public class TurtlePlaceCommand implements ITurtleCommand private static boolean canDeployOnBlock( @Nonnull BlockItemUseContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, Direction side, boolean allowReplaceable, String[] outErrorMessage ) { World world = turtle.getWorld(); - if( World.isValid( position ) && - !world.isAirBlock( position ) && - !(context.getItem().getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) ) + if( !World.isValid( position ) || world.isAirBlock( position ) || + (context.getItem().getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) ) { return false; } @@ -315,7 +314,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } } - return context.canPlace(); + return true; } @Nonnull From 772c54ec74f3f3a0be0f135492c06b1598e11fd4 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 21 Jun 2019 22:00:21 +0100 Subject: [PATCH 033/711] Copy the item stack before merging Otherwise we would mutate the stack, and so the current mount was considered empty. Closes #240 (though would be nice to improve this). --- .../shared/peripheral/diskdrive/ContainerDiskDrive.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index dcef9ae3d..df9c0069d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -63,7 +63,7 @@ public class ContainerDiskDrive extends Container Slot slot = inventorySlots.get( slotIndex ); if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY; - ItemStack existing = slot.getStack(); + ItemStack existing = slot.getStack().copy(); ItemStack result = existing.copy(); if( slotIndex == 0 ) { From f1e551b96011e2ae8fb1f93a31f9e2b4ff450a86 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 23 Jun 2019 15:30:29 +0100 Subject: [PATCH 034/711] Bump Forge version Turtle models now work (though texture registration is still broken). --- gradle.properties | 2 +- src/main/java/dan200/computercraft/client/ClientRegistry.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2624b6173..5acb12d7c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.83.1 # Minecraft properties mc_version=1.14.2 -forge_version=26.0.35 +forge_version=26.0.55 mappings_version=20190621-1.14.2 diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index d8cd382a6..22bc90878 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -34,7 +34,7 @@ import java.util.Map; /** * Registers textures and models for items. */ -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class ClientRegistry { private static final String[] EXTRA_MODELS = new String[] { @@ -91,7 +91,7 @@ public final class ClientRegistry { // Load all extra models ModelLoader loader = event.getModelLoader(); - Map registry = event.getModelRegistry(); + Map registry = event.getModelRegistry(); for( String model : EXTRA_MODELS ) { From 6ea8ca991b4725437300af206fbeaedb259b0c01 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 26 Jun 2019 08:25:32 +0100 Subject: [PATCH 035/711] Bump Forge to 1.14.3 Guess it's time for another release? --- gradle.properties | 6 +++--- .../shared/computer/blocks/TileCommandComputer.java | 5 +++-- .../shared/computer/blocks/TileComputerBase.java | 2 +- .../shared/peripheral/diskdrive/TileDiskDrive.java | 2 +- .../shared/peripheral/printer/TilePrinter.java | 2 +- src/main/resources/META-INF/mods.toml | 4 ++-- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5acb12d7c..b6ea6fe23 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.83.1 # Minecraft properties -mc_version=1.14.2 -forge_version=26.0.55 -mappings_version=20190621-1.14.2 +mc_version=1.14.3 +forge_version=27.0.3 +mappings_version=20190626-1.14.3 diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index dcd476592..1a689ded3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -22,6 +22,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.GameRules; import net.minecraft.world.ServerWorld; import javax.annotation.Nonnull; @@ -63,7 +64,7 @@ public class TileCommandComputer extends TileComputer @Override public boolean shouldReceiveFeedback() { - return getWorld().getGameRules().getBoolean( "sendCommandFeedback" ); + return getWorld().getGameRules().getBoolean( GameRules.SEND_COMMAND_FEEDBACK ); } @Override @@ -75,7 +76,7 @@ public class TileCommandComputer extends TileComputer @Override public boolean allowLogging() { - return getWorld().getGameRules().getBoolean( "commandBlockOutput" ); + return getWorld().getGameRules().getBoolean( GameRules.COMMAND_BLOCK_OUTPUT ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index e0a6da47d..cdadb3c3c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -416,7 +416,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { return hasCustomName() ? new StringTextComponent( label ) - : new TranslationTextComponent(getBlockState().getBlock().getTranslationKey()); + : new TranslationTextComponent( getBlockState().getBlock().getTranslationKey() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index a2715d432..72d3c634f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -581,7 +581,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Override public ITextComponent getName() { - return customName != null ? customName : new TranslationTextComponent(getBlockState().getBlock().getTranslationKey()); + return customName != null ? customName : new TranslationTextComponent( getBlockState().getBlock().getTranslationKey() ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 206040c81..98a22fb35 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -574,7 +574,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Override public ITextComponent getName() { - return customName != null ? customName : new TranslationTextComponent(getBlockState().getBlock().getTranslationKey()); + return customName != null ? customName : new TranslationTextComponent( getBlockState().getBlock().getTranslationKey() ); } @Override diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index ff246ba74..0e40894ea 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[26,)" +loaderVersion="[27,28)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[26,)" + versionRange="[27,28)" ordering="NONE" side="BOTH" From 95aa48c456f1aefbe85861104e266d77aa8f5823 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 29 Jun 2019 15:37:41 +0100 Subject: [PATCH 036/711] Allow running expectations against stubbed functions Co-authored-by: hydraz --- src/test/resources/test-rom/mcfly.lua | 116 +++++++++++++++++++++++--- 1 file changed, 105 insertions(+), 11 deletions(-) diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 38ebf9e83..05c88b58e 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -27,18 +27,52 @@ local function check(func, arg, ty, val) end end +--- A stub - wraps a value within a a table, +local stub_mt = {} +stub_mt.__index = stub_mt + +--- Revert this stub, restoring the previous value. +-- +-- Note, a stub can only be reverted once. +function stub_mt:revert() + if not self.active then return end + + self.active = false + rawset(self.stubbed_in, self.key, self.original) +end + local active_stubs = {} ---- Stub a global variable with a specific value +--- Stub a table entry with a new value. -- --- @tparam string var The variable to stub --- @param value The value to stub it with -local function stub(tbl, var, value) +-- @tparam table +-- @tparam string key The variable to stub +-- @param value The value to stub it with. If this is a function, one can use +-- the various stub expectation methods to determine what it was called with. +-- @treturn Stub The resulting stub +local function stub(tbl, key, value) check('stub', 1, 'table', tbl) - check('stub', 2, 'string', var) + check('stub', 2, 'string', key) - table.insert(active_stubs, { tbl = tbl, var = var, value = tbl[var] }) - rawset(tbl, var, value) + local stub = setmetatable({ + active = true, + stubbed_in = tbl, + key = key, + original = rawget(tbl, key), + }, stub_mt) + + if type(value) == "function" then + local arguments, delegate = {}, value + stub.arguments = arguments + value = function(...) + arguments[#arguments + 1] = table.pack(...) + return delegate(value) + end + end + + table.insert(active_stubs, stub) + rawset(tbl, key, value) + return stub end --- Capture the current global state of the computer @@ -57,10 +91,7 @@ end --- Restore the global state of the computer to a previous version local function pop_state(state) - for i = #active_stubs, 1, -1 do - local stub = active_stubs[i] - rawset(stub.tbl, stub.var, stub.value) - end + for i = #active_stubs, 1, -1 do active_stubs[i]:revert() end active_stubs = state.stubs @@ -210,6 +241,16 @@ local function matches(eq, exact, left, right) return true end +local function pairwise_equal(left, right) + if left.n ~= right.n then return false end + + for i = 1, left.n do + if left[i] ~= right[i] then return false end + end + + return true +end + --- Assert that this expectation is structurally equivalent to -- the provided object. -- @@ -236,6 +277,59 @@ function expect_mt:matches(value) return self end +--- Assert that this stub was called a specific number of times. +-- +-- @tparam[opt] number The exact number of times the function must be called. +-- If not given just require the function to be called at least once. +-- @raises If this function was not called the expected number of times. +function expect_mt:called(times) + if getmetatable(self.value) ~= stub_mt or self.value.arguments == nil then + fail(("Expected stubbed function, got %s"):format(type(self.value))) + end + + local called = #self.value.arguments + + if times == nil then + if called == 0 then + fail("Expected stub to be called\nbut it was not.") + end + else + check('stub', 1, 'number', times) + if called ~= times then + fail(("Expected stub to be called %d times\nbut was called %d times."):format(times, called)) + end + end + + return self +end + +--- Assert that this stub was called with a set of arguments +-- +-- Arguments are compared using exact equality. +function expect_mt:called_with(...) + if getmetatable(self.value) ~= stub_mt or self.value.arguments == nil then + fail(("Expected stubbed function, got %s"):format(type(self.value))) + end + + local exp_args = table.pack(...) + local actual_args = self.value.arguments + for i = 1, #actual_args do + if pairwise_equal(actual_args[i], exp_args) then return self end + end + + local head = ("Expected stub to be called with %s\nbut was"):format(format(exp_args)) + if #actual_args == 0 then + fail(head .. " not called at all") + elseif #actual_args == 1 then + fail(("%s called with %s."):format(head, format(actual_args[1]))) + else + local lines = { head .. " called with:" } + for i = 1, #actual_args do lines[i + 1] = " - " .. format(actual_args[i]) end + + fail(table.concat(lines, "\n")) + end +end + local expect = setmetatable( { --- Construct an expectation on the error message calling this function -- produces From 7a3f7d3bba43e0350406ad64b5827e8d0e9bc133 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 29 Jun 2019 15:44:53 +0100 Subject: [PATCH 037/711] I'm a muppet Even worse, I enabled branch protection for some reason, and so can't force push and pretend this never happened. --- src/test/resources/test-rom/mcfly.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 05c88b58e..228ce332d 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -66,7 +66,7 @@ local function stub(tbl, key, value) stub.arguments = arguments value = function(...) arguments[#arguments + 1] = table.pack(...) - return delegate(value) + return delegate(...) end end From 18068effec61c2130e59f08b76803695b83e69f9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 5 Jul 2019 21:50:43 +0100 Subject: [PATCH 038/711] Use reflection to get the record's sound getSound is client side only - I could have sworn it became shared at some point, but that may have been reverted again (or I imagined it). Fixes #263 --- .../shared/media/items/RecordMedia.java | 25 ++++++++++++++++--- .../computercraft/shared/util/RecordUtil.java | 14 ----------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 243f57625..1f92bb1b6 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -6,11 +6,16 @@ package dan200.computercraft.shared.media.items; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.media.IMedia; -import dan200.computercraft.shared.util.RecordUtil; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.MusicDiscItem; import net.minecraft.util.SoundEvent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper.UnableToAccessFieldException; +import net.minecraftforge.fml.common.ObfuscationReflectionHelper.UnableToFindFieldException; import javax.annotation.Nonnull; @@ -34,12 +39,26 @@ public final class RecordMedia implements IMedia @Override public String getAudioTitle( @Nonnull ItemStack stack ) { - return RecordUtil.getRecordInfo( stack ); + Item item = stack.getItem(); + if( !(item instanceof MusicDiscItem) ) return null; + + return new TranslationTextComponent( item.getTranslationKey() + ".desc" ).getString(); } @Override public SoundEvent getAudio( @Nonnull ItemStack stack ) { - return ((MusicDiscItem) stack.getItem()).getSound(); + Item item = stack.getItem(); + if( !(item instanceof MusicDiscItem) ) return null; + + try + { + return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "field_185076_b" ); + } + catch( UnableToAccessFieldException | UnableToFindFieldException e ) + { + ComputerCraft.log.error( "Cannot get disk sound", e ); + return null; + } } } diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index ba04109ce..627012878 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -9,17 +9,11 @@ package dan200.computercraft.shared.util; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.PlayRecordClientMessage; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.MusicDiscItem; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; -import javax.annotation.Nonnull; - public final class RecordUtil { private RecordUtil() {} @@ -29,12 +23,4 @@ public final class RecordUtil NetworkMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos ); NetworkHandler.sendToAllAround( packet, world, new Vec3d( pos ), 64 ); } - - public static String getRecordInfo( @Nonnull ItemStack recordStack ) - { - Item item = recordStack.getItem(); - if( !(item instanceof MusicDiscItem) ) return null; - - return new TranslationTextComponent( item.getTranslationKey() + ".desc" ).getString(); - } } From 9d51c4c340d17d9abea99791fee5c6ebddfc56bf Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 5 Jul 2019 22:09:42 +0100 Subject: [PATCH 039/711] Use world-specific collider entity This is equally an ugly hack, but means we're at least not constructing entities with null worlds any more. Ideally we could always use the turtle entity, but this will require a bit more of a refactor. Fixes #265 --- .../computercraft/shared/util/WorldUtil.java | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index 7f7e77981..25252f3d4 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.util; import com.google.common.base.Predicate; +import com.google.common.collect.MapMaker; import net.minecraft.block.BlockState; import net.minecraft.entity.*; import net.minecraft.entity.item.ItemEntity; @@ -20,25 +21,35 @@ import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; import java.util.List; +import java.util.Map; public final class WorldUtil { @SuppressWarnings( "Guava" ) private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.canBeCollidedWith(); - private static final Entity ENTITY = new ItemEntity( EntityType.ITEM, null ) - { - @Override - public EntitySize getSize( Pose pose ) - { - return EntitySize.fixed( 0, 0 ); - } - }; + private static final Map entityCache = new MapMaker().weakKeys().weakValues().makeMap(); - static + private static synchronized Entity getEntity( World world ) { - ENTITY.noClip = true; - ENTITY.recalculateSize(); + // TODO: It'd be nice if we could avoid this. Maybe always use the turtle player (if it's available). + Entity entity = entityCache.get( world ); + if( entity != null ) return entity; + + entity = new ItemEntity( EntityType.ITEM, world ) + { + @Nonnull + @Override + public EntitySize getSize( Pose pose ) + { + return EntitySize.fixed( 0, 0 ); + } + }; + + entity.noClip = true; + entity.recalculateSize(); + entityCache.put( world, entity ); + return entity; } public static boolean isLiquidBlock( World world, BlockPos pos ) @@ -61,8 +72,9 @@ public final class WorldUtil Vec3d vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); // Raycast for blocks - ENTITY.setPosition( vecStart.x, vecStart.y, vecStart.z ); - RayTraceContext context = new RayTraceContext( vecStart, vecEnd, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, ENTITY ); + Entity collisionEntity = getEntity( world ); + collisionEntity.setPosition( vecStart.x, vecStart.y, vecStart.z ); + RayTraceContext context = new RayTraceContext( vecStart, vecEnd, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, collisionEntity ); RayTraceResult result = world.rayTraceBlocks( context ); if( result != null && result.getType() == RayTraceResult.Type.BLOCK ) { From acfb72246c5341c104f7b4d86d4373f98869798a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 7 Jul 2019 15:52:52 +0100 Subject: [PATCH 040/711] Bump JEI version --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 7f8f4cc7c..ada301a77 100644 --- a/build.gradle +++ b/build.gradle @@ -94,11 +94,11 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.13.2:5.0.0.20:api") + compileOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7:api") // deobfProvided "pl.asie:Charset-Lib:0.5.4.6" // deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" - // runtimeOnly fg.deobf("mezz.jei:jei-1.13.2:5.0.0.20") + runtimeOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7") shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' From e05c262468faa07905660c91f3295c45641ed355 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 8 Jul 2019 10:24:05 +0200 Subject: [PATCH 041/711] Add more tests (#253) I'm not entirely sure how useful all of these will be yet - still trying to work out what/when to test things, but hopefully this'll be a useful datapoint. --- .luacheckrc | 3 +- src/test/resources/test-rom/mcfly.lua | 42 +++++++-- .../spec/programs/advanced/bg_spec.lua | 11 +++ .../spec/programs/advanced/fg_spec.lua | 11 +++ .../test-rom/spec/programs/alias_spec.lua | 28 ++++++ .../test-rom/spec/programs/cd_spec.lua | 15 ++-- .../test-rom/spec/programs/clear_spec.lua | 13 +++ .../spec/programs/command/commands_spec.lua | 20 +++++ .../spec/programs/command/exec_spec.lua | 33 +++++++ .../test-rom/spec/programs/drive_spec.lua | 16 ++++ .../test-rom/spec/programs/edit_spec.lua | 5 +- .../test-rom/spec/programs/eject_spec.lua | 13 +++ .../test-rom/spec/programs/exit_spec.lua | 9 ++ .../spec/programs/fun/advanced/paint_spec.lua | 8 ++ .../test-rom/spec/programs/fun/dj_spec.lua | 13 +++ .../test-rom/spec/programs/fun/hello_spec.lua | 10 +++ .../test-rom/spec/programs/gps_spec.lua | 23 +++++ .../test-rom/spec/programs/help_spec.lua | 8 ++ .../test-rom/spec/programs/label_spec.lua | 34 +++++++ .../test-rom/spec/programs/list_spec.lua | 22 +++++ .../test-rom/spec/programs/monitor_spec.lua | 8 ++ .../spec/programs/peripherals_spec.lua | 8 ++ .../spec/programs/pocket/equip_spec.lua | 27 ++++++ .../spec/programs/pocket/unequip_spec.lua | 27 ++++++ .../test-rom/spec/programs/programs_spec.lua | 14 +++ .../test-rom/spec/programs/reboot_spec.lua | 14 +++ .../test-rom/spec/programs/redstone_spec.lua | 8 ++ .../test-rom/spec/programs/shutdown_spec.lua | 15 ++++ .../spec/programs/turtle/craft_spec.lua | 69 ++++++++++++++ .../spec/programs/turtle/equip_spec.lua | 89 +++++++++++++++++++ .../spec/programs/turtle/refuel_spec.lua | 62 +++++++++++++ .../spec/programs/turtle/unequip_spec.lua | 69 ++++++++++++++ 32 files changed, 727 insertions(+), 20 deletions(-) create mode 100644 src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/alias_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/clear_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/command/commands_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/command/exec_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/drive_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/eject_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/exit_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/fun/dj_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/fun/hello_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/gps_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/help_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/label_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/list_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/monitor_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/peripherals_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/programs_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/reboot_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/redstone_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/shutdown_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua create mode 100644 src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua diff --git a/.luacheckrc b/.luacheckrc index 71b0f872c..3bf2c2c41 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -17,7 +17,8 @@ ignore = { -- are largely unsupported. include_files = { 'src/main/resources/assets/computercraft/lua/rom', - 'src/main/resources/assets/computercraft/lua/bios.lua' + 'src/main/resources/assets/computercraft/lua/bios.lua', + 'src/test/resources/test-rom', } files['src/main/resources/assets/computercraft/lua/bios.lua'] = { diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 228ce332d..4275102ad 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -43,14 +43,18 @@ end local active_stubs = {} +local function default_stub() end + --- Stub a table entry with a new value. -- -- @tparam table -- @tparam string key The variable to stub --- @param value The value to stub it with. If this is a function, one can use --- the various stub expectation methods to determine what it was called with. +-- @param[opt] value The value to stub it with. If this is a function, one can +-- use the various stub expectation methods to determine what it was called +-- with. Defaults to an empty function - pass @{nil} in explicitly to set the +-- value to nil. -- @treturn Stub The resulting stub -local function stub(tbl, key, value) +local function stub(tbl, key, ...) check('stub', 1, 'table', tbl) check('stub', 2, 'string', key) @@ -61,6 +65,8 @@ local function stub(tbl, key, value) original = rawget(tbl, key), }, stub_mt) + local value = ... + if select('#', ...) == 0 then value = default_stub end if type(value) == "function" then local arguments, delegate = {}, value stub.arguments = arguments @@ -85,6 +91,7 @@ local function push_state() output = io.output(), dir = shell.dir(), path = shell.path(), + aliases = shell.aliases(), stubs = stubs, } end @@ -100,6 +107,14 @@ local function pop_state(state) io.output(state.output) shell.setDir(state.dir) shell.setPath(state.path) + + local aliases = shell.aliases() + for k in pairs(aliases) do + if not state.aliases[k] then shell.clearAlias(k) end + end + for k, v in pairs(state.aliases) do + if aliases[k] ~= v then shell.setAlias(k, v) end + end end local error_mt = { __tostring = function(self) return self.message end } @@ -303,10 +318,7 @@ function expect_mt:called(times) return self end ---- Assert that this stub was called with a set of arguments --- --- Arguments are compared using exact equality. -function expect_mt:called_with(...) +local function called_with_check(eq, self, ...) if getmetatable(self.value) ~= stub_mt or self.value.arguments == nil then fail(("Expected stubbed function, got %s"):format(type(self.value))) end @@ -314,7 +326,7 @@ function expect_mt:called_with(...) local exp_args = table.pack(...) local actual_args = self.value.arguments for i = 1, #actual_args do - if pairwise_equal(actual_args[i], exp_args) then return self end + if eq(actual_args[i], exp_args) then return self end end local head = ("Expected stub to be called with %s\nbut was"):format(format(exp_args)) @@ -330,6 +342,20 @@ function expect_mt:called_with(...) end end +--- Assert that this stub was called with a set of arguments +-- +-- Arguments are compared using exact equality. +function expect_mt:called_with(...) + return called_with_check(pairwise_equal, self, ...) +end + +--- Assert that this stub was called with a set of arguments +-- +-- Arguments are compared using matching. +function expect_mt:called_with_matching(...) + return called_with_check(matches, self, ...) +end + local expect = setmetatable( { --- Construct an expectation on the error message calling this function -- produces diff --git a/src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua b/src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua new file mode 100644 index 000000000..a53dc2f2d --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/advanced/bg_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The bg program", function() + it("opens a tab in the background", function() + local openTab = stub(shell, "openTab", function() return 12 end) + local switchTab = stub(shell, "switchTab") + capture(stub, "bg") + expect(openTab):called_with("shell") + expect(switchTab):called(0) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua b/src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua new file mode 100644 index 000000000..8e5cc4f26 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/advanced/fg_spec.lua @@ -0,0 +1,11 @@ +local capture = require "test_helpers".capture_program + +describe("The fg program", function() + it("opens the shell in the foreground", function() + local openTab = stub(shell, "openTab", function() return 12 end) + local switchTab = stub(shell, "switchTab") + capture(stub, "fg") + expect(openTab):called_with("shell") + expect(switchTab):called_with(12) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/alias_spec.lua b/src/test/resources/test-rom/spec/programs/alias_spec.lua new file mode 100644 index 000000000..95a2c2556 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/alias_spec.lua @@ -0,0 +1,28 @@ +local capture = require "test_helpers".capture_program + +describe("The alias program", function() + it("displays its usage when given too many arguments", function() + expect(capture(stub, "alias a b c")) + :matches { ok = true, output = "Usage: alias \n", error = "" } + end) + + it("lists aliases", function() + local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) + stub(shell, "aliases", function() return { cp = "copy" } end) + expect(capture(stub, "alias")) + :matches { ok = true, output = "cp:copy\n", error = "" } + expect(pagedTabulate):called_with_matching({ "cp:copy" }) + end) + + it("sets an alias", function() + local setAlias = stub(shell, "setAlias") + capture(stub, "alias test Hello") + expect(setAlias):called_with("test", "Hello") + end) + + it("clears an alias", function() + local clearAlias = stub(shell, "clearAlias") + capture(stub, "alias test") + expect(clearAlias):called_with("test") + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/cd_spec.lua b/src/test/resources/test-rom/spec/programs/cd_spec.lua index 2826b8007..348d62944 100644 --- a/src/test/resources/test-rom/spec/programs/cd_spec.lua +++ b/src/test/resources/test-rom/spec/programs/cd_spec.lua @@ -1,19 +1,18 @@ local capture = require "test_helpers".capture_program describe("The cd program", function() - - it("cd into a directory", function() - shell.run("cd /rom/programs") - - expect(shell.dir()):eq("rom/programs") + it("changes into a directory", function() + local setDir = stub(shell, "setDir") + capture(stub, "cd /rom/programs") + expect(setDir):called_with("rom/programs") end) - it("cd into a not existing directory", function() + it("does not move into a non-existent directory", function() expect(capture(stub, "cd /rom/nothing")) :matches { ok = true, output = "Not a directory\n", error = "" } end) - - it("displays the usage with no arguments", function() + + it("displays the usage when given no arguments", function() expect(capture(stub, "cd")) :matches { ok = true, output = "Usage: cd \n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/clear_spec.lua b/src/test/resources/test-rom/spec/programs/clear_spec.lua new file mode 100644 index 000000000..f339c83ce --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/clear_spec.lua @@ -0,0 +1,13 @@ +local capture = require "test_helpers".capture_program + +describe("The clear program", function() + it("clears the screen", function() + local clear = stub(term, "clear") + local setCursorPos = stub(term, "setCursorPos") + + capture(stub, "clear") + + expect(clear):called(1) + expect(setCursorPos):called_with(1, 1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/command/commands_spec.lua b/src/test/resources/test-rom/spec/programs/command/commands_spec.lua new file mode 100644 index 000000000..d7261b9d1 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/command/commands_spec.lua @@ -0,0 +1,20 @@ +local capture = require "test_helpers".capture_program + +describe("The commands program", function() + it("displays an error without the commands api", function() + stub(_G, "commands", nil) + expect(capture(stub, "/rom/programs/command/commands.lua")) + :matches { ok = true, output = "", error = "Requires a Command Computer.\n" } + end) + + it("lists commands", function() + local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) + stub(_G, "commands", { + list = function() return { "computercraft" } end + }) + + expect(capture(stub, "/rom/programs/command/commands.lua")) + :matches { ok = true, output = "Available commands:\ncomputercraft\n", error = "" } + expect(pagedTabulate):called_with_matching({ "computercraft" }) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua new file mode 100644 index 000000000..869222b2c --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua @@ -0,0 +1,33 @@ +local capture = require "test_helpers".capture_program + +describe("The exec program", function() + it("displays an error without the commands api", function() + stub(_G, "commands", nil) + expect(capture(stub, "/rom/programs/command/exec.lua")) + :matches { ok = true, output = "", error = "Requires a Command Computer.\n" } + end) + + it("displays its usage when given no argument", function() + stub(_G, "commands", {}) + expect(capture(stub, "/rom/programs/command/exec.lua")) + :matches { ok = true, output = "", error = "Usage: exec \n" } + end) + + it("runs a command", function() + stub(_G, "commands", { + exec = function() return true, {"Hello World!"} end + }) + + expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) + :matches { ok = true, output = "Success\nHello World!\n", error = "" } + end) + + it("reports command failures", function() + stub(_G,"commands",{ + exec = function() return false, {"Hello World!"} end + }) + + expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) + :matches { ok = true, output = "Hello World!\n", error = "Failed\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/drive_spec.lua b/src/test/resources/test-rom/spec/programs/drive_spec.lua new file mode 100644 index 000000000..d175a60f7 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/drive_spec.lua @@ -0,0 +1,16 @@ +local capture = require "test_helpers".capture_program + +describe("The drive program", function() + it("run the program", function() + local getFreeSpace = stub(fs, "getFreeSpace", function() return 1234e4 end) + + expect(capture(stub, "drive")) + :matches { ok = true, output = "hdd (12.3MB remaining)\n", error = "" } + expect(getFreeSpace):called(1):called_with("") + end) + + it("fails on a non-existent path", function() + expect(capture(stub, "drive /rom/nothing")) + :matches { ok = true, output = "No such path\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/edit_spec.lua b/src/test/resources/test-rom/spec/programs/edit_spec.lua index dc8bcf9d0..137c39c83 100644 --- a/src/test/resources/test-rom/spec/programs/edit_spec.lua +++ b/src/test/resources/test-rom/spec/programs/edit_spec.lua @@ -1,10 +1,9 @@ local capture = require "test_helpers".capture_program +local testFile = require "test_helpers".testFile describe("The edit program", function() - it("displays its usage when given no argument", function() - multishell = nil - + it("displays its usage when given no argument", function() expect(capture(stub, "edit")) :matches { ok = true, output = "Usage: edit \n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/eject_spec.lua b/src/test/resources/test-rom/spec/programs/eject_spec.lua new file mode 100644 index 000000000..e524a8625 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/eject_spec.lua @@ -0,0 +1,13 @@ +local capture = require "test_helpers".capture_program + +describe("The eject program", function() + it("displays its usage when given no argument", function() + expect(capture(stub, "eject")) + :matches { ok = true, output = "Usage: eject \n", error = "" } + end) + + it("fails when trying to eject a non-drive", function() + expect(capture(stub, "eject /rom")) + :matches { ok = true, output = "Nothing in /rom drive\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/exit_spec.lua b/src/test/resources/test-rom/spec/programs/exit_spec.lua new file mode 100644 index 000000000..301461087 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/exit_spec.lua @@ -0,0 +1,9 @@ +local capture = require "test_helpers".capture_program + +describe("The exit program", function() + it("exits the shell", function() + local exit = stub(shell, "exit") + expect(capture(stub, "exit")):matches { ok = true, combined = "" } + expect(exit):called(1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua b/src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua new file mode 100644 index 000000000..086404add --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/fun/advanced/paint_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The paint program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "paint")) + :matches { ok = true, output = "Usage: paint \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/fun/dj_spec.lua b/src/test/resources/test-rom/spec/programs/fun/dj_spec.lua new file mode 100644 index 000000000..4464d4e8c --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/fun/dj_spec.lua @@ -0,0 +1,13 @@ +local capture = require "test_helpers".capture_program + +describe("The dj program", function() + it("displays its usage when given too many arguments", function() + expect(capture(stub, "dj a b c")) + :matches { ok = true, output = "Usages:\ndj play\ndj play \ndj stop\n", error = "" } + end) + + it("fails when no disks are present", function() + expect(capture(stub, "dj")) + :matches { ok = true, output = "No Music Discs in attached disk drives\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/fun/hello_spec.lua b/src/test/resources/test-rom/spec/programs/fun/hello_spec.lua new file mode 100644 index 000000000..25db085bc --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/fun/hello_spec.lua @@ -0,0 +1,10 @@ +local capture = require "test_helpers".capture_program + +describe("The hello program", function() + it("says hello", function() + local slowPrint = stub(textutils, "slowPrint", function(...) return print(...) end) + expect(capture(stub, "hello")) + :matches { ok = true, output = "Hello World!\n", error = "" } + expect(slowPrint):called(1) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/gps_spec.lua b/src/test/resources/test-rom/spec/programs/gps_spec.lua new file mode 100644 index 000000000..245f259c9 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/gps_spec.lua @@ -0,0 +1,23 @@ +local capture = require "test_helpers".capture_program + +describe("The gps program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "gps")) + :matches { ok = true, output = "Usages:\ngps host\ngps host \ngps locate\n", error = "" } + end) + + it("fails on a pocket computer", function() + stub(_G, "pocket", {}) + + expect(capture(stub, "gps host")) + :matches { ok = true, output = "GPS Hosts must be stationary\n", error = "" } + end) + + it("can locate the computer", function() + local locate = stub(gps, "locate", function() print("Some debugging information.") end) + + expect(capture(stub, "gps locate")) + :matches { ok = true, output = "Some debugging information.\n", error = "" } + expect(locate):called_with(2, true) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/help_spec.lua b/src/test/resources/test-rom/spec/programs/help_spec.lua new file mode 100644 index 000000000..79e4e4742 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/help_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The help program", function() + it("errors when there is no such help file", function() + expect(capture(stub, "help nothing")) + :matches { ok = true, output = "No help available\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/label_spec.lua b/src/test/resources/test-rom/spec/programs/label_spec.lua new file mode 100644 index 000000000..5762f8fbe --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/label_spec.lua @@ -0,0 +1,34 @@ +local capture = require "test_helpers".capture_program + +describe("The label program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "label")) + :matches { ok = true, output = "Usages:\nlabel get\nlabel get \nlabel set \nlabel set \nlabel clear\nlabel clear \n", error = "" } + end) + + describe("displays the computer's label", function() + it("when it is not labelled", function() + stub(os, "getComputerLabel", function() return nil end) + expect(capture(stub, "label get")) + :matches { ok = true, output = "No Computer label\n", error = "" } + end) + + it("when it is labelled", function() + stub(os, "getComputerLabel", function() return "Test" end) + expect(capture(stub, "label get")) + :matches { ok = true, output = "Computer label is \"Test\"\n", error = "" } + end) + end) + + it("sets the computer's label", function() + local setComputerLabel = stub(os, "setComputerLabel") + capture(stub, "label set Test") + expect(setComputerLabel):called_with("Test") + end) + + it("clears the computer's label", function() + local setComputerLabel = stub(os, "setComputerLabel") + capture(stub, "label clear") + expect(setComputerLabel):called_with(nil) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/list_spec.lua b/src/test/resources/test-rom/spec/programs/list_spec.lua new file mode 100644 index 000000000..f9f5f0b0b --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/list_spec.lua @@ -0,0 +1,22 @@ +local capture = require "test_helpers".capture_program + +describe("The list program", function() + it("lists files", function() + local pagedTabulate = stub(textutils, "pagedTabulate") + capture(stub, "list /rom") + expect(pagedTabulate):called_with_matching( + colors.green, { "apis", "autorun", "help", "modules", "programs" }, + colors.white, { "motd.txt", "startup.lua" } + ) + end) + + it("fails on a non-existent directory", function() + expect(capture(stub, "list /rom/nothing")) + :matches { ok = true, output = "", error = "Not a directory\n" } + end) + + it("fails on a file", function() + expect(capture(stub, "list /rom/startup.lua")) + :matches { ok = true, output = "", error = "Not a directory\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/monitor_spec.lua b/src/test/resources/test-rom/spec/programs/monitor_spec.lua new file mode 100644 index 000000000..04fbb613a --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/monitor_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The monitor program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "monitor")) + :matches { ok = true, output = "Usage: monitor \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua new file mode 100644 index 000000000..f52961a13 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The peripherals program", function() + it("says when there are no peripherals", function() + expect(capture(stub, "peripherals" )) + :matches { ok = true, output = "Attached Peripherals:\nNone\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua b/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua new file mode 100644 index 000000000..0c3fb3183 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua @@ -0,0 +1,27 @@ +local capture = require "test_helpers".capture_program + +describe("The pocket equip program", function() + it("errors when not a pocket computer", function() + stub(_G, "pocket", nil) + expect(capture(stub, "/rom/programs/pocket/equip.lua")) + :matches { ok = true, output = "", error = "Requires a Pocket Computer\n" } + end) + + it("can equip an upgrade", function() + stub(_G, "pocket", { + equipBack = function() return true end + }) + + expect(capture(stub, "/rom/programs/pocket/equip.lua")) + :matches { ok = true, output = "Item equipped\n", error = "" } + end) + + it("handles when an upgrade cannot be equipped", function() + stub(_G, "pocket", { + equipBack = function() return false, "Cannot equip this item." end + }) + + expect(capture(stub, "/rom/programs/pocket/equip.lua")) + :matches { ok = true, output = "", error = "Cannot equip this item.\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua new file mode 100644 index 000000000..85a1e640f --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua @@ -0,0 +1,27 @@ +local capture = require "test_helpers".capture_program + +describe("The pocket unequip program", function() + it("errors when not a pocket computer", function() + stub(_G, "pocket", nil) + expect(capture(stub, "/rom/programs/pocket/unequip.lua")) + :matches { ok = true, output = "", error = "Requires a Pocket Computer\n" } + end) + + it("unequips an upgrade", function() + stub(_G, "pocket", { + unequipBack = function() return true end + }) + + expect(capture(stub, "/rom/programs/pocket/unequip.lua")) + :matches { ok = true, output = "Item unequipped\n", error = "" } + end) + + it("handles when an upgrade cannot be equipped", function() + stub(_G, "pocket", { + unequipBack = function() return false, "Nothing to remove." end + }) + + expect(capture(stub, "/rom/programs/pocket/unequip.lua")) + :matches { ok = true, output = "", error = "Nothing to remove.\n" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/programs_spec.lua b/src/test/resources/test-rom/spec/programs/programs_spec.lua new file mode 100644 index 000000000..8f19bc83e --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/programs_spec.lua @@ -0,0 +1,14 @@ +local capture = require "test_helpers".capture_program + +describe("The programs program", function() + it("list programs", function() + local programs = stub(shell, "programs", function() return { "some", "programs" } end) + local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) + + expect(capture(stub, "/rom/programs/programs.lua")) + :matches { ok = true, output = "some programs\n", error = "" } + + expect(programs):called_with(false) + expect(pagedTabulate):called_with_matching({ "some", "programs" }) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/reboot_spec.lua b/src/test/resources/test-rom/spec/programs/reboot_spec.lua new file mode 100644 index 000000000..d2a877d9d --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/reboot_spec.lua @@ -0,0 +1,14 @@ +local capture = require "test_helpers".capture_program + +describe("The reboot program", function() + it("sleeps and then reboots", function() + local sleep = stub(_G, "sleep") + local reboot = stub(os, "reboot") + + expect(capture(stub, "reboot")) + :matches { ok = true, output = "Goodbye\n", error = "" } + + expect(sleep):called_with(1) + expect(reboot):called() + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/redstone_spec.lua b/src/test/resources/test-rom/spec/programs/redstone_spec.lua new file mode 100644 index 000000000..fc687ac7e --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/redstone_spec.lua @@ -0,0 +1,8 @@ +local capture = require "test_helpers".capture_program + +describe("The redstone program", function() + it("displays its usage when given no arguments", function() + expect(capture(stub, "redstone")) + :matches { ok = true, output = "Usages:\nredstone probe\nredstone set \nredstone set \nredstone pulse \n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/shutdown_spec.lua b/src/test/resources/test-rom/spec/programs/shutdown_spec.lua new file mode 100644 index 000000000..4cfa37ba1 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/shutdown_spec.lua @@ -0,0 +1,15 @@ +local capture = require "test_helpers".capture_program + +describe("The shutdown program", function() + + it("run the program", function() + local sleep = stub(_G, "sleep") + local shutdown = stub(os, "shutdown") + + expect(capture(stub, "shutdown")) + :matches { ok = true, output = "Goodbye\n", error = "" } + + expect(sleep):called_with(1) + expect(shutdown):called() + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua new file mode 100644 index 000000000..43b7ea982 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua @@ -0,0 +1,69 @@ +local capture = require "test_helpers".capture_program + +describe("The craft program", function() + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/craft.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + it("fails when turtle.craft() is unavailable", function() + stub(_G, "turtle", {}) + + expect(capture(stub, "/rom/programs/turtle/craft.lua")) + :matches { ok = true, output = "Requires a Crafty Turtle\n", error = "" } + end) + + it("displays its usage when given no arguments", function() + stub(_G, "turtle", { craft = function() end }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua")) + :matches { ok = true, output = "Usage: craft [number]\n", error = "" } + end) + + it("crafts multiple items", function() + local item_count = 3 + stub(_G, "turtle", { + craft = function() + item_count = 1 + return true + end, + getItemCount = function() return item_count end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua 2")) + :matches { ok = true, output = "2 items crafted\n", error = "" } + end) + + it("craft a single item", function() + local item_count = 2 + stub(_G,"turtle",{ + craft = function() + item_count = 1 + return true + end, + getItemCount = function() return item_count end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua 1")) + :matches { ok = true, output = "1 item crafted\n", error = "" } + end) + + it("crafts no items", function() + local item_count = 2 + stub(_G,"turtle",{ + craft = function() + item_count = 1 + return false + end, + getItemCount = function() return item_count end, + getSelectedSlot = function() return 1 end, + }) + + expect(capture(stub, "/rom/programs/turtle/craft.lua 1")) + :matches { ok = true, output = "No items crafted\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua new file mode 100644 index 000000000..2e637fc82 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua @@ -0,0 +1,89 @@ +local capture = require "test_helpers".capture_program + +describe("The turtle equip program", function() + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/equip.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + + it("displays its usage when given no arguments", function() + stub(_G, "turtle", {}) + + expect(capture(stub, "/rom/programs/turtle/equip.lua")) + :matches { ok = true, output = "Usage: equip \n", error = "" } + end) + + it("equip nothing", function() + stub(_G, "turtle", { + select = function() end, + getItemCount = function() return 0 end, + }) + + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Nothing to equip\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Nothing to equip\n", error = "" } + end) + + it("swaps existing upgrades", function() + stub(_G,"turtle",{ + select = function() end, + getItemCount = function() return 1 end, + equipLeft = function() return true end, + equipRight = function() return true end, + }) + + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Items swapped\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Items swapped\n", error = "" } + end) + + describe("equips a new upgrade", function() + local function setup() + local item_count = 1 + stub(_G,"turtle",{ + select = function() end, + getItemCount = function() return item_count end, + equipLeft = function() + item_count = 0 + return true + end, + equipRight = function() + item_count = 0 + return true + end, + }) + end + + it("on the left", function() + setup() + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Item equipped\n", error = "" } + end) + + it("on the right", function() + setup() + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Item equipped\n", error = "" } + end) + end) + + it("handles when an upgrade cannot be equipped", function() + stub(_G,"turtle",{ + select = function() end, + getItemCount = function() return 1 end, + equipLeft = function() return false end, + equipRight = function() return false end, + }) + + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left")) + :matches { ok = true, output = "Item not equippable\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right")) + :matches { ok = true, output = "Item not equippable\n", error = "" } + end) + +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua new file mode 100644 index 000000000..3b6283260 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua @@ -0,0 +1,62 @@ +local capture = require "test_helpers".capture_program + +describe("The refuel program", function() + local function setup_turtle(fuel_level, fuel_limit, item_count) + stub(_G, "turtle", { + getFuelLevel = function() + return fuel_level + end, + getItemCount = function() + return item_count + end, + refuel = function(nLimit) + item_count = item_count - nLimit + fuel_level = fuel_level + nLimit + end, + select = function() + end, + getFuelLimit = function() + return fuel_limit + end + }) + end + + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/refuel.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + + it("displays its usage when given too many argument", function() + setup_turtle(0, 5, 0) + expect(capture(stub, "/rom/programs/turtle/refuel.lua a b")) + :matches { ok = true, output = "Usage: refuel [number]\n", error = "" } + end) + + it("requires a numeric argument", function() + setup_turtle(0, 0, 0) + expect(capture(stub, "/rom/programs/turtle/refuel.lua nothing")) + :matches { ok = true, output = "Invalid limit, expected a number or \"all\"\n", error = "" } + end) + + it("refuels the turtle", function() + setup_turtle(0, 10, 5) + + expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) + :matches { ok = true, output = "Fuel level is 5\n", error = "" } + end) + + it("reports when the fuel limit is reached", function() + setup_turtle(0,5,5) + expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) + :matches { ok = true, output = "Fuel level is 5\nFuel limit reached\n", error = "" } + end) + + it("reports when the fuel level is unlimited", function() + setup_turtle("unlimited",5,5) + expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) + :matches { ok = true, output = "Fuel level is unlimited\n", error = "" } + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua new file mode 100644 index 000000000..1cb97b440 --- /dev/null +++ b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua @@ -0,0 +1,69 @@ +local capture = require "test_helpers".capture_program + +describe("The turtle unequip program", function() + it("errors when not a turtle", function() + stub(_G, "turtle", nil) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua")) + :matches { ok = true, output = "", error = "Requires a Turtle\n" } + end) + + + it("displays its usage when given no arguments", function() + stub(_G, "turtle", {}) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua")) + :matches { ok = true, output = "Usage: unequip \n", error = "" } + end) + + it("says when nothing was unequipped", function() + stub(_G,"turtle",{ + select = function() end, + getItemCount = function() return 0 end, + equipRight = function() return true end, + equipLeft = function() return true end + }) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) + :matches { ok = true, output = "Nothing to unequip\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/unequip.lua right")) + :matches { ok = true, output = "Nothing to unequip\n", error = "" } + end) + + it("unequips a upgrade", function() + local item_count = 0 + stub(_G,"turtle",{ + select = function() end, + getItemCount = function() return item_count end, + equipRight = function() + item_count = 1 + return true + end, + equipLeft = function() + item_count = 1 + return true + end + }) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) + :matches { ok = true, output = "Item unequipped\n", error = "" } + item_count = 0 + expect(capture(stub, "/rom/programs/turtle/unequip.lua right")) + :matches { ok = true, output = "Item unequipped\n", error = "" } + end) + + it("fails when the turtle is full", function() + stub(_G,"turtle",{ + select = function() end, + getItemCount = function() return 1 end, + equipRight = function() return true end, + equipLeft = function() return true end + }) + + expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) + :matches { ok = true, output = "No space to unequip item\n", error = "" } + expect(capture(stub, "/rom/programs/turtle/unequip.lua right")) + :matches { ok = true, output = "No space to unequip item\n", error = "" } + end) + +end) From bafab1ac073e82ae4601e29921defa9c2986ebda Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 9 Jul 2019 08:04:49 +0100 Subject: [PATCH 042/711] Expose expect as a module (#267) This moves expect from the bios into a new craftos.expect module, removing the internal _G["~expect"] definition. Apparently people were using this irrespective of the "don't use this" comment, so we need to find another solution. While this does introduce some ugliness (having to load the module in weird ways for programs, duplicating the expect function in memory), it does allow people to use the function in a supported way, and removes the global ugliness. --- .../assets/computercraft/lua/bios.lua | 51 ++++--------------- .../computercraft/lua/rom/apis/colors.lua | 2 +- .../assets/computercraft/lua/rom/apis/gps.lua | 2 +- .../computercraft/lua/rom/apis/help.lua | 2 +- .../assets/computercraft/lua/rom/apis/io.lua | 2 +- .../computercraft/lua/rom/apis/keys.lua | 2 +- .../computercraft/lua/rom/apis/paintutils.lua | 2 +- .../computercraft/lua/rom/apis/peripheral.lua | 2 +- .../computercraft/lua/rom/apis/rednet.lua | 2 +- .../computercraft/lua/rom/apis/settings.lua | 2 +- .../computercraft/lua/rom/apis/term.lua | 2 +- .../computercraft/lua/rom/apis/textutils.lua | 2 +- .../computercraft/lua/rom/apis/window.lua | 2 +- .../lua/rom/modules/main/craftos/expect.lua | 46 +++++++++++++++++ .../lua/rom/programs/advanced/multishell.lua | 2 +- .../computercraft/lua/rom/programs/shell.lua | 2 +- .../resources/test-rom/spec/base_spec.lua | 32 ------------ .../test-rom/spec/modules/expect_spec.lua | 31 +++++++++++ 18 files changed, 102 insertions(+), 86 deletions(-) create mode 100644 src/main/resources/assets/computercraft/lua/rom/modules/main/craftos/expect.lua create mode 100644 src/test/resources/test-rom/spec/modules/expect_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 5f24d94cb..7b8b6b030 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -1,48 +1,19 @@ -local native_select, native_type = select, type - ---- Expect an argument to have a specific type. +-- Load in expect from the module path. -- --- @tparam int index The 1-based argument index. --- @param value The argument's value. --- @tparam string ... The allowed types of the argument. --- @throws If the value is not one of the allowed types. -local function expect(index, value, ...) - local t = native_type(value) - for i = 1, native_select("#", ...) do - if t == native_select(i, ...) then return true end - end +-- Ideally we'd use require, but that is part of the shell, and so is not +-- available to the BIOS or any APIs. All APIs load this using dofile, but that +-- has not been defined at this point. +local expect - local types = table.pack(...) - for i = types.n, 1, -1 do - if types[i] == "nil" then table.remove(types, i) end - end +do + local h = fs.open("rom/modules/main/craftos/expect.lua", "r") + local f, err = loadstring(h.readAll(), "@expect.lua") + h.close() - local type_names - if #types <= 1 then - type_names = tostring(...) - else - type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] - end - - -- If we can determine the function name with a high level of confidence, try to include it. - local name - if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then - local ok, info = pcall(debug.getinfo, 3, "nS") - if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end - end - - if name then - error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 ) - else - error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 ) - end + if not f then error(err) end + expect = f().expect end --- We expose expect in the global table as APIs need to access it, but give it --- a non-identifier name - meaning it does not show up in auto-completion. --- expect is an internal function, and should not be used by users. -_G["~expect"] = expect - if _VERSION == "Lua 5.1" then -- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it local type = type diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua index c113d324a..bf3444724 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect -- Colors white = 1 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index d27ba1beb..b36e0b79a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect CHANNEL_GPS = 65534 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index 63ca4d1d6..fd9b22289 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local sPath = "/rom/help" diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index cd8a02acb..b50c724bf 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -1,6 +1,6 @@ -- Definition for the IO API -local expect, typeOf = _G["~expect"], _G.type +local expect, typeOf = dofile("rom/modules/main/craftos/expect.lua").expect, _G.type --- If we return nil then close the file, as we've reached the end. -- We use this weird wrapper function as we wish to preserve the varargs diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua index 6a7e035d9..b4b3daccd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua @@ -1,7 +1,7 @@ -- Minecraft key code bindings -- See http://www.minecraftwiki.net/wiki/Key_codes for more info -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local tKeys = { nil, "one", "two", "three", "four", -- 1 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index fe475a6fa..a0a028aac 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local function drawPixelInternal( xPos, yPos ) term.setCursorPos( xPos, yPos ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index c34a59eb8..4b6fee2dc 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local native = peripheral diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index 8867e4caf..84a20c0cb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect CHANNEL_BROADCAST = 65535 CHANNEL_REPEAT = 65533 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 3290a03d3..68f2ba2d7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local tSettings = {} diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index d93c3f367..baaeccf25 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local native = (term.native and term.native()) or term local redirectTarget = native diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index ba9f5e033..05f32117c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect function slowWrite( sText, nRate ) expect(2, nRate, "number", "nil") diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 6d9ab38ec..d3ecf0915 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local tHex = { [ colors.white ] = "0", diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/craftos/expect.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/craftos/expect.lua new file mode 100644 index 000000000..14db7231c --- /dev/null +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/craftos/expect.lua @@ -0,0 +1,46 @@ +--- The @{craftos.expect} library provides helper functions for verifying that +-- function arguments are well-formed and of the correct type. +-- +-- @module craftos.expect + +local native_select, native_type = select, type + +--- Expect an argument to have a specific type. +-- +-- @tparam int index The 1-based argument index. +-- @param value The argument's value. +-- @tparam string ... The allowed types of the argument. +-- @throws If the value is not one of the allowed types. +local function expect(index, value, ...) + local t = native_type(value) + for i = 1, native_select("#", ...) do + if t == native_select(i, ...) then return true end + end + + local types = table.pack(...) + for i = types.n, 1, -1 do + if types[i] == "nil" then table.remove(types, i) end + end + + local type_names + if #types <= 1 then + type_names = tostring(...) + else + type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] + end + + -- If we can determine the function name with a high level of confidence, try to include it. + local name + if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then + local ok, info = pcall(debug.getinfo, 3, "nS") + if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end + end + + if name then + error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 ) + else + error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 ) + end +end + +return { expect = expect } diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index 00988eb27..9bca4b166 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect -- Setup process switching local parentTerm = term.current() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index bc95dbf2e..08c7e515e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -1,4 +1,4 @@ -local expect = _G["~expect"] +local expect = dofile("rom/modules/main/craftos/expect.lua").expect local multishell = multishell local parentShell = shell diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua index 191d87eab..4713bfc64 100644 --- a/src/test/resources/test-rom/spec/base_spec.lua +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -1,36 +1,4 @@ describe("The Lua base library", function() - describe("expect", function() - local e = _G["~expect"] - - it("checks a single type", function() - expect(e(1, "test", "string")):eq(true) - expect(e(1, 2, "number")):eq(true) - - expect.error(e, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)") - expect.error(e, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)") - end) - - it("checks multiple types", function() - expect(e(1, "test", "string", "number")):eq(true) - expect(e(1, 2, "string", "number")):eq(true) - - expect.error(e, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)") - expect.error(e, 2, false, "string", "table", "number", "nil") - :eq("bad argument #2 (expected string, table or number, got boolean)") - end) - - it("includes the function name", function() - local function worker() - expect(e(1, nil, "string")):eq(true) - end - local function trampoline() - worker() - end - - expect.error(trampoline):eq("base_spec.lua:27: bad argument #1 to 'worker' (expected string, got nil)") - end) - end) - describe("sleep", function() it("validates arguments", function() sleep(0) diff --git a/src/test/resources/test-rom/spec/modules/expect_spec.lua b/src/test/resources/test-rom/spec/modules/expect_spec.lua new file mode 100644 index 000000000..6b6aa77c0 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/expect_spec.lua @@ -0,0 +1,31 @@ +describe("craftos.expect", function() + local e = require("craftos.expect") + + it("checks a single type", function() + expect(e.expect(1, "test", "string")):eq(true) + expect(e.expect(1, 2, "number")):eq(true) + + expect.error(e.expect, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)") + expect.error(e.expect, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)") + end) + + it("checks multiple types", function() + expect(e.expect(1, "test", "string", "number")):eq(true) + expect(e.expect(1, 2, "string", "number")):eq(true) + + expect.error(e.expect, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)") + expect.error(e.expect, 2, false, "string", "table", "number", "nil") + :eq("bad argument #2 (expected string, table or number, got boolean)") + end) + + it("includes the function name", function() + local function worker() + expect(e.expect(1, nil, "string")):eq(true) + end + local function trampoline() + worker() + end + + expect.error(trampoline):eq("expect_spec.lua:26: bad argument #1 to 'worker' (expected string, got nil)") + end) +end) From f9929cb27d4f9cf7efa9ebfd3fb6caa047b0f278 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 12 Jul 2019 22:04:28 +0100 Subject: [PATCH 043/711] Fix the signature of loadfile Lua 5.2+ uses loadfile(filename, mode, env), not loadfile(filename, env). While this is a minor incompatibility, it'd be nice to be consistent as much as possible. We try to handle the incorrect case too, as obviously we don't want to break existing programs. --- .../assets/computercraft/lua/bios.lua | 31 +++++++++++-------- .../computercraft/lua/rom/programs/shell.lua | 2 +- .../core/ComputerTestDelegate.java | 2 +- .../core/computer/ComputerBootstrap.java | 2 +- src/test/resources/test-rom/mcfly.lua | 2 +- .../resources/test-rom/spec/base_spec.lua | 29 +++++++++++++++-- 6 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 7b8b6b030..eb3600379 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -539,23 +539,28 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) return sLine end -function loadfile( _sFile, _tEnv ) - expect(1, _sFile, "string") - expect(2, _tEnv, "table", "nil") - - local file = fs.open( _sFile, "r" ) - if file then - local func, err = load( file.readAll(), "@" .. fs.getName( _sFile ), "t", _tEnv ) - file.close() - return func, err +function loadfile( filename, mode, env ) + -- Support the previous `loadfile(filename, env)` form instead. + if type(mode) == "table" and env == nil then + mode, env = nil, mode end - return nil, "File not found" + + expect(1, filename, "string") + expect(2, mode, "string", "nil") + expect(3, env, "table", "nil") + + local file = fs.open( filename, "r" ) + if not file then return nil, "File not found" end + + local func, err = load( file.readAll(), "@" .. fs.getName( filename ), mode, env ) + file.close() + return func, err end function dofile( _sFile ) expect(1, _sFile, "string") - local fnFile, e = loadfile( _sFile, _G ) + local fnFile, e = loadfile( _sFile, nil, _G ) if fnFile then return fnFile() else @@ -571,7 +576,7 @@ function os.run( _tEnv, _sPath, ... ) local tArgs = table.pack( ... ) local tEnv = _tEnv setmetatable( tEnv, { __index = _G } ) - local fnFile, err = loadfile( _sPath, tEnv ) + local fnFile, err = loadfile( _sPath, nil, tEnv ) if fnFile then local ok, err = pcall( function() fnFile( table.unpack( tArgs, 1, tArgs.n ) ) @@ -605,7 +610,7 @@ function os.loadAPI( _sPath ) local tEnv = {} setmetatable( tEnv, { __index = _G } ) - local fnAPI, err = loadfile( _sPath, tEnv ) + local fnAPI, err = loadfile( _sPath, nil, tEnv ) if fnAPI then local ok, err = pcall( fnAPI ) if not ok then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 08c7e515e..2fea697d7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -56,7 +56,7 @@ local function createShellEnv( sDir ) sPath = fs.combine(sDir, sPath) end if fs.exists(sPath) and not fs.isDir(sPath) then - local fnFile, sError = loadfile( sPath, tEnv ) + local fnFile, sError = loadfile( sPath, nil, tEnv ) if fnFile then return fnFile, sPath else diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 50bea8baa..5d84bc9fe 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -91,7 +91,7 @@ public class ComputerTestDelegate try( WritableByteChannel channel = mount.openChannelForWrite( "startup.lua" ); Writer writer = Channels.newWriter( channel, StandardCharsets.UTF_8.newEncoder(), -1 ) ) { - writer.write( "loadfile('test/mcfly.lua', _ENV)('test/spec') cct_test.finish()" ); + writer.write( "loadfile('test/mcfly.lua', nil, _ENV)('test/spec') cct_test.finish()" ); } computer = new Computer( new BasicEnvironment( mount ), term, 0 ); diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 926596d90..0545328ca 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -40,7 +40,7 @@ public class ComputerBootstrap { MemoryMount mount = new MemoryMount() .addFile( "test.lua", program ) - .addFile( "startup", "assertion.assert(pcall(loadfile('test.lua', _ENV))) os.shutdown()" ); + .addFile( "startup", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()" ); run( mount, x -> { } ); } diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 4275102ad..e46d2dc4e 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -501,7 +501,7 @@ do if fs.isDir(file) then run_in(file) elseif file:sub(-#suffix) == suffix then - local fun, err = loadfile(file, env) + local fun, err = loadfile(file, nil, env) if not fun then do_test { name = file:sub(#root_dir + 2), error = { message = err } } else diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua index 4713bfc64..43de8239d 100644 --- a/src/test/resources/test-rom/spec/base_spec.lua +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -16,18 +16,43 @@ describe("The Lua base library", function() end) describe("loadfile", function() + local function make_file() + local tmp = fs.open("test-files/out.lua", "w") + tmp.write("return _ENV") + tmp.close() + end + it("validates arguments", function() loadfile("") - loadfile("", {}) + loadfile("", "") + loadfile("", "", {}) expect.error(loadfile, nil):eq("bad argument #1 (expected string, got nil)") - expect.error(loadfile, "", false):eq("bad argument #2 (expected table, got boolean)") + expect.error(loadfile, "", false):eq("bad argument #2 (expected string, got boolean)") + expect.error(loadfile, "", "", false):eq("bad argument #3 (expected table, got boolean)") end) it("prefixes the filename with @", function() local info = debug.getinfo(loadfile("/rom/startup.lua"), "S") expect(info):matches { short_src = "startup.lua", source = "@startup.lua" } end) + + it("loads a file with the global environment", function() + make_file() + expect(loadfile("test-files/out.lua")()):eq(_G) + end) + + it("loads a file with a specific environment", function() + make_file() + local env = {} + expect(loadfile("test-files/out.lua", nil, env)()):eq(env) + end) + + it("supports the old-style argument form", function() + make_file() + local env = {} + expect(loadfile("test-files/out.lua", env)()):eq(env) + end) end) describe("dofile", function() From 85b740f4845d5c976cf5a90cba8130b3da913e6c Mon Sep 17 00:00:00 2001 From: liquid Date: Fri, 12 Jul 2019 22:54:37 -0500 Subject: [PATCH 044/711] Added term.getLine and window.getLine --- .../dan200/computercraft/core/apis/TermAPI.java | 16 ++++++++++++++++ .../assets/computercraft/lua/rom/apis/window.lua | 10 ++++++++++ .../resources/test-rom/spec/apis/term_spec.lua | 9 +++++++++ .../resources/test-rom/spec/apis/window_spec.lua | 11 +++++++++++ 4 files changed, 46 insertions(+) diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 382ae4069..4a26d36e2 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -67,6 +67,7 @@ public class TermAPI implements ILuaAPI "nativePaletteColour", "nativePaletteColor", "getCursorBlink", + "getLine" }; } @@ -279,6 +280,21 @@ public class TermAPI implements ILuaAPI case 25: // getCursorBlink return new Object[] { m_terminal.getCursorBlink() }; + case 26: + // getLine + int y = getInt( args, 0 ) - 1; + if ( y < 0 || y >= m_terminal.getHeight() ) + { + throw new LuaException( "Line is out of range." ); + } + String line, lineTextColour, lineBackgroundColour; + synchronized (m_terminal) + { + line = m_terminal.getLine( y ).read(); + lineTextColour = m_terminal.getTextColourLine( y ).read(); + lineBackgroundColour = m_terminal.getBackgroundColourLine( y ).read(); + } + return new Object[] { line, lineTextColour, lineBackgroundColour }; default: return null; } diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index d3ecf0915..8ac9674dd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -388,6 +388,16 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nBackgroundColor end + function window.getLine( nY ) + if type(nY) ~= "number" then expect(1, nY, "number") end + + if nY < 1 or nY > nHeight then + error( "Line is out of range.", 2 ) + end + + return tLines[nY].text, tLines[nY].textColor, tLines[nY].backgroundColor + end + -- Other functions function window.setVisible( bVis ) if type(bVis) ~= "boolean" then expect(1, bVis, "boolean") end diff --git a/src/test/resources/test-rom/spec/apis/term_spec.lua b/src/test/resources/test-rom/spec/apis/term_spec.lua index 769fcb867..2bc4f85ac 100644 --- a/src/test/resources/test-rom/spec/apis/term_spec.lua +++ b/src/test/resources/test-rom/spec/apis/term_spec.lua @@ -9,4 +9,13 @@ describe("The term library", function() :eq("term is not a recommended redirect target, try term.current() instead") end) end) + + describe("term.getLine", function() + it("validates arguments", function() + local _, y = term.getSize() + expect.error(term.getLine, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(term.getLine, 0):eq("Line is out of range.") + expect.error(term.getLine, y + 1):eq("Line is out of range.") + end) + end) end) diff --git a/src/test/resources/test-rom/spec/apis/window_spec.lua b/src/test/resources/test-rom/spec/apis/window_spec.lua index 16fe229e1..b6102e841 100644 --- a/src/test/resources/test-rom/spec/apis/window_spec.lua +++ b/src/test/resources/test-rom/spec/apis/window_spec.lua @@ -120,4 +120,15 @@ describe("The window library", function() expect.error(w.reposition, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") end) end) + + describe("Window.getLine", function() + it("validates arguments", function() + local w = mk() + w.getLine(1) + local _, y = w.getSize() + expect.error(w.getLine, nil):eq("bad argument #1 (expected number, got nil)") + expect.error(w.getLine, 0):eq("Line is out of range.") + expect.error(w.getLine, y + 1):eq("Line is out of range.") + end) + end) end) From 1c28df65c37fd73695cc4574409d4a073176765d Mon Sep 17 00:00:00 2001 From: liquid Date: Fri, 12 Jul 2019 23:54:56 -0500 Subject: [PATCH 045/711] Fixed style errors --- src/main/java/dan200/computercraft/core/apis/TermAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 4a26d36e2..210372e20 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -67,7 +67,7 @@ public class TermAPI implements ILuaAPI "nativePaletteColour", "nativePaletteColor", "getCursorBlink", - "getLine" + "getLine", }; } @@ -288,7 +288,7 @@ public class TermAPI implements ILuaAPI throw new LuaException( "Line is out of range." ); } String line, lineTextColour, lineBackgroundColour; - synchronized (m_terminal) + synchronized ( m_terminal ) { line = m_terminal.getLine( y ).read(); lineTextColour = m_terminal.getTextColourLine( y ).read(); From 4b7d843b78f391c6c8db5f8ad1f7e67bc6ca864e Mon Sep 17 00:00:00 2001 From: liquid Date: Sat, 13 Jul 2019 01:45:16 -0500 Subject: [PATCH 046/711] Removed term.getLine --- .../dan200/computercraft/core/apis/TermAPI.java | 16 ---------------- .../resources/test-rom/spec/apis/term_spec.lua | 9 --------- 2 files changed, 25 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 210372e20..382ae4069 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -67,7 +67,6 @@ public class TermAPI implements ILuaAPI "nativePaletteColour", "nativePaletteColor", "getCursorBlink", - "getLine", }; } @@ -280,21 +279,6 @@ public class TermAPI implements ILuaAPI case 25: // getCursorBlink return new Object[] { m_terminal.getCursorBlink() }; - case 26: - // getLine - int y = getInt( args, 0 ) - 1; - if ( y < 0 || y >= m_terminal.getHeight() ) - { - throw new LuaException( "Line is out of range." ); - } - String line, lineTextColour, lineBackgroundColour; - synchronized ( m_terminal ) - { - line = m_terminal.getLine( y ).read(); - lineTextColour = m_terminal.getTextColourLine( y ).read(); - lineBackgroundColour = m_terminal.getBackgroundColourLine( y ).read(); - } - return new Object[] { line, lineTextColour, lineBackgroundColour }; default: return null; } diff --git a/src/test/resources/test-rom/spec/apis/term_spec.lua b/src/test/resources/test-rom/spec/apis/term_spec.lua index 2bc4f85ac..769fcb867 100644 --- a/src/test/resources/test-rom/spec/apis/term_spec.lua +++ b/src/test/resources/test-rom/spec/apis/term_spec.lua @@ -9,13 +9,4 @@ describe("The term library", function() :eq("term is not a recommended redirect target, try term.current() instead") end) end) - - describe("term.getLine", function() - it("validates arguments", function() - local _, y = term.getSize() - expect.error(term.getLine, nil):eq("bad argument #1 (expected number, got nil)") - expect.error(term.getLine, 0):eq("Line is out of range.") - expect.error(term.getLine, y + 1):eq("Line is out of range.") - end) - end) end) From 4ae77261fa884fcdcd425748ca2a838f38986395 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 13 Jul 2019 08:29:28 +0100 Subject: [PATCH 047/711] Petty changes because I'm petty --- .../assets/computercraft/lua/rom/apis/window.lua | 10 +++++----- src/test/resources/test-rom/spec/apis/window_spec.lua | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 8ac9674dd..fb4820be8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -388,14 +388,14 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nBackgroundColor end - function window.getLine( nY ) - if type(nY) ~= "number" then expect(1, nY, "number") end + function window.getLine(y) + if type(y) ~= "number" then expect(1, y, "number") end - if nY < 1 or nY > nHeight then - error( "Line is out of range.", 2 ) + if y < 1 or y > nHeight then + error("Line is out of range.", 2) end - return tLines[nY].text, tLines[nY].textColor, tLines[nY].backgroundColor + return tLines[y].text, tLines[y].textColor, tLines[y].backgroundColor end -- Other functions diff --git a/src/test/resources/test-rom/spec/apis/window_spec.lua b/src/test/resources/test-rom/spec/apis/window_spec.lua index b6102e841..2fb6d119d 100644 --- a/src/test/resources/test-rom/spec/apis/window_spec.lua +++ b/src/test/resources/test-rom/spec/apis/window_spec.lua @@ -130,5 +130,11 @@ describe("The window library", function() expect.error(w.getLine, 0):eq("Line is out of range.") expect.error(w.getLine, y + 1):eq("Line is out of range.") end) + + it("provides a line's contents", function() + local w = mk() + w.blit("test", "aaaa", "4444") + expect({ w.getLine(1) }):same { "test ", "aaaa0", "4444f" } + end) end) end) From 6279816ecceca94e4bdbd8864210c161a5d1b104 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 15 Jul 2019 08:45:22 +0100 Subject: [PATCH 048/711] Try using the HTTP one instead --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ae888343..d7996659e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ![CC: Tweaked](logo.png) -[![Current build status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked "Current build status") [![Download CC: Tweaked on CurseForge](https://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") +[![Current build status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers, turtles and more to Minecraft. From 303b57779a186e1690868167c4a44a5e15fae781 Mon Sep 17 00:00:00 2001 From: powerboat9 <7397652+powerboat9@users.noreply.github.com> Date: Wed, 17 Jul 2019 04:23:14 -0400 Subject: [PATCH 049/711] Fix turtles harvesting blocks when they shouldn't (#276) harvestBlock should only be called when removedByPlayer and canHarvestBlock return true, otherwise we run the risk of causing dupe bugs. See #273. --- .../dan200/computercraft/shared/turtle/upgrades/TurtleTool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index d91c02a77..d7c40e27a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -246,7 +246,7 @@ public class TurtleTool extends AbstractTurtleUpgrade boolean canHarvest = state.getBlock().canHarvestBlock( world, blockPosition, turtlePlayer ); boolean canBreak = state.getBlock().removedByPlayer( state, world, blockPosition, turtlePlayer, canHarvest ); if( canBreak ) state.getBlock().onPlayerDestroy( world, blockPosition, state ); - if( canHarvest ) + if( canHarvest && canBreak ) { state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() ); } From ccd85eb0556f6aaa134f14871f96ae233567ee17 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 21 Jul 2019 09:41:58 +0100 Subject: [PATCH 050/711] Bump Forge version --- build.gradle | 4 ++-- gradle.properties | 6 ++--- .../client/render/CableHighlightRenderer.java | 5 ++-- .../render/MonitorHighlightRenderer.java | 4 ++-- .../client/render/TurtleMultiModel.java | 1 + .../client/render/TurtleSmartItemModel.java | 1 + .../shared/command/CommandComputerCraft.java | 2 +- .../shared/common/TileGeneric.java | 1 - .../computer/blocks/BlockComputerBase.java | 2 +- .../computer/blocks/TileCommandComputer.java | 2 +- .../peripheral/diskdrive/TileDiskDrive.java | 22 ----------------- .../peripheral/printer/ContainerPrinter.java | 2 +- .../peripheral/printer/TilePrinter.java | 15 ------------ .../shared/turtle/blocks/TileTurtle.java | 1 - .../turtle/core/TurtleCompareCommand.java | 2 +- .../shared/turtle/core/TurtlePlayer.java | 2 +- .../turtle/inventory/ContainerTurtle.java | 2 +- .../upgrades/TurtleInventoryCrafting.java | 2 +- .../shared/util/NamedTileEntityType.java | 24 +------------------ src/main/resources/META-INF/mods.toml | 4 ++-- 20 files changed, 22 insertions(+), 82 deletions(-) diff --git a/build.gradle b/build.gradle index ada301a77..b31811486 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.128' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.130' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } @@ -127,7 +127,7 @@ jar { manifest { attributes(["Specification-Title": "computercraft", "Specification-Vendor": "SquidDev", - "Specification-Version": "26.0", + "Specification-Version": "1", "Implementation-Title": "CC: Tweaked", "Implementation-Version": "${mod_version}", "Implementation-Vendor" :"SquidDev", diff --git a/gradle.properties b/gradle.properties index b6ea6fe23..c0f4eb432 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.83.1 # Minecraft properties -mc_version=1.14.3 -forge_version=27.0.3 -mappings_version=20190626-1.14.3 +mc_version=1.14.4 +forge_version=28.0.11 +mappings_version=20190721-1.14.3 diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index ae73b59be..7c91057d1 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -15,7 +15,6 @@ import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; @@ -39,7 +38,7 @@ public final class CableHighlightRenderer * Draw an outline for a specific part of a cable "Multipart". * * @param event The event to observe - * @see WorldRenderer#drawSelectionBox(PlayerEntity, RayTraceResult, int, float) + * @see WorldRenderer#drawSelectionBox(ActiveRenderInfo, RayTraceResult, int) */ @SubscribeEvent public static void drawHighlight( DrawBlockHighlightEvent event ) @@ -48,7 +47,7 @@ public final class CableHighlightRenderer BlockRayTraceResult hit = (BlockRayTraceResult) event.getTarget(); BlockPos pos = hit.getPos(); - World world = event.getInfo().func_216773_g().getEntityWorld(); + World world = event.getInfo().getRenderViewEntity().getEntityWorld(); ActiveRenderInfo info = event.getInfo(); BlockState state = world.getBlockState( pos ); diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 326d5c81c..8457845ae 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -42,12 +42,12 @@ public final class MonitorHighlightRenderer @SubscribeEvent public static void drawHighlight( DrawBlockHighlightEvent event ) { - if( event.getTarget().getType() != RayTraceResult.Type.BLOCK || event.getInfo().func_216773_g().isSneaking() ) + if( event.getTarget().getType() != RayTraceResult.Type.BLOCK || event.getInfo().getRenderViewEntity().isSneaking() ) { return; } - World world = event.getInfo().func_216773_g().getEntityWorld(); + World world = event.getInfo().getRenderViewEntity().getEntityWorld(); BlockPos pos = ((BlockRayTraceResult) event.getTarget()).getPos(); TileEntity tile = world.getTileEntity( pos ); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 7014b8368..296173fd4 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -119,6 +119,7 @@ public class TurtleMultiModel implements IBakedModel @Nonnull @Override + @Deprecated public TextureAtlasSprite getParticleTexture() { return m_baseModel.getParticleTexture(); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 7c24c7f55..79dd8a242 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -202,6 +202,7 @@ public class TurtleSmartItemModel implements IBakedModel @Nonnull @Override + @Deprecated public TextureAtlasSprite getParticleTexture() { return familyModel.getParticleTexture(); diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 17b333ec3..65dceef8f 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -34,8 +34,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; -import net.minecraft.world.ServerWorld; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import java.util.*; diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 9efbd3e56..3218e1af6 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -35,7 +35,6 @@ public abstract class TileGeneric extends TileEntity markDirty(); BlockPos pos = getPos(); BlockState state = getBlockState(); - getWorld().markForRerender( pos ); getWorld().notifyBlockUpdate( pos, state, state, 3 ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 975453553..71789d0f3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -25,8 +25,8 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.IBlockReader; -import net.minecraft.world.ServerWorld; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraft.world.storage.loot.LootContext; import net.minecraft.world.storage.loot.LootParameters; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 1a689ded3..7e6623c82 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -23,7 +23,7 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.GameRules; -import net.minecraft.world.ServerWorld; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import java.util.HashMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 72d3c634f..d424fbde4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -509,28 +509,6 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory if( !destroyed ) getWorld().playBroadcastSound( 1000, getPos(), 0 ); } - @Override - protected void readDescription( @Nonnull CompoundNBT nbt ) - { - super.readDescription( nbt ); - customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; - m_diskStack = nbt.contains( NBT_ITEM ) ? ItemStack.read( nbt.getCompound( NBT_ITEM ) ) : ItemStack.EMPTY; - updateBlock(); - } - - @Override - protected void writeDescription( @Nonnull CompoundNBT nbt ) - { - super.writeDescription( nbt ); - if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); - if( !m_diskStack.isEmpty() ) - { - CompoundNBT item = new CompoundNBT(); - m_diskStack.write( item ); - nbt.put( NBT_ITEM, item ); - } - } - // Private methods private void playRecord() diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index 93fb661dd..be2f8d4d1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -34,7 +34,7 @@ public class ContainerPrinter extends Container this.properties = properties; this.inventory = inventory; - func_216961_a( properties ); + trackIntArray( properties ); // Ink slot addSlot( new Slot( inventory, 0, 13, 35 ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 98a22fb35..b525dfbfd 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -149,21 +149,6 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent return super.write( nbt ); } - @Override - protected void writeDescription( @Nonnull CompoundNBT nbt ) - { - super.writeDescription( nbt ); - if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); - } - - @Override - public void readDescription( @Nonnull CompoundNBT nbt ) - { - super.readDescription( nbt ); - customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; - updateBlock(); - } - public boolean isPrinting() { return m_printing; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 75e80658f..982697aa5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -563,7 +563,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default { super.readDescription( nbt ); m_brain.readDescription( nbt ); - updateBlock(); } // Privates diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index 3d143019d..59db580aa 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -14,8 +14,8 @@ import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.ServerWorld; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 6dadf9126..64edff54d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -17,7 +17,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.ServerWorld; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.FakePlayer; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index c294a7d7e..e7c9b72d3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -44,7 +44,7 @@ public class ContainerTurtle extends ContainerComputerBase super( TYPE, id, canUse, computer, family ); this.properties = properties; - func_216961_a( properties ); + trackIntArray( properties ); // Turtle inventory for( int y = 0; y < 4; y++ ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 218e5254c..085e86b12 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -15,8 +15,8 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.IRecipeType; import net.minecraft.util.NonNullList; -import net.minecraft.world.ServerWorld; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fml.hooks.BasicEventHooks; diff --git a/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java index 42f292495..b6d08624d 100644 --- a/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java +++ b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java @@ -6,16 +6,10 @@ package dan200.computercraft.shared.util; -import com.mojang.datafixers.DataFixUtils; -import com.mojang.datafixers.types.Type; -import dan200.computercraft.ComputerCraft; import net.minecraft.block.Block; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.SharedConstants; -import net.minecraft.util.datafix.DataFixesManager; -import net.minecraft.util.datafix.TypeReferences; import javax.annotation.Nonnull; import java.util.Collections; @@ -30,7 +24,7 @@ public final class NamedTileEntityType extends TileEntityT private NamedTileEntityType( ResourceLocation identifier, Supplier supplier ) { - super( supplier, Collections.emptySet(), getDatafixer( identifier ) ); + super( supplier, Collections.emptySet(), null ); this.identifier = identifier; setRegistryName( identifier ); } @@ -62,22 +56,6 @@ public final class NamedTileEntityType extends TileEntityT return identifier; } - private static Type getDatafixer( ResourceLocation id ) - { - try - { - return DataFixesManager.getDataFixer() - .getSchema( DataFixUtils.makeKey( ComputerCraft.DATAFIXER_VERSION ) ) - .getChoiceType( TypeReferences.BLOCK_ENTITY, id.toString() ); - } - catch( IllegalArgumentException e ) - { - if( SharedConstants.developmentMode ) throw e; - ComputerCraft.log.warn( "No data fixer registered for block entity " + id ); - return null; - } - } - private static final class FixedPointSupplier implements Supplier { final NamedTileEntityType factory; diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 0e40894ea..c9f314f66 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[27,28)" +loaderVersion="[28,29)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[27,28)" + versionRange="[28,29)" ordering="NONE" side="BOTH" From cef26570483a5b0c82b5328a70c532fe3257afad Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 21 Jul 2019 10:28:22 +0100 Subject: [PATCH 051/711] Fix turtles being replaced by leaves And logs. Well, hopefully at least. Fixes #278 --- .../dan200/computercraft/shared/common/BlockGeneric.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index 03e995463..f08b8521a 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -89,4 +89,10 @@ public abstract class BlockGeneric extends Block { return type.create(); } + + @Override + public boolean canBeReplacedByLeaves( BlockState state, IWorldReader world, BlockPos pos ) + { + return false; + } } From a2880b12caa43d52c7fb2ba1659d035d8ff78a0c Mon Sep 17 00:00:00 2001 From: powerboat9 <7397652+powerboat9@users.noreply.github.com> Date: Wed, 24 Jul 2019 07:15:02 +0000 Subject: [PATCH 052/711] Do not refuel beyond the turtle limit (#274) --- .../computercraft/shared/turtle/FurnaceRefuelHandler.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index af987204b..d842b8615 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -30,9 +30,13 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler @Override public int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack currentStack, int slot, int limit ) { - ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false ); - int fuelToGive = getFuelPerItem( stack ) * stack.getCount(); + int fuelSpaceLeft = turtle.getFuelLimit() - turtle.getFuelLevel(); + int fuelPerItem = getFuelPerItem( turtle.getItemHandler().getStackInSlot( slot ) ); + int fuelItemLimit = (int) Math.ceil( fuelSpaceLeft / (double) fuelPerItem ); + if ( limit > fuelItemLimit ) limit = fuelItemLimit; + ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false ); + int fuelToGive = fuelPerItem * stack.getCount(); // Store the replacement item in the inventory ItemStack replacementStack = stack.getItem().getContainerItem( stack ); if( !replacementStack.isEmpty() ) From 93310850d27286919c162d2387d6540430e2cbe6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 27 Jul 2019 11:34:36 +0100 Subject: [PATCH 053/711] Use the "cc" module namespace instead of "craftos" This is what we actually discussed in the issue, and I failed to remember. --- src/main/resources/assets/computercraft/lua/bios.lua | 2 +- .../resources/assets/computercraft/lua/rom/apis/colors.lua | 2 +- src/main/resources/assets/computercraft/lua/rom/apis/gps.lua | 2 +- src/main/resources/assets/computercraft/lua/rom/apis/help.lua | 2 +- src/main/resources/assets/computercraft/lua/rom/apis/io.lua | 2 +- src/main/resources/assets/computercraft/lua/rom/apis/keys.lua | 2 +- .../assets/computercraft/lua/rom/apis/paintutils.lua | 2 +- .../assets/computercraft/lua/rom/apis/peripheral.lua | 2 +- .../resources/assets/computercraft/lua/rom/apis/rednet.lua | 2 +- .../resources/assets/computercraft/lua/rom/apis/settings.lua | 2 +- src/main/resources/assets/computercraft/lua/rom/apis/term.lua | 2 +- .../resources/assets/computercraft/lua/rom/apis/textutils.lua | 2 +- .../resources/assets/computercraft/lua/rom/apis/window.lua | 2 +- .../lua/rom/modules/main/{craftos => cc}/expect.lua | 0 .../computercraft/lua/rom/programs/advanced/multishell.lua | 2 +- .../resources/assets/computercraft/lua/rom/programs/shell.lua | 2 +- .../resources/test-rom/spec/modules/{ => cc}/expect_spec.lua | 4 ++-- 17 files changed, 17 insertions(+), 17 deletions(-) rename src/main/resources/assets/computercraft/lua/rom/modules/main/{craftos => cc}/expect.lua (100%) rename src/test/resources/test-rom/spec/modules/{ => cc}/expect_spec.lua (93%) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index eb3600379..417b55bc9 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -6,7 +6,7 @@ local expect do - local h = fs.open("rom/modules/main/craftos/expect.lua", "r") + local h = fs.open("rom/modules/main/cc/expect.lua", "r") local f, err = loadstring(h.readAll(), "@expect.lua") h.close() diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua index bf3444724..969f984e5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect -- Colors white = 1 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index b36e0b79a..08f698eb2 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect CHANNEL_GPS = 65534 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index fd9b22289..b4e69921f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local sPath = "/rom/help" diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index b50c724bf..efbc13b40 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -1,6 +1,6 @@ -- Definition for the IO API -local expect, typeOf = dofile("rom/modules/main/craftos/expect.lua").expect, _G.type +local expect, typeOf = dofile("rom/modules/main/cc/expect.lua").expect, _G.type --- If we return nil then close the file, as we've reached the end. -- We use this weird wrapper function as we wish to preserve the varargs diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua index b4b3daccd..8411883cf 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua @@ -1,7 +1,7 @@ -- Minecraft key code bindings -- See http://www.minecraftwiki.net/wiki/Key_codes for more info -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local tKeys = { nil, "one", "two", "three", "four", -- 1 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index a0a028aac..0988945e0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local function drawPixelInternal( xPos, yPos ) term.setCursorPos( xPos, yPos ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index 4b6fee2dc..3f4fdc150 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = peripheral diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index 84a20c0cb..5af3a4706 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect CHANNEL_BROADCAST = 65535 CHANNEL_REPEAT = 65533 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 68f2ba2d7..d60510937 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local tSettings = {} diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index baaeccf25..e9ad00408 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = (term.native and term.native()) or term local redirectTarget = native diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 05f32117c..447babb44 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect function slowWrite( sText, nRate ) expect(2, nRate, "number", "nil") diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index fb4820be8..b1e1b3db4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local tHex = { [ colors.white ] = "0", diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/craftos/expect.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua similarity index 100% rename from src/main/resources/assets/computercraft/lua/rom/modules/main/craftos/expect.lua rename to src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index 9bca4b166..51c1c1753 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect -- Setup process switching local parentTerm = term.current() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 2fea697d7..3c15e04b3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -1,4 +1,4 @@ -local expect = dofile("rom/modules/main/craftos/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua").expect local multishell = multishell local parentShell = shell diff --git a/src/test/resources/test-rom/spec/modules/expect_spec.lua b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua similarity index 93% rename from src/test/resources/test-rom/spec/modules/expect_spec.lua rename to src/test/resources/test-rom/spec/modules/cc/expect_spec.lua index 6b6aa77c0..36f076f60 100644 --- a/src/test/resources/test-rom/spec/modules/expect_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua @@ -1,5 +1,5 @@ -describe("craftos.expect", function() - local e = require("craftos.expect") +describe("cc.expect", function() + local e = require("cc.expect") it("checks a single type", function() expect(e.expect(1, "test", "string")):eq(true) From 5eeb320b604864b60018a090ed9e678a6430cf60 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 30 Jul 2019 15:20:08 +0100 Subject: [PATCH 054/711] Include all mods within a resource mount This is the behaviour on 1.14 already, so it makes sense to backport to 1.12. Any mod may now insert files into assets/computercraft/lua/rom, and they'll be automatically added to the default ROM mount. This allows other mods to easily register new programs or autorun files. See #242 --- .../dan200/computercraft/ComputerCraft.java | 79 ++++++++++--------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 4661f7ee8..c0240599a 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -72,9 +72,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockAccess; import net.minecraft.world.World; import net.minecraftforge.common.DimensionManager; -import net.minecraftforge.fml.common.FMLCommonHandler; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.SidedProxy; +import net.minecraftforge.fml.common.*; import net.minecraftforge.fml.common.event.*; import net.minecraftforge.fml.relauncher.Side; import org.apache.logging.log4j.Logger; @@ -83,9 +81,7 @@ import java.io.*; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -394,6 +390,27 @@ public class ComputerCraft } } + private static void loadFromFile( List mounts, File file, String path, boolean allowMissing ) + { + try + { + if( file.isFile() ) + { + mounts.add( new JarMount( file, path ) ); + } + else + { + File subResource = new File( file, path ); + if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) ); + } + } + catch( IOException | RuntimeException e ) + { + if( allowMissing && e instanceof FileNotFoundException ) return; + ComputerCraft.log.error( "Could not load mount '" + path + " 'from '" + file.getName() + "'", e ); + } + } + @Deprecated public static IMount createResourceMount( Class modClass, String domain, String subPath ) { @@ -413,18 +430,26 @@ public class ComputerCraft } } - // Mount from mod jar + // Mount from mod jars, preferring the specified one. File modJar = getContainingJar( modClass ); + Set otherMods = new HashSet<>(); + for( ModContainer container : Loader.instance().getActiveModList() ) + { + File modFile = container.getSource(); + if( modFile != null && !modFile.equals( modJar ) && modFile.exists() ) + { + otherMods.add( container.getSource() ); + } + } + + for( File file : otherMods ) + { + loadFromFile( mounts, file, subPath, true ); + } + if( modJar != null ) { - try - { - mounts.add( new JarMount( modJar, subPath ) ); - } - catch( IOException | RuntimeException e ) - { - ComputerCraft.log.error( "Could not load mount from mod jar", e ); - } + loadFromFile( mounts, modJar, subPath, false ); } // Mount from resource packs @@ -434,28 +459,8 @@ public class ComputerCraft String[] resourcePacks = resourcePackDir.list(); for( String resourcePackName : resourcePacks ) { - try - { - File resourcePack = new File( resourcePackDir, resourcePackName ); - if( !resourcePack.isDirectory() ) - { - // Mount a resource pack from a jar - mounts.add( new JarMount( resourcePack, subPath ) ); - } - else - { - // Mount a resource pack from a folder - File subResource = new File( resourcePack, subPath ); - if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) ); - } - } - catch( FileNotFoundException ignored ) - { - } - catch( IOException | RuntimeException e ) - { - ComputerCraft.log.error( "Could not load resource pack '" + resourcePackName + "'", e ); - } + File resourcePack = new File( resourcePackDir, resourcePackName ); + loadFromFile( mounts, resourcePack, subPath, true ); } } From 6ce34aba79ce4e442d09f2d4f83e96ac49e9f5f6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 30 Jul 2019 15:25:14 +0100 Subject: [PATCH 055/711] A quick attempt at fixing Travis Oracle JDK 8 is EOL (I think at least). --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 327098845..0e4be822e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,4 @@ cache: - $HOME/.gradle/wrapper/s jdk: - - oraclejdk8 + - openjdk8 From 2ab79cf474d42795d2675fe09d079e0c6c64836d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 30 Jul 2019 15:48:05 +0100 Subject: [PATCH 056/711] Version bumps 'n stuff --- gradle.properties | 2 +- .../computercraft/api/turtle/ITurtleUpgrade.java | 4 ++-- .../computercraft/lua/rom/help/changelog.txt | 15 +++++++++++++++ .../computercraft/lua/rom/help/whatsnew.txt | 16 +++++++++++----- .../assets/computercraft/lua/rom/help/window.txt | 1 + 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/gradle.properties b/gradle.properties index c053184cb..8b34c6687 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.83.1 +mod_version=1.84.0 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index c28fcae74..08d89f177 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -109,8 +109,8 @@ public interface ITurtleUpgrade * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called * by the turtle, and the tool is required to do some work. * - * Conforming implementations should fire {@link BlockEvent.BreakEvent} and {@link TurtleBlockEvent.Dig}for digging, - * {@link AttackEntityEvent} and {@link TurtleAttackEvent} for attacking. + * Conforming implementations should fire {@link BlockEvent.BreakEvent} and {@link TurtleBlockEvent.Dig} for + * digging, {@link AttackEntityEvent} and {@link TurtleAttackEvent} for attacking. * * @param turtle Access to the turtle that the tool resides on. * @param side Which side of the turtle (left or right) the tool resides on. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index a9e543539..ae4ebbbc7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,18 @@ +New features in CC: Tweaked 1.84.0 + +* Improve validation in rename, copy and delete programs +* Add window.getLine - the inverse of blit +* turtle.refuel no longer consumes more fuel than needed +* Add "cc.expect" module, for improved argument type checks +* Mount the ROM from all mod jars, not just CC's + +And several bug fixes: +* Ensure file error messages use the absolute correct path +* Fix NPE when closing a file multiple times. +* Do not load chunks when calling writeDescription. +* Fix the signature of loadfile +* Fix turtles harvesting blocks multiple times + # New features in CC: Tweaked 1.83.1 * Add several new MOTD messages (JakobDev) diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 55e2ac007..3c7ecacdd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,10 +1,16 @@ -New features in CC: Tweaked 1.83.1 +New features in CC: Tweaked 1.84.0 -* Add several new MOTD messages (JakobDev) +* Improve validation in rename, copy and delete programs +* Add window.getLine - the inverse of blit +* turtle.refuel no longer consumes more fuel than needed +* Add "cc.expect" module, for improved argument type checks +* Mount the ROM from all mod jars, not just CC's And several bug fixes: -* Fix type check in `rednet.lookup` -* Error if turtle and pocket computer programs are run on the wrong system (JakobDev) -* Do not discard varargs after a nil. +* Ensure file error messages use the absolute correct path +* Fix NPE when closing a file multiple times. +* Do not load chunks when calling writeDescription. +* Fix the signature of loadfile +* Fix turtles harvesting blocks multiple times Type "help changelog" to see the full version history. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/window.txt b/src/main/resources/assets/computercraft/lua/rom/help/window.txt index 7fcf5d43e..ea3ea3d78 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/window.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/window.txt @@ -23,3 +23,4 @@ getPosition() reposition( x, y, width, height ) getPaletteColor( color ) setPaletteColor( color, r, g, b ) +getLine() From cbe6e9b5f5116b3e23f715d670c9b582cf3e9dfb Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 2 Apr 2019 12:45:54 +0100 Subject: [PATCH 057/711] Make printers thread-safe --- .../peripheral/printer/PrinterPeripheral.java | 20 +- .../peripheral/printer/TilePrinter.java | 379 ++++++++---------- .../computercraft/lua/rom/programs/edit.lua | 3 +- 3 files changed, 178 insertions(+), 224 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index 0a786b1e2..e88202014 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -51,8 +51,13 @@ public class PrinterPeripheral implements IPeripheral } @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException { + // FIXME: There's a theoretical race condition here between getCurrentPage and then using the page. Ideally + // we'd lock on the page, consume it, and unlock. + + // FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be + // persisted correctly. switch( method ) { case 0: // write @@ -89,10 +94,13 @@ public class PrinterPeripheral implements IPeripheral return new Object[] { width, height }; } case 4: // newPage - return new Object[] { m_printer.startNewPage() }; + return context.executeMainThreadTask( () -> new Object[] { m_printer.startNewPage() } ); case 5: // endPage getCurrentPage(); - return new Object[] { m_printer.endCurrentPage() }; + return context.executeMainThreadTask( () -> { + getCurrentPage(); + return new Object[] { m_printer.endCurrentPage() }; + } ); case 6: // getInkLevel return new Object[] { m_printer.getInkLevel() }; case 7: @@ -123,13 +131,11 @@ public class PrinterPeripheral implements IPeripheral return m_printer; } + @Nonnull private Terminal getCurrentPage() throws LuaException { Terminal currentPage = m_printer.getCurrentPage(); - if( currentPage == null ) - { - throw new LuaException( "Page not started" ); - } + if( currentPage == null ) throw new LuaException( "Page not started" ); return currentPage; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 2afbe1a2c..6542e3adb 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -45,9 +45,9 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven { // Statics - private static final int[] bottomSlots = new int[] { 7, 8, 9, 10, 11, 12 }; - private static final int[] topSlots = new int[] { 1, 2, 3, 4, 5, 6 }; - private static final int[] sideSlots = new int[] { 0 }; + private static final int[] BOTTOM_SLOTS = new int[] { 7, 8, 9, 10, 11, 12 }; + private static final int[] TOP_SLOTS = new int[] { 1, 2, 3, 4, 5, 6 }; + private static final int[] SIDE_SLOTS = new int[] { 0 }; // Members @@ -88,18 +88,12 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven } // Read inventory - synchronized( m_inventory ) + NBTTagList itemList = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND ); + for( int i = 0; i < itemList.tagCount(); i++ ) { - NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND ); - for( int i = 0; i < nbttaglist.tagCount(); i++ ) - { - NBTTagCompound itemTag = nbttaglist.getCompoundTagAt( i ); - int j = itemTag.getByte( "Slot" ) & 0xff; - if( j < m_inventory.size() ) - { - m_inventory.set( j, new ItemStack( itemTag ) ); - } - } + NBTTagCompound itemTag = itemList.getCompoundTagAt( i ); + int slot = itemTag.getByte( "Slot" ) & 0xff; + if( slot < m_inventory.size() ) m_inventory.set( slot, new ItemStack( itemTag ) ); } } @@ -116,21 +110,18 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven } // Write inventory - synchronized( m_inventory ) + NBTTagList itemList = new NBTTagList(); + for( int i = 0; i < m_inventory.size(); i++ ) { - NBTTagList nbttaglist = new NBTTagList(); - for( int i = 0; i < m_inventory.size(); i++ ) - { - if( !m_inventory.get( i ).isEmpty() ) - { - NBTTagCompound tag = new NBTTagCompound(); - tag.setByte( "Slot", (byte) i ); - m_inventory.get( i ).writeToNBT( tag ); - nbttaglist.appendTag( tag ); - } - } - nbt.setTag( "Items", nbttaglist ); + ItemStack stack = m_inventory.get( i ); + if( stack.isEmpty() ) continue; + + NBTTagCompound tag = new NBTTagCompound(); + tag.setByte( "Slot", (byte) i ); + stack.writeToNBT( tag ); + itemList.appendTag( tag ); } + nbt.setTag( "Items", itemList ); return super.writeToNBT( nbt ); } @@ -148,7 +139,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.Printer; } - public boolean isPrinting() + boolean isPrinting() { return m_printing; } @@ -173,73 +164,59 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven @Nonnull @Override - public ItemStack getStackInSlot( int i ) + public ItemStack getStackInSlot( int slot ) { - return m_inventory.get( i ); + return m_inventory.get( slot ); } @Nonnull @Override - public ItemStack removeStackFromSlot( int i ) + public ItemStack removeStackFromSlot( int slot ) { - synchronized( m_inventory ) - { - ItemStack result = m_inventory.get( i ); - m_inventory.set( i, ItemStack.EMPTY ); - markDirty(); - updateAnim(); - return result; - } + ItemStack result = m_inventory.get( slot ); + m_inventory.set( slot, ItemStack.EMPTY ); + markDirty(); + updateAnim(); + return result; } @Nonnull @Override - public ItemStack decrStackSize( int i, int j ) + public ItemStack decrStackSize( int slot, int count ) { - synchronized( m_inventory ) + ItemStack stack = m_inventory.get( slot ); + if( stack.isEmpty() ) return ItemStack.EMPTY; + + if( stack.getCount() <= count ) { - if( m_inventory.get( i ).isEmpty() ) return ItemStack.EMPTY; - - if( m_inventory.get( i ).getCount() <= j ) - { - ItemStack itemstack = m_inventory.get( i ); - m_inventory.set( i, ItemStack.EMPTY ); - markDirty(); - updateAnim(); - return itemstack; - } - - ItemStack part = m_inventory.get( i ).splitStack( j ); - if( m_inventory.get( i ).isEmpty() ) - { - m_inventory.set( i, ItemStack.EMPTY ); - updateAnim(); - } - markDirty(); - return part; + setInventorySlotContents( slot, ItemStack.EMPTY ); + return stack; } + + ItemStack part = stack.splitStack( count ); + if( m_inventory.get( slot ).isEmpty() ) + { + m_inventory.set( slot, ItemStack.EMPTY ); + updateAnim(); + } + markDirty(); + return part; } @Override - public void setInventorySlotContents( int i, @Nonnull ItemStack stack ) + public void setInventorySlotContents( int slot, @Nonnull ItemStack stack ) { - synchronized( m_inventory ) - { - m_inventory.set( i, stack ); - markDirty(); - updateAnim(); - } + m_inventory.set( slot, stack ); + markDirty(); + updateAnim(); } @Override public void clear() { - synchronized( m_inventory ) - { - for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY ); - markDirty(); - updateAnim(); - } + for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY ); + markDirty(); + updateAnim(); } @Override @@ -249,7 +226,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven { return isInk( stack ); } - else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] ) + else if( slot >= TOP_SLOTS[0] && slot <= TOP_SLOTS[TOP_SLOTS.length - 1] ) { return isPaper( stack ); } @@ -295,11 +272,11 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven switch( side ) { case DOWN: // Bottom (Out tray) - return bottomSlots; + return BOTTOM_SLOTS; case UP: // Top (In tray) - return topSlots; + return TOP_SLOTS; default: // Sides (Ink) - return sideSlots; + return SIDE_SLOTS; } } @@ -311,14 +288,18 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven return new PrinterPeripheral( this ); } - public Terminal getCurrentPage() + @Nullable + Terminal getCurrentPage() { - return m_printing ? m_page : null; + synchronized( m_page ) + { + return m_printing ? m_page : null; + } } - public boolean startNewPage() + boolean startNewPage() { - synchronized( m_inventory ) + synchronized( m_page ) { if( !canInputPage() ) return false; if( m_printing && !outputPage() ) return false; @@ -326,49 +307,36 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven } } - public boolean endCurrentPage() + boolean endCurrentPage() { - synchronized( m_inventory ) + synchronized( m_page ) { - if( m_printing && outputPage() ) - { - return true; - } - } - return false; - } - - public int getInkLevel() - { - synchronized( m_inventory ) - { - ItemStack inkStack = m_inventory.get( 0 ); - return isInk( inkStack ) ? inkStack.getCount() : 0; + return m_printing && outputPage(); } } - public int getPaperLevel() + int getInkLevel() + { + ItemStack inkStack = m_inventory.get( 0 ); + return isInk( inkStack ) ? inkStack.getCount() : 0; + } + + int getPaperLevel() { int count = 0; - synchronized( m_inventory ) + for( int i = 1; i < 7; i++ ) { - for( int i = 1; i < 7; i++ ) - { - ItemStack paperStack = m_inventory.get( i ); - if( !paperStack.isEmpty() && isPaper( paperStack ) ) - { - count += paperStack.getCount(); - } - } + ItemStack paperStack = m_inventory.get( i ); + if( isPaper( paperStack ) ) count += paperStack.getCount(); } return count; } - public void setPageTitle( String title ) + void setPageTitle( String title ) { - if( m_printing ) + synchronized( m_page ) { - m_pageTitle = title; + if( m_printing ) m_pageTitle = title; } } @@ -385,145 +353,126 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven private boolean canInputPage() { - synchronized( m_inventory ) - { - ItemStack inkStack = m_inventory.get( 0 ); - return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0; - } + ItemStack inkStack = m_inventory.get( 0 ); + return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0; } private boolean inputPage() { - synchronized( m_inventory ) + ItemStack inkStack = m_inventory.get( 0 ); + if( !isInk( inkStack ) ) return false; + + for( int i = 1; i < 7; i++ ) { - ItemStack inkStack = m_inventory.get( 0 ); - if( !isInk( inkStack ) ) return false; + ItemStack paperStack = m_inventory.get( i ); + if( paperStack.isEmpty() || !isPaper( paperStack ) ) continue; - for( int i = 1; i < 7; i++ ) + // Setup the new page + int colour = inkStack.getItemDamage(); + m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 ); + + m_page.clear(); + if( paperStack.getItem() instanceof ItemPrintout ) { - ItemStack paperStack = m_inventory.get( i ); - if( !paperStack.isEmpty() && isPaper( paperStack ) ) + m_pageTitle = ItemPrintout.getTitle( paperStack ); + String[] text = ItemPrintout.getText( paperStack ); + String[] textColour = ItemPrintout.getColours( paperStack ); + for( int y = 0; y < m_page.getHeight(); y++ ) { - // Setup the new page - int colour = inkStack.getItemDamage(); - m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 ); - - m_page.clear(); - if( paperStack.getItem() instanceof ItemPrintout ) - { - m_pageTitle = ItemPrintout.getTitle( paperStack ); - String[] text = ItemPrintout.getText( paperStack ); - String[] textColour = ItemPrintout.getColours( paperStack ); - for( int y = 0; y < m_page.getHeight(); y++ ) - { - m_page.setLine( y, text[y], textColour[y], "" ); - } - } - else - { - m_pageTitle = ""; - } - m_page.setCursorPos( 0, 0 ); - - // Decrement ink - inkStack.shrink( 1 ); - if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY ); - - // Decrement paper - paperStack.shrink( 1 ); - if( paperStack.isEmpty() ) - { - m_inventory.set( i, ItemStack.EMPTY ); - updateAnim(); - } - - markDirty(); - m_printing = true; - return true; + m_page.setLine( y, text[y], textColour[y], "" ); } } - return false; + else + { + m_pageTitle = ""; + } + m_page.setCursorPos( 0, 0 ); + + // Decrement ink + inkStack.shrink( 1 ); + if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY ); + + // Decrement paper + paperStack.shrink( 1 ); + if( paperStack.isEmpty() ) + { + m_inventory.set( i, ItemStack.EMPTY ); + updateAnim(); + } + + markDirty(); + m_printing = true; + return true; } + return false; } private boolean outputPage() { - synchronized( m_page ) + int height = m_page.getHeight(); + String[] lines = new String[height]; + String[] colours = new String[height]; + for( int i = 0; i < height; i++ ) { - int height = m_page.getHeight(); - String[] lines = new String[height]; - String[] colours = new String[height]; - for( int i = 0; i < height; i++ ) - { - lines[i] = m_page.getLine( i ).toString(); - colours[i] = m_page.getTextColourLine( i ).toString(); - } - - ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours ); - synchronized( m_inventory ) - { - for( int slot : bottomSlots ) - { - if( m_inventory.get( slot ).isEmpty() ) - { - setInventorySlotContents( slot, stack ); - m_printing = false; - return true; - } - } - } - return false; + lines[i] = m_page.getLine( i ).toString(); + colours[i] = m_page.getTextColourLine( i ).toString(); } + + ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours ); + for( int slot : BOTTOM_SLOTS ) + { + if( m_inventory.get( slot ).isEmpty() ) + { + setInventorySlotContents( slot, stack ); + m_printing = false; + return true; + } + } + return false; } private void ejectContents() { - synchronized( m_inventory ) + for( int i = 0; i < 13; i++ ) { - for( int i = 0; i < 13; i++ ) + ItemStack stack = m_inventory.get( i ); + if( !stack.isEmpty() ) { - ItemStack stack = m_inventory.get( i ); - if( !stack.isEmpty() ) - { - // Remove the stack from the inventory - setInventorySlotContents( i, ItemStack.EMPTY ); + // Remove the stack from the inventory + setInventorySlotContents( i, ItemStack.EMPTY ); - // Spawn the item in the world - BlockPos pos = getPos(); - double x = pos.getX() + 0.5; - double y = pos.getY() + 0.75; - double z = pos.getZ() + 0.5; - WorldUtil.dropItemStack( stack, getWorld(), x, y, z ); - } + // Spawn the item in the world + BlockPos pos = getPos(); + double x = pos.getX() + 0.5; + double y = pos.getY() + 0.75; + double z = pos.getZ() + 0.5; + WorldUtil.dropItemStack( stack, getWorld(), x, y, z ); } } } private void updateAnim() { - synchronized( m_inventory ) + int anim = 0; + for( int i = 1; i < 7; i++ ) { - int anim = 0; - for( int i = 1; i < 7; i++ ) + ItemStack stack = m_inventory.get( i ); + if( !stack.isEmpty() && isPaper( stack ) ) { - ItemStack stack = m_inventory.get( i ); - if( !stack.isEmpty() && isPaper( stack ) ) - { - anim += 1; - break; - } + anim += 1; + break; } - for( int i = 7; i < 13; i++ ) - { - ItemStack stack = m_inventory.get( i ); - if( !stack.isEmpty() && isPaper( stack ) ) - { - anim += 2; - break; - } - } - setAnim( anim ); } + for( int i = 7; i < 13; i++ ) + { + ItemStack stack = m_inventory.get( i ); + if( !stack.isEmpty() && isPaper( stack ) ) + { + anim += 2; + break; + } + } + setAnim( anim ); } @Override diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index 43910d56a..e481dd9cd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -329,7 +329,7 @@ local tMenuFuncs = { printer.setPageTitle( sName.." (page "..nPage..")" ) end - while not printer.newPage() do + while not printer.newPage() do if printer.getInkLevel() < 1 then sStatus = "Printer out of ink, please refill" elseif printer.getPaperLevel() < 1 then @@ -342,7 +342,6 @@ local tMenuFuncs = { redrawMenu() term.redirect( printerTerminal ) - local timer = os.startTimer(0.5) sleep(0.5) end From 2f96283286e29a6b33c1a47592ee273a8b6b5116 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 2 Apr 2019 13:17:06 +0100 Subject: [PATCH 058/711] Make disk drives thread-safe --- .../diskdrive/DiskDrivePeripheral.java | 43 +++++++++++-------- .../peripheral/diskdrive/TileDiskDrive.java | 26 +++++------ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 048127ab0..1977e4796 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -11,6 +11,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.media.items.ItemDiskLegacy; import dan200.computercraft.shared.util.StringUtil; import net.minecraft.item.Item; @@ -20,11 +21,11 @@ import javax.annotation.Nonnull; import static dan200.computercraft.core.apis.ArgumentHelper.optString; -public class DiskDrivePeripheral implements IPeripheral +class DiskDrivePeripheral implements IPeripheral { private final TileDiskDrive m_diskDrive; - public DiskDrivePeripheral( TileDiskDrive diskDrive ) + DiskDrivePeripheral( TileDiskDrive diskDrive ) { m_diskDrive = diskDrive; } @@ -56,7 +57,7 @@ public class DiskDrivePeripheral implements IPeripheral } @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException + public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException { switch( method ) { @@ -64,21 +65,26 @@ public class DiskDrivePeripheral implements IPeripheral return new Object[] { !m_diskDrive.getDiskStack().isEmpty() }; case 1: // getDiskLabel { - IMedia media = m_diskDrive.getDiskMedia(); - return media == null ? null : new Object[] { media.getLabel( m_diskDrive.getDiskStack() ) }; + ItemStack stack = m_diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + return media == null ? null : new Object[] { media.getLabel( stack ) }; } case 2: // setDiskLabel { String label = optString( arguments, 0, null ); - IMedia media = m_diskDrive.getDiskMedia(); - if( media == null ) return null; + return context.executeMainThreadTask( () -> { + ItemStack stack = m_diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + if( media == null ) return null; - ItemStack disk = m_diskDrive.getDiskStack(); - label = StringUtil.normaliseLabel( label ); - if( !media.setLabel( disk, label ) ) throw new LuaException( "Disk label cannot be changed" ); - m_diskDrive.setDiskStack( disk ); - return null; + if( !media.setLabel( stack, StringUtil.normaliseLabel( label ) ) ) + { + throw new LuaException( "Disk label cannot be changed" ); + } + m_diskDrive.setDiskStack( stack ); + return null; + } ); } case 3: // hasData return new Object[] { m_diskDrive.getDiskMountPath( computer ) != null }; @@ -87,14 +93,16 @@ public class DiskDrivePeripheral implements IPeripheral case 5: { // hasAudio - IMedia media = m_diskDrive.getDiskMedia(); - return new Object[] { media != null && media.getAudio( m_diskDrive.getDiskStack() ) != null }; + ItemStack stack = m_diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + return new Object[] { media != null && media.getAudio( stack ) != null }; } case 6: { // getAudioTitle - IMedia media = m_diskDrive.getDiskMedia(); - return new Object[] { media != null ? media.getAudioTitle( m_diskDrive.getDiskStack() ) : false }; + ItemStack stack = m_diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + return new Object[] { media != null ? media.getAudioTitle( stack ) : false }; } case 7: // playAudio m_diskDrive.playDiskAudio(); @@ -131,8 +139,7 @@ public class DiskDrivePeripheral implements IPeripheral @Override public boolean equals( IPeripheral other ) { - if( this == other ) return true; - return other instanceof DiskDrivePeripheral && ((DiskDrivePeripheral) other).m_diskDrive == m_diskDrive; + return this == other || other instanceof DiskDrivePeripheral && ((DiskDrivePeripheral) other).m_diskDrive == m_diskDrive; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 83c0b35a0..8d46edd44 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -318,35 +318,31 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor } @Nonnull - public ItemStack getDiskStack() + ItemStack getDiskStack() { return getStackInSlot( 0 ); } - public void setDiskStack( @Nonnull ItemStack stack ) + void setDiskStack( @Nonnull ItemStack stack ) { setInventorySlotContents( 0, stack ); } - public IMedia getDiskMedia() + private IMedia getDiskMedia() { return MediaProviders.get( getDiskStack() ); } - public String getDiskMountPath( IComputerAccess computer ) + String getDiskMountPath( IComputerAccess computer ) { synchronized( this ) { - if( m_computers.containsKey( computer ) ) - { - MountInfo info = m_computers.get( computer ); - return info.mountPath; - } + MountInfo info = m_computers.get( computer ); + return info != null ? info.mountPath : null; } - return null; } - public void mount( IComputerAccess computer ) + void mount( IComputerAccess computer ) { synchronized( this ) { @@ -355,7 +351,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor } } - public void unmount( IComputerAccess computer ) + void unmount( IComputerAccess computer ) { synchronized( this ) { @@ -364,7 +360,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor } } - public void playDiskAudio() + void playDiskAudio() { synchronized( this ) { @@ -377,7 +373,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor } } - public void stopDiskAudio() + void stopDiskAudio() { synchronized( this ) { @@ -386,7 +382,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor } } - public void ejectDisk() + void ejectDisk() { synchronized( this ) { From 75e2845c01532987026ed028e97bab74e274a9dd Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 1 Aug 2019 14:09:57 +0100 Subject: [PATCH 059/711] Remove synchronized from turtle inventory code These should never be called off the server thread, so this doesn't make much difference. --- .../api/turtle/ITurtleAccess.java | 6 +- .../shared/turtle/FurnaceRefuelHandler.java | 2 +- .../shared/turtle/apis/TurtleAPI.java | 6 +- .../shared/turtle/blocks/TileTurtle.java | 142 ++++++------------ 4 files changed, 59 insertions(+), 97 deletions(-) diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 2c74d2543..b693de3a7 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -145,7 +145,9 @@ public interface ITurtleAccess GameProfile getOwningPlayer(); /** - * Get the inventory of this turtle + * Get the inventory of this turtle. + * + * Note: this inventory should only be accessed and modified on the server thread. * * @return This turtle's inventory * @see #getItemHandler() @@ -156,6 +158,8 @@ public interface ITurtleAccess /** * Get the inventory of this turtle as an {@link IItemHandlerModifiable}. * + * Note: this inventory should only be accessed and modified on the server thread. + * * @return This turtle's inventory * @see #getInventory() * @see IItemHandlerModifiable diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index d842b8615..feccb9543 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -33,7 +33,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler int fuelSpaceLeft = turtle.getFuelLimit() - turtle.getFuelLevel(); int fuelPerItem = getFuelPerItem( turtle.getItemHandler().getStackInSlot( slot ) ); int fuelItemLimit = (int) Math.ceil( fuelSpaceLeft / (double) fuelPerItem ); - if ( limit > fuelItemLimit ) limit = fuelItemLimit; + if( limit > fuelItemLimit ) limit = fuelItemLimit; ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false ); int fuelToGive = fuelPerItem * stack.getCount(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 475400aaa..573400499 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -334,9 +334,11 @@ public class TurtleAPI implements ILuaAPI return tryCommand( context, new TurtleInspectCommand( InteractDirection.Up ) ); case 40: // inspectDown return tryCommand( context, new TurtleInspectCommand( InteractDirection.Down ) ); - case 41: + case 41: // getItemDetail { - // getItemDetail + // FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...) + // on another thread. The obvious solution is to move this into a command, but some programs rely + // on this having a 0-tick delay. int slot = parseOptionalSlotNumber( args, 0, m_turtle.getSelectedSlot() ); ItemStack stack = m_turtle.getInventory().getStackInSlot( slot ); if( stack.isEmpty() ) return new Object[] { null }; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 353ce8d5d..e70c7d333 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -43,19 +43,16 @@ import net.minecraftforge.items.wrapper.InvWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collections; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; public class TileTurtle extends TileComputerBase implements ITurtleTile, DefaultInventory { - // Statics - public static final int INVENTORY_SIZE = 16; public static final int INVENTORY_WIDTH = 4; public static final int INVENTORY_HEIGHT = 4; - // Members - enum MoveState { NOT_MOVED, @@ -63,12 +60,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default MOVED } - private NonNullList m_inventory; - private NonNullList m_previousInventory; + private final NonNullList m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + private final NonNullList m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this ); - private boolean m_inventoryChanged; - private TurtleBrain m_brain; - private MoveState m_moveState; + private boolean m_inventoryChanged = false; + private TurtleBrain m_brain = new TurtleBrain( this ); + private MoveState m_moveState = MoveState.NOT_MOVED; private ComputerFamily m_family; public TileTurtle() @@ -78,15 +75,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public TileTurtle( ComputerFamily family ) { - m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); - m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); - m_inventoryChanged = false; - m_brain = new TurtleBrain( this ); - m_moveState = MoveState.NOT_MOVED; m_family = family; } - public boolean hasMoved() + private boolean hasMoved() { return m_moveState == MoveState.MOVED; } @@ -224,18 +216,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default { super.update(); m_brain.update(); - synchronized( m_inventory ) + if( !getWorld().isRemote && m_inventoryChanged ) { - if( !getWorld().isRemote && m_inventoryChanged ) - { - ServerComputer computer = getServerComputer(); - if( computer != null ) computer.queueEvent( "turtle_inventory" ); + ServerComputer computer = getServerComputer(); + if( computer != null ) computer.queueEvent( "turtle_inventory" ); - m_inventoryChanged = false; - for( int n = 0; n < getSizeInventory(); n++ ) - { - m_previousInventory.set( n, InventoryUtil.copyItem( getStackInSlot( n ) ) ); - } + m_inventoryChanged = false; + for( int n = 0; n < getSizeInventory(); n++ ) + { + m_previousInventory.set( n, InventoryUtil.copyItem( getStackInSlot( n ) ) ); } } } @@ -270,8 +259,8 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default // Read inventory NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND ); - m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); - m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + m_inventory.clear(); + m_previousInventory.clear(); for( int i = 0; i < nbttaglist.tagCount(); i++ ) { NBTTagCompound tag = nbttaglist.getCompoundTagAt( i ); @@ -382,7 +371,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default return m_family; } - public void setOwningPlayer( GameProfile player ) + void setOwningPlayer( GameProfile player ) { m_brain.setOwningPlayer( player ); markDirty(); @@ -410,109 +399,76 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public ItemStack getStackInSlot( int slot ) { - if( slot >= 0 && slot < INVENTORY_SIZE ) - { - synchronized( m_inventory ) - { - return m_inventory.get( slot ); - } - } - return ItemStack.EMPTY; + return slot >= 0 && slot < INVENTORY_SIZE ? m_inventory.get( slot ) : ItemStack.EMPTY; } @Nonnull @Override public ItemStack removeStackFromSlot( int slot ) { - synchronized( m_inventory ) - { - ItemStack result = getStackInSlot( slot ); - setInventorySlotContents( slot, ItemStack.EMPTY ); - return result; - } + ItemStack result = getStackInSlot( slot ); + setInventorySlotContents( slot, ItemStack.EMPTY ); + return result; } @Nonnull @Override public ItemStack decrStackSize( int slot, int count ) { - if( count == 0 ) + if( count == 0 ) return ItemStack.EMPTY; + + ItemStack stack = getStackInSlot( slot ); + if( stack.isEmpty() ) return ItemStack.EMPTY; + + if( stack.getCount() <= count ) { - return ItemStack.EMPTY; + setInventorySlotContents( slot, ItemStack.EMPTY ); + return stack; } - synchronized( m_inventory ) - { - ItemStack stack = getStackInSlot( slot ); - if( stack.isEmpty() ) - { - return ItemStack.EMPTY; - } - - if( stack.getCount() <= count ) - { - setInventorySlotContents( slot, ItemStack.EMPTY ); - return stack; - } - - ItemStack part = stack.splitStack( count ); - onInventoryDefinitelyChanged(); - return part; - } + ItemStack part = stack.splitStack( count ); + onInventoryDefinitelyChanged(); + return part; } @Override public void setInventorySlotContents( int i, @Nonnull ItemStack stack ) { - if( i >= 0 && i < INVENTORY_SIZE ) + if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, m_inventory.get( i ) ) ) { - synchronized( m_inventory ) - { - if( !InventoryUtil.areItemsEqual( stack, m_inventory.get( i ) ) ) - { - m_inventory.set( i, stack ); - onInventoryDefinitelyChanged(); - } - } + m_inventory.set( i, stack ); + onInventoryDefinitelyChanged(); } } @Override public void clear() { - synchronized( m_inventory ) + boolean changed = false; + for( int i = 0; i < INVENTORY_SIZE; i++ ) { - boolean changed = false; - for( int i = 0; i < INVENTORY_SIZE; i++ ) + if( !m_inventory.get( i ).isEmpty() ) { - if( !m_inventory.get( i ).isEmpty() ) - { - m_inventory.set( i, ItemStack.EMPTY ); - changed = true; - } - } - if( changed ) - { - onInventoryDefinitelyChanged(); + m_inventory.set( i, ItemStack.EMPTY ); + changed = true; } } + + if( changed ) onInventoryDefinitelyChanged(); } @Override public void markDirty() { super.markDirty(); - synchronized( m_inventory ) + if( !m_inventoryChanged ) { - if( !m_inventoryChanged ) + for( int n = 0; n < getSizeInventory(); n++ ) { - for( int n = 0; n < getSizeInventory(); n++ ) + if( !ItemStack.areItemStacksEqual( getStackInSlot( n ), m_previousInventory.get( n ) ) ) { - if( !ItemStack.areItemStacksEqual( getStackInSlot( n ), m_previousInventory.get( n ) ) ) - { - m_inventoryChanged = true; - break; - } + m_inventoryChanged = true; + break; } } } @@ -574,8 +530,8 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public void transferStateFrom( TileTurtle copy ) { super.transferStateFrom( copy ); - m_inventory = copy.m_inventory; - m_previousInventory = copy.m_previousInventory; + Collections.copy( m_inventory, copy.m_inventory ); + Collections.copy( m_previousInventory, copy.m_previousInventory ); m_inventoryChanged = copy.m_inventoryChanged; m_brain = copy.m_brain; m_brain.setOwner( this ); From 35c7792aa2e4f09ab41823863055c6f84c1bc04b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Aug 2019 08:59:44 +0100 Subject: [PATCH 060/711] Limit the titles of printed pages Just enforce the same restrictions as we do for computer/disk labels. --- .../shared/peripheral/printer/PrinterPeripheral.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index e88202014..91ea62895 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -11,6 +11,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.util.StringUtil; import javax.annotation.Nonnull; @@ -108,7 +109,7 @@ public class PrinterPeripheral implements IPeripheral // setPageTitle String title = optString( args, 0, "" ); getCurrentPage(); - m_printer.setPageTitle( title ); + m_printer.setPageTitle( StringUtil.normaliseLabel( title ) ); return null; } case 8: // getPaperLevel From eb5cff104537ef0d0f2e33fd5110dfaafce4163f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Aug 2019 09:27:48 +0100 Subject: [PATCH 061/711] Alright, let's do this one last time --- .../resources/assets/computercraft/lua/rom/help/changelog.txt | 2 ++ .../resources/assets/computercraft/lua/rom/help/whatsnew.txt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index ae4ebbbc7..c9fb3ad1b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -12,6 +12,8 @@ And several bug fixes: * Do not load chunks when calling writeDescription. * Fix the signature of loadfile * Fix turtles harvesting blocks multiple times +* Improve thread-safety of various peripherals +* Prevent printed pages having massive/malformed titles # New features in CC: Tweaked 1.83.1 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 3c7ecacdd..20957867e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -12,5 +12,7 @@ And several bug fixes: * Do not load chunks when calling writeDescription. * Fix the signature of loadfile * Fix turtles harvesting blocks multiple times +* Improve thread-safety of various peripherals +* Prevent printed pages having massive/malformed titles Type "help changelog" to see the full version history. From e6c691a8f8614e8136263a3873d1a3533ab1a171 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Aug 2019 11:02:07 +0100 Subject: [PATCH 062/711] Fix rom's location This isn't going to get annoying or anything --- .../computercraft/lua/rom/modules/main/cc/expect.lua | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{assets => data}/computercraft/lua/rom/modules/main/cc/expect.lua (100%) diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua similarity index 100% rename from src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua rename to src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua From 08d22fd3dfb8e658d66272288206d16b933c83e3 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Aug 2019 11:05:14 +0100 Subject: [PATCH 063/711] Fix changelog being out-of-sync --- .../resources/data/computercraft/lua/rom/help/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index c9fb3ad1b..90cd8c0a9 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,4 +1,4 @@ -New features in CC: Tweaked 1.84.0 +# New features in CC: Tweaked 1.84.0 * Improve validation in rename, copy and delete programs * Add window.getLine - the inverse of blit From 46d78af068f5f4de1894e49f1e4d6fc83a88ff3d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Aug 2019 11:05:14 +0100 Subject: [PATCH 064/711] Fix changelog being out-of-sync --- .../resources/assets/computercraft/lua/rom/help/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index c9fb3ad1b..90cd8c0a9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,4 +1,4 @@ -New features in CC: Tweaked 1.84.0 +# New features in CC: Tweaked 1.84.0 * Improve validation in rename, copy and delete programs * Add window.getLine - the inverse of blit From 455a59ca85765c83cdedceed005933e7b74ae0ec Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Aug 2019 17:01:52 +0100 Subject: [PATCH 065/711] Sure, you can be an actual release now --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 94f7d11c3..49ae9b524 100644 --- a/build.gradle +++ b/build.gradle @@ -379,7 +379,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'beta' + releaseType = 'release' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { @@ -455,7 +455,7 @@ githubRelease { .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() } - prerelease true + prerelease false } def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] From a0e72d02c8ceee5fe04de667b9fea96a016e844b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 6 Aug 2019 08:33:39 +0100 Subject: [PATCH 066/711] Bump Forge version --- build.gradle | 2 +- gradle.properties | 4 ++-- src/main/java/dan200/computercraft/client/FrameInfo.java | 2 +- .../computercraft/shared/proxy/ComputerCraftProxyCommon.java | 4 ++-- .../java/dan200/computercraft/shared/util/TickScheduler.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 49ae9b524..7a1eb5bb7 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.130' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.134' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } diff --git a/gradle.properties b/gradle.properties index 44330812b..12b36f573 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.84.0 # Minecraft properties mc_version=1.14.4 -forge_version=28.0.11 -mappings_version=20190721-1.14.3 +forge_version=28.0.45 +mappings_version=20190806-1.14.3 diff --git a/src/main/java/dan200/computercraft/client/FrameInfo.java b/src/main/java/dan200/computercraft/client/FrameInfo.java index 0466b8684..aef1f584d 100644 --- a/src/main/java/dan200/computercraft/client/FrameInfo.java +++ b/src/main/java/dan200/computercraft/client/FrameInfo.java @@ -8,9 +8,9 @@ package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.gameevent.TickEvent; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class FrameInfo diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 67fdc4b88..11490e9ae 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -34,11 +34,11 @@ import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.conditions.LootConditionManager; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.gameevent.TickEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; @@ -146,7 +146,7 @@ public final class ComputerCraftProxyCommon IComputer computer = ((IContainerComputer) container).getComputer(); if( computer instanceof ServerComputer ) { - ((ServerComputer) computer).sendTerminalState( event.getEntityPlayer() ); + ((ServerComputer) computer).sendTerminalState( event.getPlayer() ); } } } diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 50a3bcad6..ba92ceaab 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -13,9 +13,9 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.ITickList; import net.minecraft.world.World; +import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.gameevent.TickEvent; import java.util.Collections; import java.util.Iterator; From 07a56454a0d70d63600d366ff3ccb495904ddf1a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 9 Aug 2019 09:38:30 +0100 Subject: [PATCH 067/711] Bumpity bumpity bump --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 4 ++++ .../computercraft/lua/rom/help/whatsnew.txt | 17 ++--------------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index 12b36f573..4f99ef545 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.84.0 +mod_version=1.84.1 # Minecraft properties mc_version=1.14.4 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 90cd8c0a9..0091e15a9 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.84.1 + +* Update to latest Forge + # New features in CC: Tweaked 1.84.0 * Improve validation in rename, copy and delete programs diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 20957867e..0059f42fd 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,18 +1,5 @@ -New features in CC: Tweaked 1.84.0 +New features in CC: Tweaked 1.84.1 -* Improve validation in rename, copy and delete programs -* Add window.getLine - the inverse of blit -* turtle.refuel no longer consumes more fuel than needed -* Add "cc.expect" module, for improved argument type checks -* Mount the ROM from all mod jars, not just CC's - -And several bug fixes: -* Ensure file error messages use the absolute correct path -* Fix NPE when closing a file multiple times. -* Do not load chunks when calling writeDescription. -* Fix the signature of loadfile -* Fix turtles harvesting blocks multiple times -* Improve thread-safety of various peripherals -* Prevent printed pages having massive/malformed titles +* Update to latest Forge Type "help changelog" to see the full version history. From 1c46949da70a99d9515f7d6a252f3539818490e9 Mon Sep 17 00:00:00 2001 From: Lignum Date: Thu, 15 Aug 2019 07:37:02 +0200 Subject: [PATCH 068/711] Available --- .../resources/assets/computercraft/lua/rom/programs/help.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/help.lua b/src/main/resources/assets/computercraft/lua/rom/programs/help.lua index 5dc7f09d9..2925cf72d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/help.lua @@ -7,7 +7,7 @@ else end if sTopic == "index" then - print( "Help topics availiable:" ) + print( "Help topics available:" ) local tTopics = help.topics() textutils.pagedTabulate( tTopics ) return From f1d6d21d6d5865894595b4bec18db54a2a98c41a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 18 Aug 2019 16:12:16 +0100 Subject: [PATCH 069/711] Add back texture registration hook I totally forgot to do this when Forge re-added this functionality. Fixes #285 --- build.gradle | 4 ++-- .../dan200/computercraft/client/ClientRegistry.java | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 7a1eb5bb7..b23548fc1 100644 --- a/build.gradle +++ b/build.gradle @@ -94,11 +94,11 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7:api") + compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.10:api") // deobfProvided "pl.asie:Charset-Lib:0.5.4.6" // deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" - runtimeOnly fg.deobf("mezz.jei:jei-1.14.3:6.0.0.7") + runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.10") shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 22bc90878..1a5efaefb 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -12,6 +12,7 @@ import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.model.ModelResourceLocation; @@ -58,8 +59,8 @@ public final class ClientRegistry }; private static final String[] EXTRA_TEXTURES = new String[] { - // TODO: Gather these automatically from the model. I'm unable to get this working with Forge's current - // model loading code. + // TODO: Gather these automatically from the model. Sadly the model loader isn't available + // when stitching textures. "block/turtle_colour", "block/turtle_elf_overlay", "block/turtle_crafty_face", @@ -77,13 +78,12 @@ public final class ClientRegistry @SubscribeEvent public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) { - /* - IResourceManager manager = Minecraft.getInstance().getResourceManager(); + if( event.getMap() != Minecraft.getInstance().getTextureMap() ) return; + for( String extra : EXTRA_TEXTURES ) { - // TODO: event.getMap().registerSprite( manager, new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); + event.addSprite( new ResourceLocation( ComputerCraft.MOD_ID, extra ) ); } - */ } @SubscribeEvent From a802f25dd6659826a3c2f82e7c5e36cd25c53651 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 19 Aug 2019 10:33:53 +0100 Subject: [PATCH 070/711] Do not listen to block/entity drop events It appears several mods inject their own drops on the LOWEST priority, meaning that we capture the existing drops, and the other mod will clear the (now empty) drop list and add its own, resulting in dupe bugs. While I'd argue it's somewhat dubious doing this on the LOWEST priority, it's not a battle I'm prepared to fight. For now, we just remove the block/entity drop handlers, and handle all drop logic when entities are spawned. Fixes #288 --- .../shared/util/DropConsumer.java | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 94a053aa9..4e8a973c2 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -14,8 +14,6 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.entity.EntityJoinWorldEvent; -import net.minecraftforge.event.entity.living.LivingDropsEvent; -import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; @@ -35,7 +33,6 @@ public final class DropConsumer private static Function dropConsumer; private static List remainingDrops; private static WeakReference dropWorld; - private static BlockPos dropPos; private static AxisAlignedBB dropBounds; private static WeakReference dropEntity; @@ -45,7 +42,6 @@ public final class DropConsumer remainingDrops = new ArrayList<>(); dropEntity = new WeakReference<>( entity ); dropWorld = new WeakReference<>( entity.world ); - dropPos = null; dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); entity.captureDrops = true; @@ -54,10 +50,9 @@ public final class DropConsumer public static void set( World world, BlockPos pos, Function consumer ) { dropConsumer = consumer; - remainingDrops = new ArrayList<>(); + remainingDrops = new ArrayList<>( 2 ); dropEntity = null; dropWorld = new WeakReference<>( world ); - dropPos = pos; dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 ); } @@ -83,7 +78,6 @@ public final class DropConsumer remainingDrops = null; dropEntity = null; dropWorld = null; - dropPos = null; dropBounds = null; return remainingStacks; @@ -95,33 +89,6 @@ public final class DropConsumer if( !remaining.isEmpty() ) remainingDrops.add( remaining ); } - @SubscribeEvent( priority = EventPriority.LOWEST ) - public static void onEntityLivingDrops( LivingDropsEvent event ) - { - // Capture any mob drops for the current entity - if( dropEntity != null && event.getEntity() == dropEntity.get() ) - { - List drops = event.getDrops(); - for( EntityItem entityItem : drops ) handleDrops( entityItem.getItem() ); - drops.clear(); - } - } - - @SubscribeEvent( priority = EventPriority.LOWEST ) - public static void onHarvestDrops( BlockEvent.HarvestDropsEvent event ) - { - // Capture block drops for the current entity - if( dropWorld != null && dropWorld.get() == event.getWorld() - && dropPos != null && dropPos.equals( event.getPos() ) ) - { - for( ItemStack item : event.getDrops() ) - { - if( event.getWorld().rand.nextFloat() < event.getDropChance() ) handleDrops( item ); - } - event.getDrops().clear(); - } - } - @SubscribeEvent( priority = EventPriority.LOWEST ) public static void onEntitySpawn( EntityJoinWorldEvent event ) { From 1e7f1c98fc9b6f4036c408c381fce77794531770 Mon Sep 17 00:00:00 2001 From: parly Date: Mon, 19 Aug 2019 23:04:57 +0900 Subject: [PATCH 071/711] Fix os.time() and os.day() behavior --- .../computercraft/shared/computer/core/ServerComputer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 2edcc9c7c..a63dbba7a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -311,13 +311,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput @Override public double getTimeOfDay() { - return (m_world.getGameTime() + 6000) % 24000 / 1000.0; + return (m_world.getDayTime() + 6000) % 24000 / 1000.0; } @Override public int getDay() { - return (int) ((m_world.getGameTime() + 6000) / 24000) + 1; + return (int) ((m_world.getDayTime() + 6000) / 24000) + 1; } @Override From b1139a4bf6f3dba4ee30366b1511bfce12b5eecb Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 12 Sep 2019 21:09:57 +0100 Subject: [PATCH 072/711] Bump to Forge RB --- build.gradle | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index b23548fc1..61e98e720 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.134' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.142' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } diff --git a/gradle.properties b/gradle.properties index 4f99ef545..b46b21df2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.84.1 # Minecraft properties mc_version=1.14.4 -forge_version=28.0.45 -mappings_version=20190806-1.14.3 +forge_version=28.1.1 +mappings_version=20190912-1.14.3 From 49c37857d40aba66a1e3171082220c98dcdb717d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 13 Sep 2019 20:55:20 +0100 Subject: [PATCH 073/711] Window.reposition now allow changing the redirect buffer See #270 --- .../computercraft/lua/rom/apis/window.lua | 6 +++++- .../test-rom/spec/apis/window_spec.lua | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index b1e1b3db4..87ede5cbd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -431,16 +431,20 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nX, nY end - function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight ) + function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight, newParent ) if type(nNewX) ~= "number" then expect(1, nNewX, "number") end if type(nNewY) ~= "number" then expect(2, nNewY, "number") end if nNewWidth ~= nil or nNewHeight ~= nil then expect(3, nNewWidth, "number") expect(4, nNewHeight, "number") end + if newParent ~= nil and type(newParent) ~= "table" then expect(5, newParent, "table") end nX = nNewX nY = nNewY + + if newParent then parent = newParent end + if nNewWidth and nNewHeight then local tNewLines = {} createEmptyLines( nNewWidth ) diff --git a/src/test/resources/test-rom/spec/apis/window_spec.lua b/src/test/resources/test-rom/spec/apis/window_spec.lua index 2fb6d119d..cb2905951 100644 --- a/src/test/resources/test-rom/spec/apis/window_spec.lua +++ b/src/test/resources/test-rom/spec/apis/window_spec.lua @@ -118,6 +118,26 @@ describe("The window library", function() expect.error(w.reposition, 1, 1, false, 1):eq("bad argument #3 (expected number, got boolean)") expect.error(w.reposition, 1, 1, nil, 1):eq("bad argument #3 (expected number, got nil)") expect.error(w.reposition, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") + expect.error(w.reposition, 1, 1, 1, 1, true):eq("bad argument #5 (expected table, got boolean)") + end) + + it("can change the buffer", function() + local a, b = mk(), mk() + local target = window.create(a, 1, 1, a.getSize()) + + target.write("Test") + expect((a.getLine(1))):equal("Test ") + expect({ a.getCursorPos() }):same { 5, 1 } + + target.reposition(1, 1, nil, nil, b) + + target.redraw() + expect((a.getLine(1))):equal("Test ") + expect({ a.getCursorPos() }):same { 5, 1 } + + target.setCursorPos(1, 1) target.write("More") + expect((a.getLine(1))):equal("Test ") + expect((b.getLine(1))):equal("More ") end) end) From cbc0c1d0b66c4f606b3ef6b32cdd726f1dd5df1b Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 14 Sep 2019 09:16:13 +0100 Subject: [PATCH 074/711] A little experiment with GitHub actions Let's give this a go. --- .github/workflows/main-ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/main-ci.yml diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml new file mode 100644 index 000000000..864c86aba --- /dev/null +++ b/.github/workflows/main-ci.yml @@ -0,0 +1,19 @@ +name: Java CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: Build with Gradle + run: ./gradlew build --no-daemon From 9bd8c86a948c1927cc84f9afcc2d31a496fc8db2 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 15 Sep 2019 16:36:47 +0100 Subject: [PATCH 075/711] Change event priority to HIGHEST See the comments in a802f25dd6659826a3c2f82e7c5e36cd25c53651 - effectively we want to make sure we arrive before any other thing which may capture items (some magnet mods, etc...). --- .../java/dan200/computercraft/shared/util/DropConsumer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 4e8a973c2..ec11947aa 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -89,7 +89,7 @@ public final class DropConsumer if( !remaining.isEmpty() ) remainingDrops.add( remaining ); } - @SubscribeEvent( priority = EventPriority.LOWEST ) + @SubscribeEvent( priority = EventPriority.HIGHEST ) public static void onEntitySpawn( EntityJoinWorldEvent event ) { // Capture any nearby item spawns From 8e4d311cd934e93d7a09ba0c2133d76880d1a1f6 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 15 Sep 2019 18:48:40 +0100 Subject: [PATCH 076/711] Refactor shell completion into a separate module (#281) - Adds cc.completions module, with a couple of helper functions for working with the more general completion functionality (i.e. that provided by read). - Adds cc.shell.completions module, which provides shell-specific completion functions. - Add a "program completion builder", which allows you to write stuff like this: shell.setCompletionFunction( "rom/programs/redstone.lua", completion.build( { completion.choice, { "probe", "set ", "pulse " } }, completion.side) ) Closes #232 --- .../lua/rom/modules/main/cc/completion.lua | 105 +++++++ .../rom/modules/main/cc/shell/completion.lua | 151 ++++++++++ .../assets/computercraft/lua/rom/startup.lua | 274 +++++------------- .../spec/modules/cc/completion_spec.lua | 57 ++++ .../spec/modules/cc/shell/completion_spec.lua | 41 +++ .../test-rom/spec/programs/mkdir_spec.lua | 4 +- 6 files changed, 428 insertions(+), 204 deletions(-) create mode 100644 src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua create mode 100644 src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua create mode 100644 src/test/resources/test-rom/spec/modules/cc/completion_spec.lua create mode 100644 src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua new file mode 100644 index 000000000..4634bcc98 --- /dev/null +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua @@ -0,0 +1,105 @@ +--- A collection of helper methods for working with input completion, such +-- as that require by @{read}. +-- +-- @module craftos.completion +-- @see cc.shell.completion For additional helpers to use with +-- @{shell.setCompletionFunction}. + +local expect = require "cc.expect".expect + +local function choice_impl(text, choices, add_space) + local results = {} + for n = 1, #choices do + local option = choices[n] + if #option + (add_space and 1 or 0) > #text and option:sub(1, #text) == text then + local result = option:sub(#text + 1) + if add_space then + table.insert(results, result .. " ") + else + table.insert(results, result) + end + end + end + return results +end + +--- Complete from a choice of one or more strings. +-- +-- @tparam string text The input string to complete. +-- @tparam { string... } choices The list of choices to complete from. +-- @tparam[opt] boolean add_space Whether to add a space after the completed item. +-- @treturn { string... } A list of suffixes of matching strings. +-- @usage Call @{read}, completing the names of various animals. +-- +-- local animals = { "dog", "cat", "lion", "unicorn" } +-- read(nil, nil, function(text) return choice(text, animals) end) +local function choice(text, choices, add_space) + expect(1, text, "string") + expect(2, choices, "table") + expect(3, add_space, "boolean", "nil") + return choice_impl(text, choices, add_space) +end + +--- Complete the name of a currently attached peripheral. +-- +-- @tparam string text The input string to complete. +-- @tparam[opt] boolean add_space Whether to add a space after the completed name. +-- @treturn { string... } A list of suffixes of matching peripherals. +-- @usage read(nil, nil, peripheral) +local function peripheral_(text, add_space) + expect(1, text, "string") + expect(2, add_space, "boolean", "nil") + return choice_impl(text, peripheral.getNames(), add_space) +end + +local sides = redstone.getSides() + +--- Complete the side of a computer. +-- +-- @tparam string text The input string to complete. +-- @tparam[opt] boolean add_space Whether to add a space after the completed side. +-- @treturn { string... } A list of suffixes of matching sides. +-- @usage read(nil, nil, side) +local function side(text, add_space) + expect(1, text, "string") + expect(2, add_space, "boolean", "nil") + return choice_impl(text, sides, add_space) +end + +--- Complete a @{settings|setting}. +-- +-- @tparam string text The input string to complete. +-- @tparam[opt] boolean add_space Whether to add a space after the completed settings. +-- @treturn { string... } A list of suffixes of matching settings. +-- @usage read(nil, nil, setting) +local function setting(text, add_space) + expect(1, text, "string") + expect(2, add_space, "boolean", "nil") + return choice_impl(text, settings.getNames(), add_space) +end + +local command_list + +--- Complete the name of a Minecraft @{commands|command}. +-- +-- @tparam string text The input string to complete. +-- @tparam[opt] boolean add_space Whether to add a space after the completed command. +-- @treturn { string... } A list of suffixes of matching commands. +-- @usage read(nil, nil, command) +local function command(text, add_space) + expect(1, text, "string") + expect(2, add_space, "boolean", "nil") + if command_list == nil then + command_list = commands and commands.list() or {} + end + + return choice_impl(text, command_list, add_space) +end + +return { + choice = choice, + peripheral = peripheral_, + side = side, + setting = setting, + command = command, +} diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua new file mode 100644 index 000000000..023e500fc --- /dev/null +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -0,0 +1,151 @@ +--- A collection of helper methods for working with shell completion. +-- +-- Most programs may be completed using the @{build} helper method, rather than +-- manually switching on the argument index. +-- +-- Note, the helper functions within this module do not accept an argument index, +-- and so are not directly usable with the @{shell.setCompletionFunction}. Instead, +-- wrap them using @{build}, or your own custom function. +-- +-- @module craftos.shell.completion +-- @see cc.completion For more general helpers, suitable for use with @{read}. +-- @see shell.setCompletionFunction + +local expect = require "cc.expect".expect +local completion = require "cc.completion" + +--- Complete the name of a file relative to the current working directory. +-- +-- @tparam shell shell The shell we're completing in +-- @tparam { string... } choices The list of choices to complete from. +-- @treturn { string... } A list of suffixes of matching files. +local function file(shell, text) + return fs.complete(text, shell.dir(), true, false) +end + +--- Complete the name of a directory relative to the current working directory. +-- +-- @tparam shell shell The shell we're completing in +-- @tparam { string... } choices The list of choices to complete from. +-- @treturn { string... } A list of suffixes of matching directories. +local function dir(shell, text) + return fs.complete(text, shell.dir(), false, true) +end + +--- Complete the name of a file or directory relative to the current working +-- directory. +-- +-- @tparam shell shell The shell we're completing in +-- @tparam { string... } choices The list of choices to complete from. +-- @tparam { string... } previous The shell arguments before this one. +-- @tparam[opt] boolean add_space Whether to add a space after the completed item. +-- @treturn { string... } A list of suffixes of matching files and directories. +local function dirOrFile(shell, text, previous, add_space) + local results = fs.complete(text, shell.dir(), true, true) + if add_space then + for n = 1, #results do + local result = results[n] + if result:sub(-1) ~= "/" then + results[n] = result .. " " + end + end + end + return results +end + +local function wrap(func) + return function(shell, text, previous, ...) + return func(text, ...) + end +end + +--- Complete the name of a program. +-- +-- @tparam shell shell The shell we're completing in +-- @tparam { string... } choices The list of choices to complete from. +-- @treturn { string... } A list of suffixes of matching programs. +local function program(shell, text) + return shell.completeProgram(text) +end + +--- A helper function for building shell completion arguments. +-- +-- This accepts a series of single-argument completion functions, and combines +-- them into a function suitable for use with @{shell.setCompletionFunction}. +-- +-- @tparam nil|table|function ... Every argument to @{build} represents an argument +-- to the program you wish to complete. Each argument can be one of three types: +-- +-- - `nil`: This argument will not be completed. +-- +-- - A function: This argument will be completed with the given function. It is +-- called with the @{shell} object, the string to complete and the arguments +-- before this one. +-- +-- - A table: This acts as a more powerful version of the function case. The table +-- must have a function as the first item - this will be called with the shell, +-- string and preceding arguments as above, but also followed by any additional +-- items in the table. This provides a more convenient interface to pass +-- options to your completion functions. +-- +-- If this table is the last argument, it may also set the `many` key to true, +-- which states this function should be used to complete any remaining arguments. +-- +-- @usage Prompt for a choice of options, followed by a directory, and then multiple +-- files. +-- +-- complete.build( +-- { complete.choice, { "get", "put" } }, +-- complete.dir, +-- } complete.file, many = true } +-- ) +local function build(...) + local arguments = table.pack(...) + for i = 1, arguments.n do + local arg = arguments[i] + if arg ~= nil then + expect(i, arg, "table", "function") + if type(arg) == "function" then + arg = { arg } + arguments[i] = arg + end + + if type(arg[1]) ~= "function" then + error(("Bad table entry #1 at argument #%d (expected function, got %s)"):format(i, type(arg[1])), 2) + end + + if arg.many and i < arguments.n then + error(("Unexpected 'many' field on argument #%d (should only occur on the last argument)"):format(i), 2) + end + end + end + + return function(shell, index, text, previous) + local arg = arguments[index] + if not arg then + if index <= arguments.n then return end + + arg = arguments[arguments.n] + if not arg or not arg.many then return end + end + + return arg[1](shell, text, previous, table.unpack(arg, 2)) + end +end + +return { + file = file, + dir = dir, + dirOrFile = dirOrFile, + program = program, + + -- Re-export various other functions + help = wrap(help.completeTopic), + choice = wrap(completion.choice), + peripheral = wrap(completion.peripheral), + side = wrap(completion.side), + setting = wrap(completion.setting), + command = wrap(completion.command), + + build = build, +} diff --git a/src/main/resources/assets/computercraft/lua/rom/startup.lua b/src/main/resources/assets/computercraft/lua/rom/startup.lua index 2bc19adca..e6b396b39 100644 --- a/src/main/resources/assets/computercraft/lua/rom/startup.lua +++ b/src/main/resources/assets/computercraft/lua/rom/startup.lua @@ -1,3 +1,4 @@ +local completion = require "cc.shell.completion" -- Setup paths local sPath = ".:/rom/programs" @@ -39,217 +40,86 @@ if term.isColor() then end -- Setup completion functions -local function completeMultipleChoice( sText, tOptions, bAddSpaces ) - local tResults = {} - for n=1,#tOptions do - local sOption = tOptions[n] - if #sOption + (bAddSpaces and 1 or 0) > #sText and string.sub( sOption, 1, #sText ) == sText then - local sResult = string.sub( sOption, #sText + 1 ) - if bAddSpaces then - table.insert( tResults, sResult .. " " ) - else - table.insert( tResults, sResult ) - end - end - end - return tResults -end -local function completePeripheralName( sText, bAddSpaces ) - return completeMultipleChoice( sText, peripheral.getNames(), bAddSpaces ) -end -local tRedstoneSides = redstone.getSides() -local function completeSide( sText, bAddSpaces ) - return completeMultipleChoice( sText, tRedstoneSides, bAddSpaces ) -end -local function completeFile( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return fs.complete( sText, shell.dir(), true, false ) + +local function completePastebinPut(shell, text, previous) + if previous[2] == "put" then + return fs.complete(text, shell.dir(), true, false ) end end -local function completeFileMany( shell, nIndex, sText, tPreviousText ) - return fs.complete( sText, shell.dir(), true, false ) -end -local function completeDir( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return fs.complete( sText, shell.dir(), false, true ) - end -end -local function completeEither( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return fs.complete( sText, shell.dir(), true, true ) - end -end -local function completeEitherMany( shell, nIndex, sText, tPreviousText ) - return fs.complete( sText, shell.dir(), true, true ) -end -local function completeEitherEither( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - local tResults = fs.complete( sText, shell.dir(), true, true ) - for n=1,#tResults do - local sResult = tResults[n] - if string.sub( sResult, #sResult, #sResult ) ~= "/" then - tResults[n] = sResult .. " " - end - end - return tResults - elseif nIndex == 2 then - return fs.complete( sText, shell.dir(), true, true ) - end -end -local function completeProgram( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return shell.completeProgram( sText ) - end -end -local function completeHelp( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return help.completeTopic( sText ) - end -end -local function completeAlias( shell, nIndex, sText, tPreviousText ) - if nIndex == 2 then - return shell.completeProgram( sText ) - end -end -local function completePeripheral( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completePeripheralName( sText ) - end -end -local tGPSOptions = { "host", "host ", "locate" } -local function completeGPS( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tGPSOptions ) - end -end -local tLabelOptions = { "get", "get ", "set ", "clear", "clear " } -local function completeLabel( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tLabelOptions ) - elseif nIndex == 2 then - return completePeripheralName( sText ) - end -end -local function completeMonitor( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completePeripheralName( sText, true ) - elseif nIndex == 2 then - return shell.completeProgram( sText ) - end -end -local tRedstoneOptions = { "probe", "set ", "pulse " } -local function completeRedstone( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tRedstoneOptions ) - elseif nIndex == 2 then - return completeSide( sText ) - end -end -local tDJOptions = { "play", "play ", "stop " } -local function completeDJ( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tDJOptions ) - elseif nIndex == 2 then - return completePeripheralName( sText ) - end -end -local tPastebinOptions = { "put ", "get ", "run " } -local function completePastebin( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tPastebinOptions ) - elseif nIndex == 2 then - if tPreviousText[2] == "put" then - return fs.complete( sText, shell.dir(), true, false ) - end - end -end -local tChatOptions = { "host ", "join " } -local function completeChat( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tChatOptions ) - end -end -local function completeSet( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, settings.getNames(), true ) - end -end -local tCommands -if commands then - tCommands = commands.list() -end -local function completeExec( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 and commands then - return completeMultipleChoice( sText, tCommands, true ) - end -end -local tWgetOptions = { "run" } -local function completeWget( shell, nIndex, sText, tPreviousText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tWgetOptions, true ) - end -end -shell.setCompletionFunction( "rom/programs/alias.lua", completeAlias ) -shell.setCompletionFunction( "rom/programs/cd.lua", completeDir ) -shell.setCompletionFunction( "rom/programs/copy.lua", completeEitherEither ) -shell.setCompletionFunction( "rom/programs/delete.lua", completeEitherMany ) -shell.setCompletionFunction( "rom/programs/drive.lua", completeDir ) -shell.setCompletionFunction( "rom/programs/edit.lua", completeFile ) -shell.setCompletionFunction( "rom/programs/eject.lua", completePeripheral ) -shell.setCompletionFunction( "rom/programs/gps.lua", completeGPS ) -shell.setCompletionFunction( "rom/programs/help.lua", completeHelp ) -shell.setCompletionFunction( "rom/programs/id.lua", completePeripheral ) -shell.setCompletionFunction( "rom/programs/label.lua", completeLabel ) -shell.setCompletionFunction( "rom/programs/list.lua", completeDir ) -shell.setCompletionFunction( "rom/programs/mkdir.lua", completeFileMany ) -shell.setCompletionFunction( "rom/programs/monitor.lua", completeMonitor ) -shell.setCompletionFunction( "rom/programs/move.lua", completeEitherEither ) -shell.setCompletionFunction( "rom/programs/redstone.lua", completeRedstone ) -shell.setCompletionFunction( "rom/programs/rename.lua", completeEitherEither ) -shell.setCompletionFunction( "rom/programs/shell.lua", completeProgram ) -shell.setCompletionFunction( "rom/programs/type.lua", completeEither ) -shell.setCompletionFunction( "rom/programs/set.lua", completeSet ) -shell.setCompletionFunction( "rom/programs/advanced/bg.lua", completeProgram ) -shell.setCompletionFunction( "rom/programs/advanced/fg.lua", completeProgram ) -shell.setCompletionFunction( "rom/programs/fun/dj.lua", completeDJ ) -shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completeFile ) -shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completePastebin ) -shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completeChat ) -shell.setCompletionFunction( "rom/programs/command/exec.lua", completeExec ) -shell.setCompletionFunction( "rom/programs/http/wget.lua", completeWget ) + +shell.setCompletionFunction( "rom/programs/alias.lua", completion.build(nil, completion.program) ) +shell.setCompletionFunction( "rom/programs/cd.lua", completion.build(completion.dir) ) +shell.setCompletionFunction( "rom/programs/copy.lua", completion.build( + { completion.dirOrFile, true }, + completion.dirOrFile +) ) +shell.setCompletionFunction( "rom/programs/delete.lua", completion.build({ completion.dirOrFile, many = true }) ) +shell.setCompletionFunction( "rom/programs/drive.lua", completion.build(completion.dir) ) +shell.setCompletionFunction( "rom/programs/edit.lua", completion.build(completion.file) ) +shell.setCompletionFunction( "rom/programs/eject.lua", completion.build(completion.peripheral) ) +shell.setCompletionFunction( "rom/programs/gps.lua", completion.build({ completion.choice, { "host", "host ", "locate" } }) ) +shell.setCompletionFunction( "rom/programs/help.lua", completion.build(completion.help) ) +shell.setCompletionFunction( "rom/programs/id.lua", completion.build(completion.peripheral) ) +shell.setCompletionFunction( "rom/programs/label.lua", completion.build( + { completion.choice, { "get", "get ", "set ", "clear", "clear " } }, + completion.peripheral +) ) +shell.setCompletionFunction( "rom/programs/list.lua", completion.build(completion.dir) ) +shell.setCompletionFunction( "rom/programs/mkdir.lua", completion.build({ completion.dir, many = true }) ) +shell.setCompletionFunction( "rom/programs/monitor.lua", completion.build( + { completion.peripheral, true }, + completion.program +) ) +shell.setCompletionFunction( "rom/programs/move.lua", completion.build( + { completion.dirOrFile, true }, + completion.dirOrFile +) ) +shell.setCompletionFunction( "rom/programs/redstone.lua", completion.build( + { completion.choice, { "probe", "set ", "pulse " } }, + completion.side +) ) +shell.setCompletionFunction( "rom/programs/rename.lua", completion.build( + { completion.dirOrFile, true }, + completion.dirOrFile +) ) +shell.setCompletionFunction( "rom/programs/shell.lua", completion.build(completion.program) ) +shell.setCompletionFunction( "rom/programs/type.lua", completion.build(completion.dirOrFile) ) +shell.setCompletionFunction( "rom/programs/set.lua", completion.build({ completion.setting, true }) ) +shell.setCompletionFunction( "rom/programs/advanced/bg.lua", completion.build(completion.program) ) +shell.setCompletionFunction( "rom/programs/advanced/fg.lua", completion.build(completion.program) ) +shell.setCompletionFunction( "rom/programs/fun/dj.lua", completion.build( + { completion.choice, { "play", "play ", "stop " } }, + completion.peripheral +) ) +shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completion.build(completion.file) ) +shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completion.build( + { completion.choice, { "put ", "get ", "run " } }, + completePastebinPut +) ) +shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completion.build({ completion.choice, { "host ", "join " } }) ) +shell.setCompletionFunction( "rom/programs/command/exec.lua", completion.build(completion.command) ) +shell.setCompletionFunction( "rom/programs/http/wget.lua", completion.build({ completion.choice, { "run " } }) ) if turtle then - local tGoOptions = { "left", "right", "forward", "back", "down", "up" } - local function completeGo( shell, nIndex, sText ) - return completeMultipleChoice( sText, tGoOptions, true) - end - local tTurnOptions = { "left", "right" } - local function completeTurn( shell, nIndex, sText ) - return completeMultipleChoice( sText, tTurnOptions, true ) - end - local tEquipOptions = { "left", "right" } - local function completeEquip( shell, nIndex, sText ) - if nIndex == 2 then - return completeMultipleChoice( sText, tEquipOptions ) - end - end - local function completeUnequip( shell, nIndex, sText ) - if nIndex == 1 then - return completeMultipleChoice( sText, tEquipOptions ) - end - end - shell.setCompletionFunction( "rom/programs/turtle/go.lua", completeGo ) - shell.setCompletionFunction( "rom/programs/turtle/turn.lua", completeTurn ) - shell.setCompletionFunction( "rom/programs/turtle/equip.lua", completeEquip ) - shell.setCompletionFunction( "rom/programs/turtle/unequip.lua", completeUnequip ) + shell.setCompletionFunction( "rom/programs/turtle/go.lua", completion.build( + { completion.choice, { "left", "right", "forward", "back", "down", "up" }, true, many = true } + ) ) + shell.setCompletionFunction( "rom/programs/turtle/turn.lua", completion.build( + { completion.choice, { "left", "right" }, true, many = true } + )) + shell.setCompletionFunction( "rom/programs/turtle/equip.lua", completion.build( + nil, + { completion.choice, { "left", "right" } } + ) ) + shell.setCompletionFunction( "rom/programs/turtle/unequip.lua", completion.build( + { completion.choice, { "left", "right" } } + ) ) end - -- Run autorun files if fs.exists( "/rom/autorun" ) and fs.isDir( "/rom/autorun" ) then local tFiles = fs.list( "/rom/autorun" ) - table.sort( tFiles ) - for n, sFile in ipairs( tFiles ) do + for _, sFile in ipairs( tFiles ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = "/rom/autorun/"..sFile if not fs.isDir( sPath ) then diff --git a/src/test/resources/test-rom/spec/modules/cc/completion_spec.lua b/src/test/resources/test-rom/spec/modules/cc/completion_spec.lua new file mode 100644 index 000000000..41e7ae5bc --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/completion_spec.lua @@ -0,0 +1,57 @@ +describe("cc.completion", function() + local c = require("cc.completion") + + describe("choice", function() + it("provides all choices", function() + expect(c.choice("", { "some text", "some other", "other" })) + :same { "some text", "some other", "other" } + end) + + it("provides a filtered list of choices", function() + expect(c.choice("som", { "some text", "some other", "other" })) + :same { "e text", "e other" } + + expect(c.choice("none", { "some text", "some other", "other" })) + :same { } + end) + + it("adds text if needed", function() + expect(c.choice("som", { "some text", "some other", "other" }, true)) + :same { "e text ", "e other " } + end) + end) + + describe("peripheral", function() + it("provides a choice of peripherals", function() + stub(peripheral, "getNames", function() return { "drive_0", "left" } end) + + expect(c.peripheral("dri")):same { "ve_0" } + expect(c.peripheral("dri", true)):same { "ve_0 " } + end) + end) + + describe("side", function() + it("provides a choice of sides", function() + expect(c.side("le")):same { "ft" } + expect(c.side("le", true)):same { "ft " } + end) + end) + + describe("setting", function() + it("provides a choice of setting names", function() + stub(settings, "getNames", function() return { "shell.allow_startup", "list.show_hidden" } end) + + expect(c.setting("li")):same { "st.show_hidden" } + expect(c.setting("li", true)):same { "st.show_hidden " } + end) + end) + + describe("command", function() + it("provides a choice of command names", function() + stub(_G, "commands", { list = function() return { "list", "say" } end }) + + expect(c.command("li")):same { "st" } + expect(c.command("li", true)):same { "st " } + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua new file mode 100644 index 000000000..7f7fd0a40 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua @@ -0,0 +1,41 @@ +describe("cc.shell.completion", function() + local c = require "cc.shell.completion" + + describe("dirOrFile", function() + it("completes both", function() + expect(c.dirOrFile(shell, "rom/")):same { + "apis/", "apis", "autorun/", "autorun", "help/", "help", + "modules/", "modules", "motd.txt", "programs/", "programs", "startup.lua" + } + end) + + it("adds a space", function() + expect(c.dirOrFile(shell, "rom/", nil, true)):same { + "apis/", "apis ", "autorun/", "autorun ", "help/", "help ", + "modules/", "modules ", "motd.txt ", "programs/", "programs ", "startup.lua ", + } + end) + end) + + describe("build", function() + it("completes multiple arguments", function() + local spec = c.build( + function() return { "a", "b", "c" } end, + nil, + { c.choice, { "d", "e", "f"} } + ) + + expect(spec(shell, 1, "")):same { "a", "b", "c" } + expect(spec(shell, 2, "")):same(nil) + expect(spec(shell, 3, "")):same { "d", "e", "f" } + expect(spec(shell, 4, "")):same(nil) + end) + + it("supports variadic completions", function() + local spec = c.build({ function() return { "a", "b", "c" } end, many = true }) + + expect(spec(shell, 1, "")):same({ "a", "b", "c" }) + expect(spec(shell, 2, "")):same({ "a", "b", "c" }) + end) + end) +end) diff --git a/src/test/resources/test-rom/spec/programs/mkdir_spec.lua b/src/test/resources/test-rom/spec/programs/mkdir_spec.lua index 91dcaf437..fb7327519 100644 --- a/src/test/resources/test-rom/spec/programs/mkdir_spec.lua +++ b/src/test/resources/test-rom/spec/programs/mkdir_spec.lua @@ -23,7 +23,7 @@ describe("The mkdir program", function() io.open("/test-files.a.txt", "w"):close() local complete = shell.getCompletionInfo()["rom/programs/mkdir.lua"].fnComplete - expect(complete(shell, 1, "/test-files/", {})):same { "a/", "b/" } - expect(complete(shell, 2, "/test-files/", { "/" })):same { "a/", "b/" } + expect(complete(shell, 1, "/test-files/", {})):same { "a/", "a", "b/", "b" } + expect(complete(shell, 2, "/test-files/", { "/" })):same { "a/", "a", "b/", "b" } end) end) From 79cd8b4da532c094098525481a675f967e9e11cb Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 15 Sep 2019 18:37:00 +0100 Subject: [PATCH 077/711] Also return the number of affected entities Closes #293. Doesn't really solve anything there aside from exposing the number, but sadly there's not really anything obvious I can do on my end - the command API just doesn't expose anything else. --- .../dan200/computercraft/shared/computer/apis/CommandAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 08e4c4afa..a3365d225 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -83,7 +83,7 @@ public class CommandAPI implements ILuaAPI { sender.clearOutput(); int result = commandManager.executeCommand( sender, command ); - return new Object[] { result > 0, sender.copyOutput() }; + return new Object[] { result > 0, sender.copyOutput(), result }; } catch( Throwable t ) { From 3023f235a4e775d38020dc5b411e1ae311b78963 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 27 Sep 2019 08:56:53 +0100 Subject: [PATCH 078/711] Goodbye Travis, I'm with GH Actions now --- .github/workflows/main-ci.yml | 2 +- .travis.yml | 14 -------------- README.md | 2 +- 3 files changed, 2 insertions(+), 16 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 864c86aba..54afe58e3 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -1,4 +1,4 @@ -name: Java CI +name: Build on: [push] diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0e4be822e..000000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: java - -script: ./gradlew build --no-daemon - -before_cache: - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/s - -jdk: - - openjdk8 diff --git a/README.md b/README.md index d7996659e..692e7bb48 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # ![CC: Tweaked](logo.png) -[![Current build status](https://travis-ci.org/SquidDev-CC/CC-Tweaked.svg?branch=master)](https://travis-ci.org/SquidDev-CC/CC-Tweaked "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") +[![Current build status](https://github.com/SquidDev-CC/CC-Tweaked/workflows/Build/badge.svg)](https://github.com/SquidDev-CC/CC-Tweaked/actions "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers, turtles and more to Minecraft. From db31a53bba4b1da9aee203a3346f731d054f8cfc Mon Sep 17 00:00:00 2001 From: Wendelstein7 <23213464+Wendelstein7@users.noreply.github.com> Date: Mon, 30 Sep 2019 15:15:22 +0200 Subject: [PATCH 079/711] Fixed turtle property category Likely was a leftover from copy pasting and a tired programmer. --- src/main/java/dan200/computercraft/shared/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 76bbe6f43..ffb176c72 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -277,7 +277,7 @@ public final class Config renameProperty( CATEGORY_GENERAL, "turtlesCanPush", CATEGORY_TURTLE, "can_push" ); renameProperty( CATEGORY_GENERAL, "turtle_disabled_actions", CATEGORY_TURTLE, "disabled_actions" ); - config.getCategory( CATEGORY_HTTP ) + config.getCategory( CATEGORY_TURTLE ) .setComment( "Various options relating to turtles." ); turtlesNeedFuel = config.get( CATEGORY_TURTLE, "need_fuel", ComputerCraft.turtlesNeedFuel ); From 7250f22ff64e4667746c8a4cc38879cd29816418 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 30 Sep 2019 15:37:52 +0100 Subject: [PATCH 080/711] Update CI to also run on PRs --- .github/workflows/main-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 54afe58e3..16f34b3e2 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -1,10 +1,9 @@ name: Build -on: [push] +on: [push, pull_request] jobs: build: - runs-on: ubuntu-latest steps: From 4243f30308949ff85bb86f8858d38226de019d9a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 1 Oct 2019 18:53:38 +0100 Subject: [PATCH 081/711] Bump Forge version --- build.gradle | 2 +- gradle.properties | 2 +- .../shared/turtle/FurnaceRefuelHandler.java | 11 ++--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 61e98e720..6272797a9 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.142' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.147' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } diff --git a/gradle.properties b/gradle.properties index b46b21df2..fb120bd3a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.84.1 # Minecraft properties mc_version=1.14.4 -forge_version=28.1.1 +forge_version=28.1.26 mappings_version=20190912-1.14.3 diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index 9c407c9b5..a62482988 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -12,8 +12,7 @@ import dan200.computercraft.api.turtle.event.TurtleRefuelEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.FurnaceTileEntity; -import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -52,15 +51,9 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler return fuelToGive; } - private static int getFuelPerItem( @Nonnull ItemStack stack ) { - int basicBurnTime = stack.getBurnTime(); - int burnTime = ForgeEventFactory.getItemBurnTime( - stack, - basicBurnTime == -1 ? FurnaceTileEntity.getBurnTimes().getOrDefault( stack.getItem(), 0 ) : basicBurnTime - ); - return (burnTime * 5) / 100; + return (ForgeHooks.getBurnTime( stack ) * 5) / 100; } @SubscribeEvent From ff5ba5c131617efc5376d3690ebf3ef51b916ad6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 1 Oct 2019 18:53:46 +0100 Subject: [PATCH 082/711] Update GUI code to be compatible with 1.14.4 Not quite sure when this changed, but I'm fairly sure isMouseOver wasn't a thing when I wrote this. Or I'm a plonker. Both are possible. Also fixes mouse dragging not being handled in turtles. Fixes #299 --- .../computercraft/client/gui/GuiComputer.java | 7 ------- .../computercraft/client/gui/GuiTurtle.java | 7 +++++++ .../client/gui/widgets/WidgetTerminal.java | 17 ++++++++++++----- .../client/gui/widgets/WidgetWrapper.java | 7 +++++++ 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 13a01b0ce..c3fc17153 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -176,11 +176,4 @@ public final class GuiComputer extends Containe return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); } - - @Override - public boolean mouseReleased( double x, double y, int button ) - { - return (getFocused() != null && getFocused().mouseReleased( x, y, button )) - || super.mouseReleased( x, y, button ); - } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 7e80b05aa..34622fa48 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -129,4 +129,11 @@ public class GuiTurtle extends ContainerScreen super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); } + + @Override + public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY ) + { + return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) + || super.mouseDragged( x, y, button, deltaX, deltaY ); + } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 72640661e..903b25e01 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -241,11 +241,12 @@ public class WidgetTerminal implements IGuiEventListener charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); - computer.mouseDrag( button + 1, charX + 1, charY + 1 ); - - lastMouseX = charX; - lastMouseY = charY; - lastMouseButton = button; + if( button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY) ) + { + computer.mouseDrag( button + 1, charX + 1, charY + 1 ); + lastMouseX = charX; + lastMouseY = charY; + } } return false; @@ -427,4 +428,10 @@ public class WidgetTerminal implements IGuiEventListener ClientComputer computer = this.computer.get(); if( computer != null ) computer.queueEvent( event, args ); } + + @Override + public boolean isMouseOver( double x, double y ) + { + return true; + } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java index fed1e086b..df5c46f6b 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java @@ -95,4 +95,11 @@ public class WidgetWrapper implements IGuiEventListener { return height; } + + @Override + public boolean isMouseOver( double x, double y ) + { + double dx = x - this.x, dy = y - this.y; + return dx >= 0 && dx < width && dy >= 0 && dy < height; + } } From f1621b30ec17bdfe6c49dfd3f377ba94c9ddaf92 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 1 Oct 2019 19:15:13 +0100 Subject: [PATCH 083/711] Remove redundant imports --- .../java/dan200/computercraft/shared/util/DropConsumer.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 411b58c59..589e41034 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -14,8 +14,6 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.entity.EntityJoinWorldEvent; -import net.minecraftforge.event.entity.living.LivingDropsEvent; -import net.minecraftforge.event.world.BlockEvent; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; From 81f85361d5953f1f9059fe3e6268090900245bc3 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 1 Oct 2019 19:43:03 +0100 Subject: [PATCH 084/711] Move Lua files to the correct location I really need to fix this. --- .../computercraft/lua/rom/modules/main/cc/completion.lua | 0 .../computercraft/lua/rom/modules/main/cc/shell/completion.lua | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{assets => data}/computercraft/lua/rom/modules/main/cc/completion.lua (100%) rename src/main/resources/{assets => data}/computercraft/lua/rom/modules/main/cc/shell/completion.lua (100%) diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua similarity index 100% rename from src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua rename to src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua similarity index 100% rename from src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua rename to src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua From d342a1f368d3c55c5e606a0e1d6abaf3c535b6be Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 1 Oct 2019 20:06:38 +0100 Subject: [PATCH 085/711] Prevent wired modems dropping on block change Fixes #303 --- .../shared/peripheral/modem/wired/BlockCable.java | 2 +- .../computercraft/shared/peripheral/modem/wired/TileCable.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 7b3d2b7cc..bf4deb175 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -210,7 +210,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable BlockPos offsetPos = pos.offset( facing ); BlockState offsetState = world.getBlockState( offsetPos ); - return Block.hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() ); + return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 9d69e2c72..d635bda98 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -201,8 +201,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile public void onNeighbourChange( @Nonnull BlockPos neighbour ) { Direction dir = getDirection(); - if( neighbour.equals( getPos().offset( dir ) ) && hasModem() - && getBlockState().isValidPosition( world, pos ) ) + if( neighbour.equals( getPos().offset( dir ) ) && hasModem() && !getBlockState().isValidPosition( getWorld(), getPos() ) ) { if( hasCable() ) { From 418420523ac0474a811a6a6fba0c4bfacbefd65b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 4 Oct 2019 16:53:48 +0100 Subject: [PATCH 086/711] Proxy the current turtle's inventory Previously we were just returning the current tile. However, if someone was holding a reference to this inventory (such as a GUI), then it'd be outdated and invalid once the turtle had moved. This caused a couple of issues: - turtle_inventory events would not be fired when moving items in the turtle GUI. - As of 75e2845c01532987026ed028e97bab74e274a9dd, turtles would no longer share their inventory state after moving. Thus, removing items from a GUI using an invalid inventory would move them from an old tile, duplicating the items. Fixes #298, fixes #300 --- .../media/inventory/ContainerHeldItem.java | 3 +- .../shared/turtle/blocks/TileTurtle.java | 4 +- .../shared/turtle/core/TurtleBrain.java | 13 +- .../shared/util/InventoryDelegate.java | 146 ++++++++++++++++++ .../shared/util/InventoryUtil.java | 6 - 5 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java diff --git a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java index 4daa4fe34..cc059646b 100644 --- a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.media.inventory; -import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.item.ItemStack; @@ -22,7 +21,7 @@ public class ContainerHeldItem extends Container public ContainerHeldItem( EntityPlayer player, EnumHand hand ) { m_hand = hand; - m_stack = InventoryUtil.copyItem( player.getHeldItem( hand ) ); + m_stack = player.getHeldItem( hand ).copy(); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index e70c7d333..e4b23311c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -224,7 +224,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default m_inventoryChanged = false; for( int n = 0; n < getSizeInventory(); n++ ) { - m_previousInventory.set( n, InventoryUtil.copyItem( getStackInSlot( n ) ) ); + m_previousInventory.set( n, getStackInSlot( n ).copy() ); } } } @@ -268,7 +268,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default if( slot < getSizeInventory() ) { m_inventory.set( slot, new ItemStack( tag ) ); - m_previousInventory.set( slot, InventoryUtil.copyItem( m_inventory.get( slot ) ) ); + m_previousInventory.set( slot, m_inventory.get( slot ).copy() ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 494b8750d..bf68e2b3f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -20,10 +20,7 @@ import dan200.computercraft.shared.computer.blocks.TileComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.ColourUtils; -import dan200.computercraft.shared.util.Holiday; -import dan200.computercraft.shared.util.HolidayUtil; +import dan200.computercraft.shared.util.*; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; @@ -40,6 +37,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.wrapper.InvWrapper; import javax.annotation.Nonnull; import java.util.*; @@ -53,6 +51,9 @@ public class TurtleBrain implements ITurtleAccess private ComputerProxy m_proxy; private GameProfile m_owningPlayer; + private final IInventory m_inventory = (InventoryDelegate) () -> m_owner; + private final IItemHandlerModifiable m_inventoryWrapper = new InvWrapper( m_inventory ); + private Queue m_commandQueue = new ArrayDeque<>(); private int m_commandsIssued = 0; @@ -531,14 +532,14 @@ public class TurtleBrain implements ITurtleAccess @Override public IInventory getInventory() { - return m_owner; + return m_inventory; } @Nonnull @Override public IItemHandlerModifiable getItemHandler() { - return m_owner.getItemHandler(); + return m_inventoryWrapper; } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java new file mode 100644 index 000000000..7f94d0460 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -0,0 +1,146 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; + +import javax.annotation.Nonnull; + +/** + * Provides a delegate over inventories. + * + * This may be used both on {@link net.minecraft.tileentity.TileEntity}s to redirect the inventory to another tile, + * and by other interfaces to have inventories which change their backing store. + */ +@FunctionalInterface +public interface InventoryDelegate extends IInventory +{ + IInventory getInventory(); + + @Override + default int getSizeInventory() + { + return getInventory().getSizeInventory(); + } + + @Override + default boolean isEmpty() + { + return getInventory().isEmpty(); + } + + @Nonnull + @Override + default ItemStack getStackInSlot( int slot ) + { + return getInventory().getStackInSlot( slot ); + } + + @Nonnull + @Override + default ItemStack decrStackSize( int slot, int count ) + { + return getInventory().decrStackSize( slot, count ); + } + + @Nonnull + @Override + default ItemStack removeStackFromSlot( int slot ) + { + return getInventory().removeStackFromSlot( slot ); + } + + @Override + default void setInventorySlotContents( int slot, ItemStack stack ) + { + getInventory().setInventorySlotContents( slot, stack ); + } + + @Override + default int getInventoryStackLimit() + { + return getInventory().getInventoryStackLimit(); + } + + @Override + default void markDirty() + { + getInventory().markDirty(); + } + + @Override + default boolean isUsableByPlayer( @Nonnull EntityPlayer player ) + { + return getInventory().isUsableByPlayer( player ); + } + + @Override + default void openInventory( @Nonnull EntityPlayer player ) + { + getInventory().openInventory( player ); + } + + @Override + default void closeInventory( @Nonnull EntityPlayer player ) + { + getInventory().closeInventory( player ); + } + + @Override + default boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack ) + { + return getInventory().isItemValidForSlot( slot, stack ); + } + + @Override + default int getField( int id ) + { + return getInventory().getField( id ); + } + + @Override + default void setField( int id, int val ) + { + getInventory().setField( id, val ); + + } + + @Override + default int getFieldCount() + { + return getInventory().getFieldCount(); + } + + @Override + default void clear() + { + getInventory().clear(); + } + + @Nonnull + @Override + default String getName() + { + return getInventory().getName(); + } + + @Override + default boolean hasCustomName() + { + return getInventory().hasCustomName(); + } + + @Nonnull + @Override + default ITextComponent getDisplayName() + { + return getInventory().getDisplayName(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 46a878f49..ae0434c9f 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -69,12 +69,6 @@ public final class InventoryUtil return shareTagA.equals( shareTagB ); } - @Nonnull - public static ItemStack copyItem( @Nonnull ItemStack a ) - { - return a.copy(); - } - // Methods for finding inventories: public static IItemHandler getInventory( World world, BlockPos pos, EnumFacing side ) From c802290437be9f1fc4abc47b691eb2c86f406c0f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 4 Oct 2019 19:52:02 +0100 Subject: [PATCH 087/711] Bump version --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 10 ++++++++++ .../computercraft/lua/rom/help/whatsnew.txt | 19 ++++++------------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/gradle.properties b/gradle.properties index 8b34c6687..30e15fd82 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.84.0 +mod_version=1.85.0 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 90cd8c0a9..aa8214920 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,13 @@ +# New features in CC: Tweaked 1.85.0 + +* Window.reposition now allows changing the redirect buffer +* Add cc.completion and cc.shell.completion modules +* command.exec also returns the number of affected objects, when exposed by the game. + +And several bug fixes: +* Change how turtle mining drops are handled, improving compatibility with some mods. +* Fix several GUI desyncs after a turtle moves. + # New features in CC: Tweaked 1.84.0 * Improve validation in rename, copy and delete programs diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 20957867e..53875ec6a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,18 +1,11 @@ -New features in CC: Tweaked 1.84.0 +New features in CC: Tweaked 1.85.0 -* Improve validation in rename, copy and delete programs -* Add window.getLine - the inverse of blit -* turtle.refuel no longer consumes more fuel than needed -* Add "cc.expect" module, for improved argument type checks -* Mount the ROM from all mod jars, not just CC's +* Window.reposition now allows changing the redirect buffer +* Add cc.completion and cc.shell.completion modules +* command.exec also returns the number of affected objects, when exposed by the game. And several bug fixes: -* Ensure file error messages use the absolute correct path -* Fix NPE when closing a file multiple times. -* Do not load chunks when calling writeDescription. -* Fix the signature of loadfile -* Fix turtles harvesting blocks multiple times -* Improve thread-safety of various peripherals -* Prevent printed pages having massive/malformed titles +* Change how turtle mining drops are handled, improving compatibility with some mods. +* Fix several GUI desyncs after a turtle moves. Type "help changelog" to see the full version history. From 14b3065ba489c85806df58425cc2969cc05b710e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 16 Oct 2019 09:22:38 +0100 Subject: [PATCH 088/711] Check for trailing whitespace I'd rather assumed one of the existing checkers did this already, but apparently not. --- config/checkstyle/checkstyle.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 3dcaa94a2..e18710be1 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -155,5 +155,8 @@ + + + + - From a93e0f3284ec041ee46d866b2e9ffca7b2dee11d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 27 Oct 2019 14:29:07 +0000 Subject: [PATCH 089/711] Expose ArgumentHelper in the public API This is sufficiently useful a class, that it's worthwhile exposing it. Hopefully we can slowly encourage other mods to migrate to it (well, at least in 1.14), and so make error messages more consistent. Also: - Add Javadoc for all public methods - Clarify the method names a little (getNumber -> getDouble, getReal -> getFiniteDouble). - Make the *Table methods return a Map instead of Map. --- .../computercraft/api/lua/ArgumentHelper.java | 335 ++++++++++++++++++ .../api/peripheral/IPeripheral.java | 8 +- .../core/apis/ArgumentHelper.java | 194 ++-------- .../dan200/computercraft/core/apis/FSAPI.java | 2 +- .../computercraft/core/apis/HTTPAPI.java | 6 +- .../dan200/computercraft/core/apis/OSAPI.java | 6 +- .../core/apis/PeripheralAPI.java | 2 +- .../computercraft/core/apis/RedstoneAPI.java | 2 +- .../computercraft/core/apis/TableHelper.java | 21 +- .../computercraft/core/apis/TermAPI.java | 8 +- .../apis/handles/BinaryReadableHandle.java | 4 +- .../apis/handles/BinaryWritableHandle.java | 4 +- .../apis/handles/EncodedReadableHandle.java | 4 +- .../core/apis/handles/HandleGeneric.java | 4 +- .../apis/http/websocket/WebsocketHandle.java | 2 +- .../shared/computer/apis/CommandAPI.java | 4 +- .../commandblock/CommandBlockPeripheral.java | 2 +- .../diskdrive/DiskDrivePeripheral.java | 2 +- .../peripheral/modem/ModemPeripheral.java | 2 +- .../modem/wired/WiredModemPeripheral.java | 2 +- .../peripheral/monitor/MonitorPeripheral.java | 10 +- .../peripheral/printer/PrinterPeripheral.java | 4 +- .../peripheral/speaker/SpeakerPeripheral.java | 12 +- .../shared/turtle/apis/TurtleAPI.java | 2 +- .../upgrades/CraftingTablePeripheral.java | 2 +- .../core/ComputerTestDelegate.java | 4 +- .../core/computer/ComputerBootstrap.java | 2 +- 27 files changed, 414 insertions(+), 236 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java diff --git a/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java b/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java new file mode 100644 index 000000000..7bc8c79e3 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java @@ -0,0 +1,335 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; + +/** + * Provides methods for extracting values and validating Lua arguments, such as those provided to + * {@link ILuaObject#callMethod(ILuaContext, int, Object[])} or + * {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}. + * + * This provides two sets of functions: the {@code get*} methods, which require an argument to be valid, and + * {@code opt*}, which accept a default value and return that if the argument was not present or was {@code null}. + * If the argument is of the wrong type, a suitable error message will be thrown, with a similar format to Lua's own + * error messages. + * + *

Example usage:

+ *
+ * {@code
+ * int slot = getInt( args, 0 );
+ * int amount = optInt( args, 1, 64 );
+ * }
+ * 
+ */ +public final class ArgumentHelper +{ + private ArgumentHelper() + { + } + + /** + * Get a string representation of the given value's type. + * + * @param value The value whose type we are trying to compute. + * @return A string representation of the given value's type, in a similar format to that provided by Lua's + * {@code type} function. + */ + @Nonnull + public static String getType( @Nullable Object value ) + { + if( value == null ) return "nil"; + if( value instanceof String ) return "string"; + if( value instanceof Boolean ) return "boolean"; + if( value instanceof Number ) return "number"; + if( value instanceof Map ) return "table"; + return "userdata"; + } + + /** + * Construct a "bad argument" exception, from an expected type and the actual value provided. + * + * @param index The argument number, starting from 0. + * @param expected The expected type for this argument. + * @param actual The actual value provided for this argument. + * @return The constructed exception, which should be thrown immediately. + */ + @Nonnull + public static LuaException badArgumentOf( int index, @Nonnull String expected, @Nullable Object actual ) + { + return badArgument( index, expected, getType( actual ) ); + } + + /** + * Construct a "bad argument" exception, from an expected and actual type. + * + * @param index The argument number, starting from 0. + * @param expected The expected type for this argument. + * @param actual The provided type for this argument. + * @return The constructed exception, which should be thrown immediately. + */ + @Nonnull + public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual ) + { + return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); + } + + /** + * Get an argument as a double. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not a number. + * @see #getFiniteDouble(Object[], int) if you require this to be finite (i.e. not infinite or NaN). + */ + public static double getDouble( @Nonnull Object[] args, int index ) throws LuaException + { + if( index >= args.length ) throw badArgument( index, "number", "nil" ); + Object value = args[index]; + if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); + return ((Number) value).doubleValue(); + } + + /** + * Get an argument as an integer. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not an integer. + */ + public static int getInt( @Nonnull Object[] args, int index ) throws LuaException + { + return (int) getLong( args, index ); + } + + /** + * Get an argument as a long. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not a long. + */ + public static long getLong( @Nonnull Object[] args, int index ) throws LuaException + { + if( index >= args.length ) throw badArgument( index, "number", "nil" ); + Object value = args[index]; + if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); + return checkFinite( index, (Number) value ).longValue(); + } + + /** + * Get an argument as a finite number (not infinite or NaN). + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not finite. + */ + public static double getFiniteDouble( @Nonnull Object[] args, int index ) throws LuaException + { + return checkFinite( index, getDouble( args, index ) ); + } + + /** + * Get an argument as a boolean. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not a boolean. + */ + public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException + { + if( index >= args.length ) throw badArgument( index, "boolean", "nil" ); + Object value = args[index]; + if( !(value instanceof Boolean) ) throw badArgumentOf( index, "boolean", value ); + return (Boolean) value; + } + + /** + * Get an argument as a string. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not a string. + */ + @Nonnull + public static String getString( @Nonnull Object[] args, int index ) throws LuaException + { + if( index >= args.length ) throw badArgument( index, "string", "nil" ); + Object value = args[index]; + if( !(value instanceof String) ) throw badArgumentOf( index, "string", value ); + return (String) value; + } + + /** + * Get an argument as a table. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @return The argument's value. + * @throws LuaException If the value is not a table. + */ + @Nonnull + public static Map getTable( @Nonnull Object[] args, int index ) throws LuaException + { + if( index >= args.length ) throw badArgument( index, "table", "nil" ); + Object value = args[index]; + if( !(value instanceof Map) ) throw badArgumentOf( index, "table", value ); + return (Map) value; + } + + /** + * Get an argument as a double. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + public static double optDouble( @Nonnull Object[] args, int index, double def ) throws LuaException + { + Object value = index < args.length ? args[index] : null; + if( value == null ) return def; + if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); + return ((Number) value).doubleValue(); + } + + /** + * Get an argument as an int. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException + { + return (int) optLong( args, index, def ); + } + + /** + * Get an argument as a long. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + public static long optLong( @Nonnull Object[] args, int index, long def ) throws LuaException + { + Object value = index < args.length ? args[index] : null; + if( value == null ) return def; + if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); + return checkFinite( index, (Number) value ).longValue(); + } + + /** + * Get an argument as a finite number (not infinite or NaN). + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not finite. + */ + public static double optFiniteDouble( @Nonnull Object[] args, int index, double def ) throws LuaException + { + return checkFinite( index, optDouble( args, index, def ) ); + } + + /** + * Get an argument as a boolean. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a boolean. + */ + public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException + { + Object value = index < args.length ? args[index] : null; + if( value == null ) return def; + if( !(value instanceof Boolean) ) throw badArgumentOf( index, "boolean", value ); + return (Boolean) value; + } + + /** + * Get an argument as a string. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a string. + */ + public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException + { + Object value = index < args.length ? args[index] : null; + if( value == null ) return def; + if( !(value instanceof String) ) throw badArgumentOf( index, "string", value ); + return (String) value; + } + + /** + * Get an argument as a table. + * + * @param args The arguments to extract from. + * @param index The index into the argument array to read from. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a table. + */ + public static Map optTable( @Nonnull Object[] args, int index, Map def ) throws LuaException + { + Object value = index < args.length ? args[index] : null; + if( value == null ) return def; + if( !(value instanceof Map) ) throw badArgumentOf( index, "table", value ); + return (Map) value; + } + + private static Number checkFinite( int index, Number value ) throws LuaException + { + checkFinite( index, value.doubleValue() ); + return value; + } + + private static double checkFinite( int index, double value ) throws LuaException + { + if( !Double.isFinite( value ) ) throw badArgument( index, "number", getNumericType( value ) ); + return value; + } + + /** + * Returns a more detailed representation of this number's type. If this is finite, it will just return "number", + * otherwise it returns whether it is infinite or NaN. + * + * @param value The value to extract the type for. + * @return This value's numeric type. + */ + @Nonnull + public static String getNumericType( double value ) + { + if( Double.isNaN( value ) ) return "nan"; + if( value == Double.POSITIVE_INFINITY ) return "inf"; + if( value == Double.NEGATIVE_INFINITY ) return "-inf"; + return "number"; + } +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 965d635c7..481499138 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -6,6 +6,7 @@ package dan200.computercraft.api.peripheral; +import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; @@ -58,9 +59,11 @@ public interface IPeripheral * Lua values of type "table" will be represented by Object type Map.
* Lua values of any other type will be represented by a null object.
* This array will be empty if no arguments are passed. + * + * It is recommended you use {@link ArgumentHelper} in order to validate and process arguments. * @return An array of objects, representing values you wish to return to the lua program. Integers, Doubles, Floats, - * Strings, Booleans, Maps and ILuaObject and null be converted to their corresponding lua type. All other types - * will be converted to nil. + * Strings, Booleans, Maps, ILuaObject and null be converted to their corresponding lua type. All other types will + * be converted to nil. * * You may return null to indicate no values should be returned. * @throws LuaException If you throw any exception from this function, a lua error will be raised with the @@ -70,6 +73,7 @@ public interface IPeripheral * InterruptedException will be thrown. This exception must not be caught or * intercepted, or the computer will leak memory and end up in a broken state. * @see #getMethodNames + * @see ArgumentHelper */ @Nullable Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException; diff --git a/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java b/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java index 1e04552ff..0123d9de4 100644 --- a/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java +++ b/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java @@ -13,256 +13,106 @@ import javax.annotation.Nullable; import java.util.Map; /** - * Various helpers for arguments + * A stub for any mods which depended on this version of the argument helper. + * + * @deprecated Use {@link dan200.computercraft.api.lua.ArgumentHelper}. */ +@Deprecated public final class ArgumentHelper { private ArgumentHelper() { - throw new IllegalStateException( "Cannot instantiate singleton " + getClass().getName() ); } @Nonnull public static String getType( @Nullable Object type ) { - if( type == null ) return "nil"; - if( type instanceof String ) return "string"; - if( type instanceof Boolean ) return "boolean"; - if( type instanceof Number ) return "number"; - if( type instanceof Map ) return "table"; - - Class klass = type.getClass(); - if( klass.isArray() ) - { - StringBuilder name = new StringBuilder(); - while( klass.isArray() ) - { - name.append( "[]" ); - klass = klass.getComponentType(); - } - name.insert( 0, klass.getName() ); - return name.toString(); - } - else - { - return klass.getName(); - } + return dan200.computercraft.api.lua.ArgumentHelper.getType( type ); } @Nonnull public static LuaException badArgument( int index, @Nonnull String expected, @Nullable Object actual ) { - return badArgument( index, expected, getType( actual ) ); + return dan200.computercraft.api.lua.ArgumentHelper.badArgumentOf( index, expected, actual ); } @Nonnull public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual ) { - return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); + return dan200.computercraft.api.lua.ArgumentHelper.badArgument( index, expected, actual ); } public static double getNumber( @Nonnull Object[] args, int index ) throws LuaException { - if( index >= args.length ) throw badArgument( index, "number", "nil" ); - Object value = args[index]; - if( value instanceof Number ) - { - return ((Number) value).doubleValue(); - } - else - { - throw badArgument( index, "number", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.getDouble( args, index ); } public static int getInt( @Nonnull Object[] args, int index ) throws LuaException { - return (int) getLong( args, index ); + return dan200.computercraft.api.lua.ArgumentHelper.getInt( args, index ); } public static long getLong( @Nonnull Object[] args, int index ) throws LuaException { - if( index >= args.length ) throw badArgument( index, "number", "nil" ); - Object value = args[index]; - if( value instanceof Number ) - { - return checkReal( index, (Number) value ).longValue(); - } - else - { - throw badArgument( index, "number", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.getLong( args, index ); } public static double getReal( @Nonnull Object[] args, int index ) throws LuaException { - return checkReal( index, getNumber( args, index ) ); + return dan200.computercraft.api.lua.ArgumentHelper.getFiniteDouble( args, index ); } public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException { - if( index >= args.length ) throw badArgument( index, "boolean", "nil" ); - Object value = args[index]; - if( value instanceof Boolean ) - { - return (Boolean) value; - } - else - { - throw badArgument( index, "boolean", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.getBoolean( args, index ); } @Nonnull public static String getString( @Nonnull Object[] args, int index ) throws LuaException { - if( index >= args.length ) throw badArgument( index, "string", "nil" ); - Object value = args[index]; - if( value instanceof String ) - { - return (String) value; - } - else - { - throw badArgument( index, "string", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.getString( args, index ); } - @SuppressWarnings( "unchecked" ) @Nonnull + @SuppressWarnings( "unchecked" ) public static Map getTable( @Nonnull Object[] args, int index ) throws LuaException { - if( index >= args.length ) throw badArgument( index, "table", "nil" ); - Object value = args[index]; - if( value instanceof Map ) - { - return (Map) value; - } - else - { - throw badArgument( index, "table", value ); - } + return (Map) dan200.computercraft.api.lua.ArgumentHelper.getTable( args, index ); } public static double optNumber( @Nonnull Object[] args, int index, double def ) throws LuaException { - Object value = index < args.length ? args[index] : null; - if( value == null ) - { - return def; - } - else if( value instanceof Number ) - { - return ((Number) value).doubleValue(); - } - else - { - throw badArgument( index, "number", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.optDouble( args, index, def ); } public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException { - return (int) optLong( args, index, def ); + return dan200.computercraft.api.lua.ArgumentHelper.optInt( args, index, def ); } public static long optLong( @Nonnull Object[] args, int index, long def ) throws LuaException { - Object value = index < args.length ? args[index] : null; - if( value == null ) - { - return def; - } - else if( value instanceof Number ) - { - return checkReal( index, (Number) value ).longValue(); - } - else - { - throw badArgument( index, "number", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.optLong( args, index, def ); } public static double optReal( @Nonnull Object[] args, int index, double def ) throws LuaException { - return checkReal( index, optNumber( args, index, def ) ); + return dan200.computercraft.api.lua.ArgumentHelper.optFiniteDouble( args, index, def ); } public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException { - Object value = index < args.length ? args[index] : null; - if( value == null ) - { - return def; - } - else if( value instanceof Boolean ) - { - return (Boolean) value; - } - else - { - throw badArgument( index, "boolean", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.optBoolean( args, index, def ); } public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException { - Object value = index < args.length ? args[index] : null; - if( value == null ) - { - return def; - } - else if( value instanceof String ) - { - return (String) value; - } - else - { - throw badArgument( index, "string", value ); - } + return dan200.computercraft.api.lua.ArgumentHelper.optString( args, index, def ); } @SuppressWarnings( "unchecked" ) public static Map optTable( @Nonnull Object[] args, int index, Map def ) throws LuaException { - Object value = index < args.length ? args[index] : null; - if( value == null ) - { - return def; - } - else if( value instanceof Map ) - { - return (Map) value; - } - else - { - throw badArgument( index, "table", value ); - } - } - - private static Number checkReal( int index, Number value ) throws LuaException - { - checkReal( index, value.doubleValue() ); - return value; - } - - private static double checkReal( int index, double value ) throws LuaException - { - if( Double.isNaN( value ) ) - { - throw badArgument( index, "number", "nan" ); - } - else if( value == Double.POSITIVE_INFINITY ) - { - throw badArgument( index, "number", "inf" ); - } - else if( value == Double.NEGATIVE_INFINITY ) - { - throw badArgument( index, "number", "-inf" ); - } - else - { - return value; - } + return (Map) dan200.computercraft.api.lua.ArgumentHelper.optTable( args, index, def ); } } diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 71178d1fe..5fece4a7c 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -27,7 +27,7 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Function; -import static dan200.computercraft.core.apis.ArgumentHelper.getString; +import static dan200.computercraft.api.lua.ArgumentHelper.getString; public class FSAPI implements ILuaAPI { diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index d7b36491c..f89853cc2 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.Locale; import java.util.Map; -import static dan200.computercraft.core.apis.ArgumentHelper.*; +import static dan200.computercraft.api.lua.ArgumentHelper.*; import static dan200.computercraft.core.apis.TableHelper.*; public class HTTPAPI implements ILuaAPI @@ -89,7 +89,7 @@ public class HTTPAPI implements ILuaAPI case 0: // request { String address, postString, requestMethod; - Map headerTable; + Map headerTable; boolean binary, redirect; if( args.length >= 1 && args[0] instanceof Map ) @@ -172,7 +172,7 @@ public class HTTPAPI implements ILuaAPI case 2: // websocket { String address = getString( args, 0 ); - Map headerTbl = optTable( args, 1, Collections.emptyMap() ); + Map headerTbl = optTable( args, 1, Collections.emptyMap() ); if( !ComputerCraft.http_websocket_enable ) { diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 40f22d176..3f6e36ee5 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -19,7 +19,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatterBuilder; import java.util.*; -import static dan200.computercraft.core.apis.ArgumentHelper.*; +import static dan200.computercraft.api.lua.ArgumentHelper.*; public class OSAPI implements ILuaAPI { @@ -229,7 +229,7 @@ public class OSAPI implements ILuaAPI case 1: { // startTimer - double timer = getReal( args, 0 ); + double timer = getFiniteDouble( args, 0 ); synchronized( m_timers ) { m_timers.put( m_nextTimerToken, new Timer( (int) Math.round( timer / 0.05 ) ) ); @@ -239,7 +239,7 @@ public class OSAPI implements ILuaAPI case 2: { // setAlarm - double time = getReal( args, 0 ); + double time = getFiniteDouble( args, 0 ); if( time < 0.0 || time >= 24.0 ) { throw new LuaException( "Number out of range" ); diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index cd27ca756..c5470a475 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -22,7 +22,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static dan200.computercraft.core.apis.ArgumentHelper.getString; +import static dan200.computercraft.api.lua.ArgumentHelper.getString; public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener { diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 1a0217c2f..2da52759c 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -15,7 +15,7 @@ import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; -import static dan200.computercraft.core.apis.ArgumentHelper.*; +import static dan200.computercraft.api.lua.ArgumentHelper.*; public class RedstoneAPI implements ILuaAPI { diff --git a/src/main/java/dan200/computercraft/core/apis/TableHelper.java b/src/main/java/dan200/computercraft/core/apis/TableHelper.java index 6a59d2f3c..8e7dbc27d 100644 --- a/src/main/java/dan200/computercraft/core/apis/TableHelper.java +++ b/src/main/java/dan200/computercraft/core/apis/TableHelper.java @@ -6,12 +6,15 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.api.lua.LuaException; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Map; +import static dan200.computercraft.api.lua.ArgumentHelper.getNumericType; + /** * Various helpers for tables */ @@ -200,21 +203,7 @@ public final class TableHelper private static double checkReal( @Nonnull String key, double value ) throws LuaException { - if( Double.isNaN( value ) ) - { - throw badKey( key, "number", "nan" ); - } - else if( value == Double.POSITIVE_INFINITY ) - { - throw badKey( key, "number", "inf" ); - } - else if( value == Double.NEGATIVE_INFINITY ) - { - throw badKey( key, "number", "-inf" ); - } - else - { - return value; - } + if( !Double.isFinite( value ) ) throw badKey( key, "number", getNumericType( value ) ); + return value; } } diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 382ae4069..ce57adc49 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -17,7 +17,7 @@ import org.apache.commons.lang3.ArrayUtils; import javax.annotation.Nonnull; -import static dan200.computercraft.core.apis.ArgumentHelper.*; +import static dan200.computercraft.api.lua.ArgumentHelper.*; public class TermAPI implements ILuaAPI { @@ -242,9 +242,9 @@ public class TermAPI implements ILuaAPI } else { - double r = getReal( args, 1 ); - double g = getReal( args, 2 ); - double b = getReal( args, 3 ); + double r = getFiniteDouble( args, 1 ); + double g = getFiniteDouble( args, 2 ); + double b = getFiniteDouble( args, 3 ); setColour( m_terminal, colour, r, g, b ); } return null; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index 77a3b032b..2ad90ddb1 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -21,8 +21,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static dan200.computercraft.core.apis.ArgumentHelper.getInt; -import static dan200.computercraft.core.apis.ArgumentHelper.optBoolean; +import static dan200.computercraft.api.lua.ArgumentHelper.getInt; +import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; public class BinaryReadableHandle extends HandleGeneric { diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index b280ebdcc..558fbfe2e 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -7,9 +7,9 @@ package dan200.computercraft.core.apis.handles; import com.google.common.collect.ObjectArrays; +import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.core.apis.ArgumentHelper; import dan200.computercraft.shared.util.StringUtil; import javax.annotation.Nonnull; @@ -73,7 +73,7 @@ public class BinaryWritableHandle extends HandleGeneric } else { - throw ArgumentHelper.badArgument( 0, "string or number", args.length > 0 ? args[0] : null ); + throw ArgumentHelper.badArgumentOf( 0, "string or number", args.length > 0 ? args[0] : null ); } return null; } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index 68cdced49..7244c914b 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -20,8 +20,8 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; -import static dan200.computercraft.core.apis.ArgumentHelper.optBoolean; -import static dan200.computercraft.core.apis.ArgumentHelper.optInt; +import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; +import static dan200.computercraft.api.lua.ArgumentHelper.optInt; public class EncodedReadableHandle extends HandleGeneric { diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index 87b40ee2a..6d3011078 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -16,8 +16,8 @@ import java.io.IOException; import java.nio.channels.Channel; import java.nio.channels.SeekableByteChannel; -import static dan200.computercraft.core.apis.ArgumentHelper.optLong; -import static dan200.computercraft.core.apis.ArgumentHelper.optString; +import static dan200.computercraft.api.lua.ArgumentHelper.optLong; +import static dan200.computercraft.api.lua.ArgumentHelper.optString; public abstract class HandleGeneric implements ILuaObject { diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index f53a2bff1..fd2d79527 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -23,7 +23,7 @@ import javax.annotation.Nullable; import java.io.Closeable; import java.util.Arrays; -import static dan200.computercraft.core.apis.ArgumentHelper.optBoolean; +import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT; diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index a3365d225..2dd6f0aa4 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -30,8 +30,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static dan200.computercraft.core.apis.ArgumentHelper.getInt; -import static dan200.computercraft.core.apis.ArgumentHelper.getString; +import static dan200.computercraft.api.lua.ArgumentHelper.getInt; +import static dan200.computercraft.api.lua.ArgumentHelper.getString; public class CommandAPI implements ILuaAPI { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index f81a862b8..b4638041c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -14,7 +14,7 @@ import net.minecraft.tileentity.TileEntityCommandBlock; import javax.annotation.Nonnull; -import static dan200.computercraft.core.apis.ArgumentHelper.getString; +import static dan200.computercraft.api.lua.ArgumentHelper.getString; public class CommandBlockPeripheral implements IPeripheral { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 1977e4796..8dc7b9008 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -19,7 +19,7 @@ import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; -import static dan200.computercraft.core.apis.ArgumentHelper.optString; +import static dan200.computercraft.api.lua.ArgumentHelper.optString; class DiskDrivePeripheral implements IPeripheral { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 9009b4ec7..3222367d6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -21,7 +21,7 @@ import javax.annotation.Nonnull; import java.util.HashSet; import java.util.Set; -import static dan200.computercraft.core.apis.ArgumentHelper.getInt; +import static dan200.computercraft.api.lua.ArgumentHelper.getInt; public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 2cb992793..daf3820df 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -28,7 +28,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static dan200.computercraft.core.apis.ArgumentHelper.getString; +import static dan200.computercraft.api.lua.ArgumentHelper.getString; public abstract class WiredModemPeripheral extends ModemPeripheral implements IWiredSender { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java index 5dac79574..13bce9955 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java @@ -17,7 +17,7 @@ import org.apache.commons.lang3.ArrayUtils; import javax.annotation.Nonnull; -import static dan200.computercraft.core.apis.ArgumentHelper.*; +import static dan200.computercraft.api.lua.ArgumentHelper.*; public class MonitorPeripheral implements IPeripheral { @@ -123,7 +123,7 @@ public class MonitorPeripheral implements IPeripheral case 8: { // setTextScale - int scale = (int) (getReal( args, 0 ) * 2.0); + int scale = (int) (getFiniteDouble( args, 0 ) * 2.0); if( scale < 1 || scale > 10 ) { throw new LuaException( "Expected number in range 0.5-5" ); @@ -184,9 +184,9 @@ public class MonitorPeripheral implements IPeripheral } else { - double r = getReal( args, 1 ); - double g = getReal( args, 2 ); - double b = getReal( args, 3 ); + double r = getFiniteDouble( args, 1 ); + double g = getFiniteDouble( args, 2 ); + double b = getFiniteDouble( args, 3 ); TermAPI.setColour( terminal, colour, r, g, b ); } return null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index 91ea62895..7dfeeb96d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -15,8 +15,8 @@ import dan200.computercraft.shared.util.StringUtil; import javax.annotation.Nonnull; -import static dan200.computercraft.core.apis.ArgumentHelper.getInt; -import static dan200.computercraft.core.apis.ArgumentHelper.optString; +import static dan200.computercraft.api.lua.ArgumentHelper.getInt; +import static dan200.computercraft.api.lua.ArgumentHelper.optString; public class PrinterPeripheral implements IPeripheral { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index f92074f7e..6ecee51d2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -23,8 +23,8 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import java.util.concurrent.atomic.AtomicInteger; -import static dan200.computercraft.core.apis.ArgumentHelper.getString; -import static dan200.computercraft.core.apis.ArgumentHelper.optReal; +import static dan200.computercraft.api.lua.ArgumentHelper.getString; +import static dan200.computercraft.api.lua.ArgumentHelper.optFiniteDouble; public abstract class SpeakerPeripheral implements IPeripheral { @@ -84,8 +84,8 @@ public abstract class SpeakerPeripheral implements IPeripheral case 0: // playSound { String name = getString( args, 0 ); - float volume = (float) optReal( args, 1, 1.0 ); - float pitch = (float) optReal( args, 2, 1.0 ); + float volume = (float) optFiniteDouble( args, 1, 1.0 ); + float pitch = (float) optFiniteDouble( args, 2, 1.0 ); return new Object[] { playSound( context, name, volume, pitch, false ) }; } @@ -102,8 +102,8 @@ public abstract class SpeakerPeripheral implements IPeripheral private synchronized Object[] playNote( Object[] arguments, ILuaContext context ) throws LuaException { String name = getString( arguments, 0 ); - float volume = (float) optReal( arguments, 1, 1.0 ); - float pitch = (float) optReal( arguments, 2, 1.0 ); + float volume = (float) optFiniteDouble( arguments, 1, 1.0 ); + float pitch = (float) optFiniteDouble( arguments, 2, 1.0 ); String noteName = "block.note." + name; diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 573400499..7dc83ce55 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -27,7 +27,7 @@ import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; -import static dan200.computercraft.core.apis.ArgumentHelper.*; +import static dan200.computercraft.api.lua.ArgumentHelper.*; public class TurtleAPI implements ILuaAPI { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index 13e12ba36..bb3049588 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -15,7 +15,7 @@ import dan200.computercraft.shared.turtle.core.TurtleCraftCommand; import javax.annotation.Nonnull; -import static dan200.computercraft.core.apis.ArgumentHelper.optInt; +import static dan200.computercraft.api.lua.ArgumentHelper.optInt; public class CraftingTablePeripheral implements IPeripheral { diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 5d84bc9fe..db75d0472 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -37,8 +37,8 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Stream; -import static dan200.computercraft.core.apis.ArgumentHelper.getTable; -import static dan200.computercraft.core.apis.ArgumentHelper.getType; +import static dan200.computercraft.api.lua.ArgumentHelper.getTable; +import static dan200.computercraft.api.lua.ArgumentHelper.getType; /** * Loads tests from {@code test-rom/spec} and executes them. diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 0545328ca..8425657bc 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -12,7 +12,7 @@ import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.core.apis.ArgumentHelper; +import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.core.filesystem.MemoryMount; import dan200.computercraft.core.terminal.Terminal; import org.apache.logging.log4j.LogManager; From c311cdc6f5fa85d77dfb80c49cb56f95ca357de6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 27 Oct 2019 15:16:47 +0000 Subject: [PATCH 090/711] Make our Javadoc validation a little stricter I'm not sure there's much utility in this, but still feels worth doing. --- build.gradle | 2 +- config/checkstyle/checkstyle.xml | 15 +++++++++---- config/checkstyle/suppressions.xml | 3 +++ .../computercraft/api/ComputerCraftAPI.java | 11 +++++----- .../computercraft/api/filesystem/IMount.java | 4 ++-- .../api/lua/IComputerSystem.java | 2 +- .../api/pocket/IPocketAccess.java | 2 +- .../computercraft/api/turtle/TurtleSide.java | 4 ++-- .../computercraft/api/turtle/TurtleVerb.java | 4 ++-- .../api/turtle/event/TurtleAction.java | 2 +- .../api/turtle/event/TurtleBlockEvent.java | 2 +- .../turtle/event/TurtleInventoryEvent.java | 2 +- .../client/render/ItemMapLikeRenderer.java | 4 ++-- .../client/render/ItemPocketRenderer.java | 2 +- .../client/render/ItemPrintoutRenderer.java | 2 +- .../client/render/PrintoutRenderer.java | 12 +++++------ .../render/TileEntityCableRenderer.java | 4 ++++ .../core/apis/AddressPredicate.java | 2 +- .../computercraft/core/apis/TableHelper.java | 2 +- .../core/apis/handles/HandleGeneric.java | 2 +- .../core/apis/http/NetworkUtils.java | 2 +- .../core/apis/http/Resource.java | 8 +++++-- .../core/apis/http/ResourceGroup.java | 2 ++ .../core/apis/http/ResourceQueue.java | 2 ++ .../core/apis/http/request/HttpRequest.java | 2 +- .../apis/http/request/HttpRequestHandler.java | 6 +++++- .../core/computer/ComputerExecutor.java | 2 +- .../core/computer/ComputerThread.java | 16 +++++++------- .../core/computer/TimeoutState.java | 12 +++++++---- .../computercraft/core/lua/MachineResult.java | 2 +- .../computercraft/core/terminal/Terminal.java | 3 +++ .../shared/command/framework/CommandRoot.java | 2 +- .../shared/command/framework/ISubCommand.java | 11 +++++----- .../shared/command/text/ChatHelpers.java | 2 +- .../shared/command/text/TableBuilder.java | 2 +- .../shared/command/text/TableFormatter.java | 4 ++-- .../computer/blocks/TileComputerBase.java | 2 +- .../shared/computer/core/InputHandler.java | 2 +- .../integration/jei/JEIComputerCraft.java | 6 +++--- .../shared/media/items/RecordMedia.java | 2 +- .../shared/network/NetworkHandler.java | 1 + .../modem/WirelessModemPeripheral.java | 5 ++++- .../wired/WiredModemLocalPeripheral.java | 6 +++--- .../shared/turtle/core/TurtlePlayer.java | 2 +- .../computercraft/shared/util/StringUtil.java | 21 +++++++++++++++---- .../shared/util/ThreadUtils.java | 4 ++-- 46 files changed, 133 insertions(+), 79 deletions(-) diff --git a/build.gradle b/build.gradle index e627e1959..d071ab3a8 100644 --- a/build.gradle +++ b/build.gradle @@ -68,7 +68,7 @@ configurations { } dependencies { - checkstyle "com.puppycrawl.tools:checkstyle:8.21" + checkstyle "com.puppycrawl.tools:checkstyle:8.25" deobfProvided "mezz.jei:jei_1.12.2:4.15.0.269:api" deobfProvided "pl.asie:Charset-Lib:0.5.4.6" diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index e18710be1..a5465578e 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -14,9 +14,7 @@ - - - + @@ -57,6 +55,9 @@ + + + @@ -65,10 +66,16 @@ + - + + + + + + diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 0cafe14ef..2de81460e 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -6,4 +6,7 @@ + + +
diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 76d9ad311..165301587 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -32,8 +32,9 @@ import java.lang.reflect.Method; /** * The static entry point to the ComputerCraft API. - * Members in this class must be called after mod_ComputerCraft has been initialised, - * but may be called before it is fully loaded. + * + * Members in this class must be called after mod_ComputerCraft has been initialised, but may be called before it is + * fully loaded. */ public final class ComputerCraftAPI { @@ -269,7 +270,7 @@ public final class ComputerCraftAPI } /** - * Registers a media provider to provide {@link IMedia} implementations for Items + * Registers a media provider to provide {@link IMedia} implementations for Items. * * @param provider The media provider to register. * @see IMediaProvider @@ -370,7 +371,7 @@ public final class ComputerCraftAPI } /** - * Construct a new wired node for a given wired element + * Construct a new wired node for a given wired element. * * @param element The element to construct it for * @return The element's node @@ -398,7 +399,7 @@ public final class ComputerCraftAPI } /** - * Get the wired network element for a block in world + * Get the wired network element for a block in world. * * @param world The world the block exists in * @param pos The position the block exists in diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 1952ee9e0..d2e5e030e 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -19,7 +19,7 @@ import java.util.List; /** * Represents a read only part of a virtual filesystem that can be mounted onto a computer using - * {@link IComputerAccess#mount(String, IMount)} + * {@link IComputerAccess#mount(String, IMount)}. * * Ready made implementations of this interface can be created using * {@link ComputerCraftAPI#createSaveDirMount(World, String, long)} or @@ -60,7 +60,7 @@ public interface IMount void list( @Nonnull String path, @Nonnull List contents ) throws IOException; /** - * Returns the size of a file with a given path, in bytes + * Returns the size of a file with a given path, in bytes. * * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". * @return The size of the file, in bytes. diff --git a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java index 1ebb4af5f..9c5c6837e 100644 --- a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java +++ b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java @@ -26,7 +26,7 @@ public interface IComputerSystem extends IComputerAccess IFileSystem getFileSystem(); /** - * Get the label for this computer + * Get the label for this computer. * * @return This computer's label, or {@code null} if it is not set. */ diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index eec0d23f4..feebe9d0b 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -16,7 +16,7 @@ import javax.annotation.Nullable; import java.util.Map; /** - * Wrapper class for pocket computers + * Wrapper class for pocket computers. */ public interface IPocketAccess { diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java index 9bfabddf9..912fa6d30 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -12,12 +12,12 @@ package dan200.computercraft.api.turtle; public enum TurtleSide { /** - * The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle) + * The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle). */ Left, /** - * The turtle's right side (where the modem usually is on a Wireless Mining Turtle) + * The turtle's right side (where the modem usually is on a Wireless Mining Turtle). */ Right, } diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index cf8e6b086..050775081 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -18,12 +18,12 @@ import net.minecraft.util.EnumFacing; public enum TurtleVerb { /** - * The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()} + * The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}. */ Dig, /** - * The turtle called {@code turtle.attack()}, {@code turtle.attackUp()} or {@code turtle.attackDown()} + * The turtle called {@code turtle.attack()}, {@code turtle.attackUp()} or {@code turtle.attackDown()}. */ Attack, } diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java index 131e36613..b7e87ad3a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java @@ -71,7 +71,7 @@ public enum TurtleAction EQUIP, /** - * Inspect a block in world + * Inspect a block in world. * * @see TurtleBlockEvent.Inspect */ diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index 036075795..1c464b83e 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -112,7 +112,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent } /** - * Get the upgrade doing the digging + * Get the upgrade doing the digging. * * @return The upgrade doing the digging. */ diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java index 9e1ecf693..18441ec33 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java @@ -31,7 +31,7 @@ public abstract class TurtleInventoryEvent extends TurtleBlockEvent } /** - * Get the inventory being interacted with + * Get the inventory being interacted with. * * @return The inventory being interacted with, {@code null} if the item will be dropped to/sucked from the world. */ diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index 8780a5bec..2a2a22e1e 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.util.math.MathHelper; public abstract class ItemMapLikeRenderer { /** - * The main rendering method for the item + * The main rendering method for the item. * * @param stack The stack to render * @see ItemRenderer#renderMapFirstPerson(ItemStack) @@ -87,7 +87,7 @@ public abstract class ItemMapLikeRenderer } /** - * Render an item in the middle of the screen + * Render an item in the middle of the screen. * * @param pitch The pitch of the player * @param equipProgress The equip progress of this item diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 0a68512b4..1abf89489 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -32,7 +32,7 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.client.gui.GuiComputer.*; /** - * Emulates map rendering for pocket computers + * Emulates map rendering for pocket computers. */ @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) public final class ItemPocketRenderer extends ItemMapLikeRenderer diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index e82d47218..7e9432ed8 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -23,7 +23,7 @@ import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAG import static dan200.computercraft.shared.media.items.ItemPrintout.LINE_MAX_LENGTH; /** - * Emulates map and item-frame rendering for printouts + * Emulates map and item-frame rendering for printouts. */ @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT ) public final class ItemPrintoutRenderer extends ItemMapLikeRenderer diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 0fd97e80a..d49aeec0c 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -28,32 +28,32 @@ public final class PrintoutRenderer private static final double BG_SIZE = 256.0; /** - * Width of a page + * Width of a page. */ public static final int X_SIZE = 172; /** - * Height of a page + * Height of a page. */ public static final int Y_SIZE = 209; /** - * Padding between the left and right of a page and the text + * Padding between the left and right of a page and the text. */ public static final int X_TEXT_MARGIN = 13; /** - * Padding between the top and bottom of a page and the text + * Padding between the top and bottom of a page and the text. */ public static final int Y_TEXT_MARGIN = 11; /** - * Width of the extra page texture + * Width of the extra page texture. */ private static final int X_FOLD_SIZE = 12; /** - * Size of the leather cover + * Size of the leather cover. */ public static final int COVER_SIZE = 12; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java index 16eb83c45..e0222e821 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java @@ -97,6 +97,8 @@ public class TileEntityCableRenderer extends TileEntitySpecialRenderer The type of this resource. Should be the class extending from {@link Resource}. */ public abstract class Resource> implements Closeable { @@ -42,8 +44,9 @@ public abstract class Resource> implements Closeable } /** - * Checks if this has been cancelled. If so, it'll clean up any - * existing resources and cancel any pending futures. + * Checks if this has been cancelled. If so, it'll clean up any existing resources and cancel any pending futures. + * + * @return Whether this resource has been closed. */ public final boolean checkClosed() { @@ -80,6 +83,7 @@ public abstract class Resource> implements Closeable /** * Create a {@link WeakReference} which will close {@code this} when collected. * + * @param The object we are wrapping in a reference. * @param object The object to reference to * @return The weak reference. */ diff --git a/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java b/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java index 598d7f336..8686a3682 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java +++ b/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java @@ -14,6 +14,8 @@ import java.util.function.Supplier; /** * A collection of {@link Resource}s, with an upper bound on capacity. + * + * @param The type of the resource this group manages. */ public class ResourceGroup> { diff --git a/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java b/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java index 9ac8eb56f..c465d6316 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java +++ b/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java @@ -12,6 +12,8 @@ import java.util.function.Supplier; /** * A {@link ResourceGroup} which will queue items when the group at capacity. + * + * @param The type of the resource this queue manages. */ public class ResourceQueue> extends ResourceGroup { diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index d26e33b66..3f9c34ff7 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -40,7 +40,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** - * Represents one or more + * Represents an in-progress HTTP request. */ public class HttpRequest extends Resource { diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index a76a82621..114c24e80 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -226,7 +226,11 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler computerQueue = new TreeSet<>( ( a, b ) -> { if( a == b ) return 0; // Should never happen, but let's be consistent here @@ -126,7 +126,7 @@ public final class ComputerThread private ComputerThread() {} /** - * Start the computer thread + * Start the computer thread. */ static void start() { @@ -194,7 +194,7 @@ public final class ComputerThread } /** - * Mark a computer as having work, enqueuing it on the thread + * Mark a computer as having work, enqueuing it on the thread. * * You must be holding {@link ComputerExecutor}'s {@code queueLock} when calling this method - it should only * be called from {@code enqueue}. @@ -244,6 +244,8 @@ public final class ComputerThread * {@link #minimumVirtualRuntime} based on the current tasks. * * This is called before queueing tasks, to ensure that {@link #minimumVirtualRuntime} is up-to-date. + * + * @param current The machine which we updating runtimes from. */ private static void updateRuntimes( @Nullable ComputerExecutor current ) { @@ -321,7 +323,7 @@ public final class ComputerThread } /** - * The scaled period for a single task + * The scaled period for a single task. * * @return The scaled period for the task * @see #DEFAULT_LATENCY @@ -336,7 +338,7 @@ public final class ComputerThread } /** - * Determine if the thread has computers queued up + * Determine if the thread has computers queued up. * * @return If we have work queued up. */ diff --git a/src/main/java/dan200/computercraft/core/computer/TimeoutState.java b/src/main/java/dan200/computercraft/core/computer/TimeoutState.java index 9e8b332ee..5939ac2bd 100644 --- a/src/main/java/dan200/computercraft/core/computer/TimeoutState.java +++ b/src/main/java/dan200/computercraft/core/computer/TimeoutState.java @@ -36,12 +36,12 @@ import java.util.concurrent.TimeUnit; public final class TimeoutState { /** - * The total time a task is allowed to run before aborting in nanoseconds + * The total time a task is allowed to run before aborting in nanoseconds. */ static final long TIMEOUT = TimeUnit.MILLISECONDS.toNanos( 7000 ); /** - * The time the task is allowed to run after each abort in nanoseconds + * The time the task is allowed to run after each abort in nanoseconds. */ static final long ABORT_TIMEOUT = TimeUnit.MILLISECONDS.toNanos( 1500 ); @@ -111,6 +111,8 @@ public final class TimeoutState /** * If the machine should be passively aborted. + * + * @return {@code true} if we should throw a timeout error. */ public boolean isSoftAborted() { @@ -118,7 +120,9 @@ public final class TimeoutState } /** - * If the machine should be forcibly aborted. + * Determine if the machine should be forcibly aborted. + * + * @return {@code true} if the machine should be forcibly shut down. */ public boolean isHardAborted() { @@ -146,7 +150,7 @@ public final class TimeoutState } /** - * Pauses the cumulative time, to be resumed by {@link #startTimer()} + * Pauses the cumulative time, to be resumed by {@link #startTimer()}. * * @see #nanoCumulative() */ diff --git a/src/main/java/dan200/computercraft/core/lua/MachineResult.java b/src/main/java/dan200/computercraft/core/lua/MachineResult.java index 26a4608d7..0b3cf8c0a 100644 --- a/src/main/java/dan200/computercraft/core/lua/MachineResult.java +++ b/src/main/java/dan200/computercraft/core/lua/MachineResult.java @@ -38,7 +38,7 @@ public final class MachineResult public static final MachineResult TIMEOUT = new MachineResult( true, false, TimeoutState.ABORT_MESSAGE ); /** - * An error with no user-friendly error message + * An error with no user-friendly error message. */ public static final MachineResult GENERIC_ERROR = new MachineResult( true, false, null ); diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 50719cc73..4bd0921de 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -314,6 +314,9 @@ public class Terminal } /** + * Determine whether this terminal has changed. + * + * @return If this terminal is dirty. * @deprecated All {@code *Changed()} methods are deprecated: one should pass in a callback * instead. */ diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java index 23cea8b6b..e4dfe3624 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java @@ -18,7 +18,7 @@ import java.util.List; import java.util.Map; /** - * A command which delegates to a series of sub commands + * A command which delegates to a series of sub commands. */ public class CommandRoot implements ISubCommand { diff --git a/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java b/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java index 828b31683..051fe3e75 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java @@ -22,7 +22,7 @@ import java.util.List; public interface ISubCommand { /** - * Get the name of this command + * Get the name of this command. * * @return The name of this command * @see ICommand#getName() @@ -40,7 +40,7 @@ public interface ISubCommand String getFullName(); /** - * Get the usage of this command + * Get the usage of this command. * * @param context The context this command is executed in * @return The usage of this command @@ -62,16 +62,17 @@ public interface ISubCommand boolean checkPermission( @Nonnull CommandContext context ); /** - * Execute this command + * Execute this command. * * @param context The current command context. - * @param arguments The arguments passed @throws CommandException When an error occurs + * @param arguments The arguments passed + * @throws CommandException When an error occurs * @see ICommand#execute(MinecraftServer, ICommandSender, String[]) */ void execute( @Nonnull CommandContext context, @Nonnull List arguments ) throws CommandException; /** - * Get a list of possible completions + * Get a list of possible completions. * * @param context The current command context. * @param arguments The arguments passed. You should complete the last one. diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index 3b61a6cc8..9e942d2fd 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -15,7 +15,7 @@ import net.minecraft.util.text.event.ClickEvent; import net.minecraft.util.text.event.HoverEvent; /** - * Various helpers for building chat messages + * Various helpers for building chat messages. */ public final class ChatHelpers { diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java index 62fd7fc9f..155306f32 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java @@ -107,7 +107,7 @@ public class TableBuilder } /** - * Trim this table to a given height + * Trim this table to a given height. * * @param height The desired height. */ diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index eaa7f63f2..2b6b361d4 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -22,7 +22,7 @@ public interface TableFormatter ITextComponent HEADER = coloured( "=", TextFormatting.GRAY ); /** - * Get additional padding for the component + * Get additional padding for the component. * * @param component The component to pad * @param width The desired width for the component @@ -32,7 +32,7 @@ public interface TableFormatter ITextComponent getPadding( ITextComponent component, int width ); /** - * Get the minimum padding between each column + * Get the minimum padding between each column. * * @return The minimum padding. */ diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 7034d91b7..6e709d3eb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -280,7 +280,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } /** - * Gets the redstone input for an adjacent block + * Gets the redstone input for an adjacent block. * * @param world The world we exist in * @param pos The position of the neighbour diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java index fc451fea9..c2b800eab 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.core; /** - * Receives some input and forwards it to a computer + * Receives some input and forwards it to a computer. * * @see InputState * @see IComputer diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 867b89947..43f002368 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -108,7 +108,7 @@ public class JEIComputerCraft implements IModPlugin } /** - * Distinguishes turtles by upgrades and family + * Distinguishes turtles by upgrades and family. */ private static final ISubtypeInterpreter turtleSubtype = stack -> { Item item = stack.getItem(); @@ -132,7 +132,7 @@ public class JEIComputerCraft implements IModPlugin }; /** - * Distinguishes pocket computers by upgrade and family + * Distinguishes pocket computers by upgrade and family. */ private static final ISubtypeInterpreter pocketSubtype = stack -> { Item item = stack.getItem(); @@ -152,7 +152,7 @@ public class JEIComputerCraft implements IModPlugin }; /** - * Distinguishes disks by colour + * Distinguishes disks by colour. */ private static final ISubtypeInterpreter diskSubtype = stack -> { Item item = stack.getItem(); diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 73fcc6e0d..39b0980c5 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -15,7 +15,7 @@ import net.minecraft.util.SoundEvent; import javax.annotation.Nonnull; /** - * An implementation of IMedia for ItemRecord's + * An implementation of IMedia for ItemRecords. */ public final class RecordMedia implements IMedia { diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 441738db0..d644e6ffe 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -72,6 +72,7 @@ public final class NetworkHandler * /** * Register packet, and a thread-unsafe handler for it. * + * @param The type of the packet to send. * @param id The identifier for this packet type * @param side The side to register this packet handler under * @param factory The factory for this type of packet. diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java index 6ec0ada76..a7718656c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java @@ -7,8 +7,11 @@ package dan200.computercraft.shared.peripheral.modem; /** - * This only exists for backwards compatibility + * This only exists for backwards compatibility. + * + * @deprecated Use {@link dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral} instead. */ +@Deprecated public abstract class WirelessModemPeripheral extends dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral { @Deprecated diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index d7451df90..83aa8590f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -23,7 +23,7 @@ import java.util.Collections; import java.util.Map; /** - * Represents a local peripheral exposed on the wired network + * Represents a local peripheral exposed on the wired network. * * This is responsible for getting the peripheral in world, tracking id and type and determining whether * it has changed. @@ -39,7 +39,7 @@ public final class WiredModemLocalPeripheral private IPeripheral peripheral; /** - * Attach a new peripheral from the world + * Attach a new peripheral from the world. * * @param world The world to search in * @param origin The position to search from @@ -76,7 +76,7 @@ public final class WiredModemLocalPeripheral } /** - * Detach the current peripheral + * Detach the current peripheral. * * @return Whether the peripheral changed */ diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 209eb4503..6bd90717e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -37,7 +37,7 @@ public class TurtlePlayer extends FakePlayer ); /** - * Construct a TurtlePlayer which exists in the world + * Construct a TurtlePlayer which exists in the world. * * @param world The world the player exists in * @deprecated This is required by {@link Entity}. diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index 8c92a25a4..f91c8f96d 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared.util; +import net.minecraft.util.text.TextComponentTranslation; + public final class StringUtil { private StringUtil() {} @@ -33,7 +35,12 @@ public final class StringUtil } /** - * Translates a Stat name + * Translates a string. + * + * Try to avoid using this where possible - it is generally preferred to use {@link TextComponentTranslation}. + * + * @param key The key to translate. + * @return The translated string. */ @SuppressWarnings( "deprecation" ) public static String translate( String key ) @@ -42,12 +49,18 @@ public final class StringUtil } /** - * Translates a Stat name with format args + * Translates and formats a string. + * + * Try to avoid using this where possible - it is generally preferred to use {@link TextComponentTranslation}. + * + * @param key The key to translate. + * @param args The arguments to supply to {@link String#format(String, Object...)}. + * @return The translated and formatted string. */ @SuppressWarnings( "deprecation" ) - public static String translateFormatted( String key, Object... format ) + public static String translateFormatted( String key, Object... args ) { - return net.minecraft.util.text.translation.I18n.translateToLocalFormatted( key, format ); + return net.minecraft.util.text.translation.I18n.translateToLocalFormatted( key, args ); } public static byte[] encodeString( String string ) diff --git a/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java b/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java index 1d58cc5a2..0751dbe1b 100644 --- a/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java @@ -12,7 +12,7 @@ import dan200.computercraft.ComputerCraft; import java.util.concurrent.ThreadFactory; /** - * Provides some utilities to create thread groups + * Provides some utilities to create thread groups. */ public final class ThreadUtils { @@ -33,7 +33,7 @@ public final class ThreadUtils } /** - * Construct a group under ComputerCraft's shared group + * Construct a group under ComputerCraft's shared group. * * @param name The group's name. This will be prefixed with "ComputerCraft-". * @return The constructed thread group. From 38f9a015cae50e2ba1731f61fc3f6a06068c7ec4 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 30 Oct 2019 17:07:29 +0000 Subject: [PATCH 091/711] Wrap all remaining uses of Grgit This allows you to build from a zip folder of CC:T. Fixes #307. Also fix the build, woops. --- build.gradle | 5 ++++- .../dan200/computercraft/core/computer/BasicEnvironment.java | 3 +-- .../dan200/computercraft/core/filesystem/FileSystemTest.java | 4 ++++ .../dan200/computercraft/core/filesystem/MemoryMount.java | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index d071ab3a8..4632fcf19 100644 --- a/build.gradle +++ b/build.gradle @@ -331,6 +331,7 @@ task checkRelease { if (!ok) throw new IllegalStateException("Could not check release") } } +check.dependsOn checkRelease curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' @@ -402,7 +403,9 @@ githubRelease { token project.hasProperty('githubApiKey') ? project.githubApiKey : '' owner 'SquidDev-CC' repo 'CC-Tweaked' - targetCommitish { Grgit.open(dir: '.').branch.current().name } + try { + targetCommitish = Grgit.open(dir: '.').branch.current().name + } catch(Exception ignored) { } tagName "v${mc_version}-${mod_version}" releaseName "[${mc_version}] ${mod_version}" diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index b43ef3bda..a66ba69d0 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -23,7 +23,7 @@ import java.net.URISyntaxException; import java.net.URL; /** - * A very basic environment + * A very basic environment. */ public class BasicEnvironment implements IComputerEnvironment { @@ -93,7 +93,6 @@ public class BasicEnvironment implements IComputerEnvironment return ComputerCraft.class.getClassLoader().getResourceAsStream( "assets/" + domain + "/" + subPath ); } - public static IMount createMount( Class klass, String path, String fallback ) { File file = getContainingFile( klass ); diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java index abff129e8..3711afa16 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -26,6 +26,10 @@ public class FileSystemTest /** * Ensures writing a file truncates it. + * + * @throws FileSystemException When the file system cannot be constructed. + * @throws LuaException When Lua functions fail. + * @throws IOException When reading and writing from strings */ @Test public void testWriteTruncates() throws FileSystemException, LuaException, IOException diff --git a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java index 60070a4d0..b68ba4340 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java +++ b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java @@ -13,7 +13,7 @@ import java.io.*; import java.util.*; /** - * Mounts in memory + * In-memory file mounts. */ public class MemoryMount implements IWritableMount { From 44d0f78c1b723a346bc3621530c0fdba9eb5326b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 09:58:54 +0000 Subject: [PATCH 092/711] Bump versions --- build.gradle | 6 +++--- gradle.properties | 6 +++--- src/main/resources/META-INF/mods.toml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 6272797a9..b17fd3823 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.147' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.154' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } @@ -94,11 +94,11 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.10:api") + compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.25:api") // deobfProvided "pl.asie:Charset-Lib:0.5.4.6" // deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" - runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.10") + runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.25") shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' diff --git a/gradle.properties b/gradle.properties index 21f69460e..1856117f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Mod properties mod_version=1.85.0 -# Minecraft properties +# Minecraft properties (update mods.toml when changing) mc_version=1.14.4 -forge_version=28.1.26 -mappings_version=20190912-1.14.3 +forge_version=28.1.71 +mappings_version=20191123-1.14.3 diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index c9f314f66..fed62637f 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[28,29)" + versionRange="[28.1.71,29)" ordering="NONE" side="BOTH" From a8fadabaf151dca5f9b49d136ade49866f7a5072 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 09:59:37 +0000 Subject: [PATCH 093/711] Correct spelling in error message --- .../dan200/computercraft/shared/computer/apis/CommandAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 2dd6f0aa4..1be33cf02 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -204,7 +204,7 @@ public class CommandAPI implements ILuaAPI ); if( !world.isValid( min ) || !world.isValid( max ) ) { - throw new LuaException( "Co-ordinates out or range" ); + throw new LuaException( "Co-ordinates out of range" ); } if( (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1) > 4096 ) { @@ -243,7 +243,7 @@ public class CommandAPI implements ILuaAPI } else { - throw new LuaException( "co-ordinates out or range" ); + throw new LuaException( "Co-ordinates out of range" ); } } ); } From 927ddb0bde19117a78372c0e595d7cb785ee3e9a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 10:14:32 +0000 Subject: [PATCH 094/711] Remove Charset and MCMP integration for now It's not clear if either of these are coming back soon, and it should be fairly simple to add them back when needed. --- build.gradle | 9 -- .../charset/BundledCapabilityProvider.java | 89 ------------ .../charset/BundledRedstoneProvider.java | 33 ----- .../charset/IntegrationCharset.java | 52 ------- .../shared/integration/mcmp/MCMPHooks.java | 49 ------- .../integration/mcmp/MCMPIntegration.java | 127 ------------------ .../integration/mcmp/PartAdvancedModem.java | 41 ------ .../integration/mcmp/PartPeripheral.java | 67 --------- .../proxy/ComputerCraftProxyCommon.java | 2 - 9 files changed, 469 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java diff --git a/build.gradle b/build.gradle index b17fd3823..f3920006e 100644 --- a/build.gradle +++ b/build.gradle @@ -108,15 +108,6 @@ dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" } -sourceSets { - main { - java { - exclude 'dan200/computercraft/shared/integration/mcmp' - exclude 'dan200/computercraft/shared/integration/charset' - } - } -} - // Compile tasks javadoc { diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java deleted file mode 100644 index 6fab2ce31..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.integration.charset; - -import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.util.Direction; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import pl.asie.charset.api.wires.IBundledEmitter; -import pl.asie.charset.api.wires.IBundledReceiver; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_EMITTER; -import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_RECEIVER; - -final class BundledCapabilityProvider implements ICapabilityProvider -{ - private final TileGeneric tile; - private IBundledReceiver receiver; - private IBundledEmitter[] emitters; - - BundledCapabilityProvider( TileGeneric tile ) - { - this.tile = tile; - } - - @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable Direction side ) - { - return capability == CAPABILITY_EMITTER || capability == CAPABILITY_RECEIVER; - } - - @Nullable - @Override - public T getCapability( @Nonnull Capability capability, @Nullable Direction side ) - { - if( capability == CAPABILITY_RECEIVER ) - { - IBundledReceiver receiver = this.receiver; - if( receiver == null ) - { - receiver = this.receiver = () -> tile.onNeighbourChange( tile.getPos().offset( side ) ); - } - - return CAPABILITY_RECEIVER.cast( receiver ); - } - else if( capability == CAPABILITY_EMITTER ) - { - IBundledEmitter[] emitters = this.emitters; - if( emitters == null ) emitters = this.emitters = new IBundledEmitter[7]; - - int index = side == null ? 6 : side.getIndex(); - IBundledEmitter emitter = emitters[index]; - if( emitter == null ) - { - if( side == null ) - { - emitter = emitters[index] = () -> { - int flags = 0; - for( Direction facing : Direction.VALUES ) flags |= tile.getBundledRedstoneOutput( facing ); - return toBytes( flags ); - }; - } - else - { - emitter = emitters[index] = () -> toBytes( tile.getBundledRedstoneOutput( side ) ); - } - } - - return CAPABILITY_EMITTER.cast( emitter ); - } - else - { - return null; - } - } - - private static byte[] toBytes( int flag ) - { - byte[] channels = new byte[16]; - for( int i = 0; i < 16; i++ ) channels[i] = (flag & (1 << i)) == 0 ? (byte) 0 : 15; - return channels; - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java deleted file mode 100644 index a2a857025..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.integration.charset; - -import dan200.computercraft.api.redstone.IBundledRedstoneProvider; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -import static dan200.computercraft.shared.integration.charset.IntegrationCharset.CAPABILITY_EMITTER; - -public class BundledRedstoneProvider implements IBundledRedstoneProvider -{ - @Override - public int getBundledRedstoneOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) - { - TileEntity tile = world.getTileEntity( pos ); - if( tile == null || !tile.hasCapability( CAPABILITY_EMITTER, side ) ) return -1; - - byte[] signal = tile.getCapability( CAPABILITY_EMITTER, side ).getBundledSignal(); - if( signal == null ) return -1; - - int flag = 0; - for( int i = 0; i < signal.length; i++ ) flag |= signal[i] > 0 ? 1 << i : 0; - return flag; - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java deleted file mode 100644 index 32055fc92..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.integration.charset; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.shared.common.TileGeneric; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityInject; -import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import pl.asie.charset.api.wires.IBundledEmitter; -import pl.asie.charset.api.wires.IBundledReceiver; - -public final class IntegrationCharset -{ - private static final ResourceLocation CAPABILITY_KEY = new ResourceLocation( ComputerCraft.MOD_ID, "charset" ); - - @CapabilityInject( IBundledEmitter.class ) - static Capability CAPABILITY_EMITTER = null; - - @CapabilityInject( IBundledReceiver.class ) - static Capability CAPABILITY_RECEIVER = null; - - private IntegrationCharset() - { - } - - public static void register() - { - if( CAPABILITY_EMITTER == null || CAPABILITY_RECEIVER == null ) return; - - MinecraftForge.EVENT_BUS.register( IntegrationCharset.class ); - ComputerCraftAPI.registerBundledRedstoneProvider( new BundledRedstoneProvider() ); - } - - @SubscribeEvent - public static void attachGenericCapabilities( AttachCapabilitiesEvent event ) - { - TileEntity tile = event.getObject(); - if( tile instanceof TileGeneric ) - { - event.addCapability( CAPABILITY_KEY, new BundledCapabilityProvider( (TileGeneric) tile ) ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java deleted file mode 100644 index f659971fa..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.integration.mcmp; - -import mcmultipart.MCMultiPart; -import mcmultipart.api.item.ItemBlockMultipart; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.BlockItem; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraftforge.fml.common.Loader; - -import javax.annotation.Nonnull; - -public final class MCMPHooks -{ - private MCMPHooks() - { - } - - public static ActionResultType onItemUse( BlockItem itemBlock, PlayerEntity player, World world, @Nonnull BlockPos pos, @Nonnull Hand hand, @Nonnull Direction facing, float hitX, float hitY, float hitZ ) - { - if( !Loader.isModLoaded( MCMultiPart.MODID ) ) return ActionResultType.PASS; - - return ItemBlockMultipart.place( - player, world, pos, hand, facing, hitX, hitY, hitZ, itemBlock, - itemBlock.getBlock()::getStateForPlacement, - MCMPIntegration.multipartMap.get( itemBlock.getBlock() ), - - ( - ItemStack stack, PlayerEntity thisPlayer, World thisWorld, BlockPos thisPos, Direction thisFacing, - float thisX, float thisY, float thisZ, BlockState thisState - ) -> - thisPlayer.canPlayerEdit( thisPos, thisFacing, stack ) && - thisWorld.getBlockState( thisPos ).getBlock().isReplaceable( thisWorld, thisPos ) && - itemBlock.getBlock().canPlaceBlockAt( thisWorld, thisPos ) && - itemBlock.getBlock().canPlaceBlockOnSide( thisWorld, thisPos, thisFacing ) && - itemBlock.placeBlockAt( stack, thisPlayer, thisWorld, thisPos, thisFacing, thisX, thisY, thisZ, thisState ), - ItemBlockMultipart::placePartAt - ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java deleted file mode 100644 index d3031c695..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.integration.mcmp; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; -import dan200.computercraft.shared.peripheral.common.TilePeripheralBase; -import dan200.computercraft.shared.peripheral.modem.wireless.TileAdvancedModem; -import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem; -import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import mcmultipart.api.addon.IMCMPAddon; -import mcmultipart.api.addon.MCMPAddon; -import mcmultipart.api.container.IMultipartContainer; -import mcmultipart.api.multipart.IMultipart; -import mcmultipart.api.multipart.IMultipartRegistry; -import mcmultipart.api.multipart.IMultipartTile; -import mcmultipart.api.ref.MCMPCapabilities; -import mcmultipart.api.slot.EnumFaceSlot; -import net.minecraft.block.Block; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; - -@MCMPAddon -public class MCMPIntegration implements IMCMPAddon -{ - private static final ResourceLocation CAPABILITY_KEY = new ResourceLocation( ComputerCraft.MOD_ID, "mcmultipart" ); - - static final Map multipartMap = new HashMap<>(); - - private static void register( IMultipartRegistry registry, Block block, IMultipart multipart ) - { - registry.registerPartWrapper( block, multipart ); - multipartMap.put( block, multipart ); - } - - @Override - public void registerParts( IMultipartRegistry registry ) - { - // Setup all parts - register( registry, ComputerCraft.Blocks.peripheral, new PartPeripheral() ); - register( registry, ComputerCraft.Blocks.advancedModem, new PartAdvancedModem() ); - - // Subscribe to capability events - MinecraftForge.EVENT_BUS.register( MCMPIntegration.class ); - - // Register a peripheral provider - ComputerCraftAPI.registerPeripheralProvider( ( world, pos, side ) -> - { - TileEntity tile = world.getTileEntity( pos ); - if( tile == null || !tile.hasCapability( MCMPCapabilities.MULTIPART_CONTAINER, null ) ) return null; - IMultipartContainer container = tile.getCapability( MCMPCapabilities.MULTIPART_CONTAINER, null ); - if( container == null ) return null; - - IMultipartTile multipart = container.getPartTile( EnumFaceSlot.fromFace( side ) ).orElse( null ); - if( multipart == null ) return null; - if( multipart instanceof IPeripheral ) return (IPeripheral) multipart; - if( multipart instanceof IPeripheralTile ) return ((IPeripheralTile) multipart).getPeripheral( side ); - - TileEntity underlying = multipart.getTileEntity(); - if( underlying instanceof IPeripheral ) return (IPeripheral) underlying; - if( underlying instanceof IPeripheralTile ) return ((IPeripheralTile) underlying).getPeripheral( side ); - - return null; - } ); - } - - @SubscribeEvent - public static void attach( AttachCapabilitiesEvent event ) - { - TileEntity tile = event.getObject(); - if( tile instanceof TileAdvancedModem || tile instanceof TileWirelessModem - || tile instanceof TilePeripheralBase || tile instanceof TileMonitor ) - { - // We need to attach to modems (obviously), but also any other tile created by BlockPeripheral. Otherwise - // IMultipart.convertToMultipartTile will error. - event.addCapability( CAPABILITY_KEY, new BasicMultipart( tile ) ); - } - } - - private static final class BasicMultipart implements ICapabilityProvider - { - private final TileEntity tile; - private IMultipartTile wrapped; - - private BasicMultipart( TileEntity tile ) - { - this.tile = tile; - } - - @Override - public boolean hasCapability( @Nonnull Capability capability, @Nullable Direction facing ) - { - return capability == MCMPCapabilities.MULTIPART_TILE; - } - - @Nullable - @Override - public T getCapability( @Nonnull Capability capability, @Nullable Direction facing ) - { - if( capability == MCMPCapabilities.MULTIPART_TILE ) - { - IMultipartTile wrapped = this.wrapped; - if( wrapped == null ) wrapped = this.wrapped = IMultipartTile.wrap( tile ); - return MCMPCapabilities.MULTIPART_TILE.cast( wrapped ); - } - - return null; - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java deleted file mode 100644 index b220d33e9..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.integration.mcmp; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem; -import mcmultipart.api.multipart.IMultipart; -import mcmultipart.api.slot.EnumFaceSlot; -import mcmultipart.api.slot.IPartSlot; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.LivingEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; - -public class PartAdvancedModem implements IMultipart -{ - @Override - public IPartSlot getSlotForPlacement( World world, BlockPos pos, BlockState state, Direction facing, float hitX, float hitY, float hitZ, LivingEntity placer ) - { - return EnumFaceSlot.fromFace( state.getValue( BlockAdvancedModem.FACING ) ); - } - - @Override - public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, BlockState state ) - { - return EnumFaceSlot.fromFace( state.getValue( BlockAdvancedModem.FACING ) ); - } - - @Override - public Block getBlock() - { - return ComputerCraft.Blocks.advancedModem; - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java deleted file mode 100644 index f96572caa..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.integration.mcmp; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.common.BlockPeripheral; -import dan200.computercraft.shared.peripheral.common.BlockPeripheralVariant; -import mcmultipart.api.multipart.IMultipart; -import mcmultipart.api.slot.EnumCenterSlot; -import mcmultipart.api.slot.EnumFaceSlot; -import mcmultipart.api.slot.IPartSlot; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.LivingEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; - -public class PartPeripheral implements IMultipart -{ - @Override - public IPartSlot getSlotForPlacement( World world, BlockPos pos, BlockState state, Direction facing, float hitX, float hitY, float hitZ, LivingEntity placer ) - { - return getSlot( state ); - } - - @Override - public IPartSlot getSlotFromWorld( IBlockAccess world, BlockPos pos, BlockState state ) - { - return getSlot( state ); - } - - @Nonnull - private static IPartSlot getSlot( BlockState state ) - { - BlockPeripheralVariant type = state.getValue( BlockPeripheral.VARIANT ); - if( type == BlockPeripheralVariant.WirelessModemUpOn || type == BlockPeripheralVariant.WirelessModemUpOff ) - { - return EnumFaceSlot.UP; - } - else if( type == BlockPeripheralVariant.WirelessModemDownOn || type == BlockPeripheralVariant.WirelessModemDownOff ) - { - return EnumFaceSlot.DOWN; - } - else if( type == BlockPeripheralVariant.WirelessModemOff || type == BlockPeripheralVariant.WirelessModemOn ) - { - return EnumFaceSlot.fromFace( state.getValue( BlockPeripheral.FACING ) ); - } - else - { - return EnumCenterSlot.CENTER; - } - } - - @Override - public Block getBlock() - { - return ComputerCraft.Blocks.peripheral; - } -} diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 11490e9ae..4cbbd8083 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -67,8 +67,6 @@ public final class ComputerCraftProxyCommon PlayerCreativeLootCondition.class, PlayerCreativeLootCondition.INSTANCE ) ); - - // if( Loader.isModLoaded( ModCharset.MODID ) ) IntegrationCharset.register(); } private static void registerProviders() From be6dd21e546925ffafc7e24b43094f77c9236d6d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 10:31:55 +0000 Subject: [PATCH 095/711] Make monitors "properly" solid blocks This fixes monitor rendering underwater (closes #314). By default, isSolid returns true if the render layer is SOLID. As we use CUTOUT due to our funky TE rendering, we need to override this to return true anyway. This will cause some side effects, as monitors now blocking light propagation, but I don't think that's the end of the world. --- .../shared/peripheral/monitor/BlockMonitor.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 104ef94cc..50d61c5e2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -49,9 +49,18 @@ public class BlockMonitor extends BlockGeneric @Override public BlockRenderLayer getRenderLayer() { + // We use the CUTOUT layer, as otherwise monitor rendering will cause flickering. return BlockRenderLayer.CUTOUT; } + @Override + @Deprecated + public boolean isSolid( BlockState p_200124_1_ ) + { + // We override isSolid, as our overriding of getRenderLayer means that it would otherwise return false. + return true; + } + @Override protected void fillStateContainer( StateContainer.Builder builder ) { From 0de75f05ddb7275b365e8753c4223579b269aed8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 11:17:03 +0000 Subject: [PATCH 096/711] Make parameter name a bit nicer Woops --- .../computercraft/shared/peripheral/monitor/BlockMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 50d61c5e2..2ea865c2c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -55,7 +55,7 @@ public class BlockMonitor extends BlockGeneric @Override @Deprecated - public boolean isSolid( BlockState p_200124_1_ ) + public boolean isSolid( BlockState state ) { // We override isSolid, as our overriding of getRenderLayer means that it would otherwise return false. return true; From ee4e42e7302b9c2bdb51c5f149eeedd036424e66 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 11:23:25 +0000 Subject: [PATCH 097/711] Dont' remove treasure disks from JEI This shouldn't matter either way - we don't expose it in the creative menu, and there's no recipes for it. This should shut up a log message though. Fixes #305. --- .../shared/integration/jei/JEIComputerCraft.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 2ce9eb8e6..79c4ccecb 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -35,7 +35,6 @@ import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import static dan200.computercraft.shared.integration.jei.RecipeResolver.MAIN_FAMILIES; @@ -92,10 +91,6 @@ public class JEIComputerCraft implements IModPlugin runtime.getIngredientManager().addIngredientsAtRuntime( VanillaTypes.ITEM, upgradeItems ); - // Hide treasure disks - runtime.getIngredientManager().removeIngredientsAtRuntime( VanillaTypes.ITEM, - Collections.singletonList( new ItemStack( ComputerCraft.Items.treasureDisk ) ) ); - // Hide all upgrade recipes IRecipeCategory category = (IRecipeCategory) registry.getRecipeCategory( VanillaRecipeCategoryUid.CRAFTING ); if( category != null ) From bedac71e3dba731cf4c18df2a15d05be8a4bb17f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 12:12:02 +0000 Subject: [PATCH 098/711] Add a fake network handler to the TurtleFakePlayer This should fix several issues (see #304, etc...). I'll try to get round to PRing this into Forge at some point, though on the other hand this is /super/ ugly. --- .../shared/turtle/core/TurtlePlayer.java | 88 ++++- .../shared/util/FakeNetHandler.java | 360 ++++++++++++++++++ 2 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 64edff54d..9c23e4f14 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -9,12 +9,20 @@ package dan200.computercraft.shared.turtle.core; import com.mojang.authlib.GameProfile; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.shared.util.FakeNetHandler; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityClassification; import net.minecraft.entity.EntityType; +import net.minecraft.entity.passive.horse.AbstractHorseEntity; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; +import net.minecraft.potion.EffectInstance; +import net.minecraft.tileentity.SignTileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.server.ServerWorld; @@ -22,6 +30,7 @@ import net.minecraftforge.common.util.FakePlayer; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.OptionalInt; import java.util.UUID; public final class TurtlePlayer extends FakePlayer @@ -40,6 +49,7 @@ public final class TurtlePlayer extends FakePlayer private TurtlePlayer( ITurtleAccess turtle ) { super( (ServerWorld) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); + this.connection = new FakeNetHandler( this ); setState( turtle ); } @@ -50,6 +60,13 @@ public final class TurtlePlayer extends FakePlayer private void setState( ITurtleAccess turtle ) { + if( openContainer != null ) + { + ComputerCraft.log.warn( "Turtle has open container ({})", openContainer ); + openContainer.onContainerClosed( this ); + openContainer = null; + } + BlockPos position = turtle.getPosition(); posX = position.getX() + 0.5; posY = position.getY() + 0.5; @@ -126,6 +143,73 @@ public final class TurtlePlayer extends FakePlayer return new Vec3d( posX, posY, posZ ); } - // TODO: Work out what needs stubbing again. - // Or just replace the network. + //region Code which depends on the connection + @Nonnull + @Override + public OptionalInt openContainer( @Nullable INamedContainerProvider prover ) + { + return OptionalInt.empty(); + } + + @Override + public void sendEnterCombat() + { + } + + @Override + public void sendEndCombat() + { + } + + @Override + public boolean startRiding( @Nonnull Entity entityIn, boolean force ) + { + return false; + } + + @Override + public void stopRiding() + { + } + + @Override + public void openSignEditor( SignTileEntity signTile ) + { + } + + @Override + public void openHorseInventory( AbstractHorseEntity horse, IInventory inventory ) + { + } + + @Override + public void openBook( ItemStack stack, @Nonnull Hand hand ) + { + } + + @Override + public void closeScreen() + { + } + + @Override + public void updateHeldItem() + { + } + + @Override + protected void onNewPotionEffect( EffectInstance id ) + { + } + + @Override + protected void onChangedPotionEffect( EffectInstance id, boolean apply ) + { + } + + @Override + protected void onFinishedPotionEffect( EffectInstance effect ) + { + } + //endregion } diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java new file mode 100644 index 000000000..9d2c504b9 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -0,0 +1,360 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.minecraft.network.*; +import net.minecraft.network.play.ServerPlayNetHandler; +import net.minecraft.network.play.client.*; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.common.util.FakePlayer; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.crypto.SecretKey; + +public class FakeNetHandler extends ServerPlayNetHandler +{ + public FakeNetHandler( @Nonnull FakePlayer player ) + { + super( player.getServerWorld().getServer(), new FakeNetworkManager(), player ); + } + + @Override + public void tick() + { + } + + @Override + public void disconnect( @Nonnull ITextComponent reason ) + { + } + + @Override + public void onDisconnect( ITextComponent reason ) + { + } + + @Override + public void sendPacket( @Nonnull IPacket packet ) + { + } + + @Override + public void sendPacket( @Nonnull IPacket packet, @Nullable GenericFutureListener> whenSent ) + { + } + + @Override + public void processInput( CInputPacket packet ) + { + } + + @Override + public void processVehicleMove( CMoveVehiclePacket packet ) + { + } + + @Override + public void processConfirmTeleport( CConfirmTeleportPacket packet ) + { + } + + @Override + public void handleRecipeBookUpdate( CRecipeInfoPacket packet ) + { + } + + @Override + public void handleSeenAdvancements( CSeenAdvancementsPacket packet ) + { + } + + @Override + public void processTabComplete( CTabCompletePacket packet ) + { + } + + @Override + public void processUpdateCommandBlock( @Nonnull CUpdateCommandBlockPacket packet ) + { + } + + @Override + public void processUpdateCommandMinecart( @Nonnull CUpdateMinecartCommandBlockPacket packet ) + { + } + + @Override + public void processPickItem( CPickItemPacket packet ) + { + } + + @Override + public void processRenameItem( @Nonnull CRenameItemPacket packet ) + { + } + + @Override + public void processUpdateBeacon( @Nonnull CUpdateBeaconPacket packet ) + { + } + + @Override + public void processUpdateStructureBlock( @Nonnull CUpdateStructureBlockPacket packet ) + { + } + + @Override + public void func_217262_a( @Nonnull CUpdateJigsawBlockPacket packet ) + { + } + + @Override + public void processSelectTrade( CSelectTradePacket packet ) + { + } + + @Override + public void processEditBook( CEditBookPacket packet ) + { + } + + @Override + public void processNBTQueryEntity( @Nonnull CQueryEntityNBTPacket packet ) + { + } + + @Override + public void processNBTQueryBlockEntity( @Nonnull CQueryTileEntityNBTPacket packet ) + { + } + + @Override + public void processPlayer( CPlayerPacket packet ) + { + } + + @Override + public void processPlayerDigging( CPlayerDiggingPacket packet ) + { + } + + @Override + public void processTryUseItemOnBlock( CPlayerTryUseItemOnBlockPacket packet ) + { + } + + @Override + public void processTryUseItem( CPlayerTryUseItemPacket packet ) + { + } + + @Override + public void handleSpectate( @Nonnull CSpectatePacket packet ) + { + } + + @Override + public void handleResourcePackStatus( CResourcePackStatusPacket packet ) + { + } + + @Override + public void processSteerBoat( @Nonnull CSteerBoatPacket packet ) + { + } + + @Override + public void processHeldItemChange( CHeldItemChangePacket packet ) + { + } + + @Override + public void processChatMessage( @Nonnull CChatMessagePacket packet ) + { + } + + @Override + public void handleAnimation( CAnimateHandPacket packet ) + { + } + + @Override + public void processEntityAction( CEntityActionPacket packet ) + { + } + + @Override + public void processUseEntity( CUseEntityPacket packet ) + { + } + + @Override + public void processClientStatus( CClientStatusPacket packet ) + { + } + + @Override + public void processCloseWindow( @Nonnull CCloseWindowPacket packet ) + { + } + + @Override + public void processClickWindow( CClickWindowPacket packet ) + { + } + + @Override + public void processPlaceRecipe( @Nonnull CPlaceRecipePacket packet ) + { + } + + @Override + public void processEnchantItem( CEnchantItemPacket packet ) + { + } + + @Override + public void processCreativeInventoryAction( @Nonnull CCreativeInventoryActionPacket packet ) + { + } + + @Override + public void processConfirmTransaction( CConfirmTransactionPacket packet ) + { + } + + @Override + public void processUpdateSign( CUpdateSignPacket packet ) + { + } + + @Override + public void processKeepAlive( @Nonnull CKeepAlivePacket packet ) + { + } + + @Override + public void processPlayerAbilities( CPlayerAbilitiesPacket packet ) + { + } + + @Override + public void processClientSettings( @Nonnull CClientSettingsPacket packet ) + { + } + + @Override + public void processCustomPayload( CCustomPayloadPacket packet ) + { + } + + @Override + public void func_217263_a( @Nonnull CSetDifficultyPacket packet ) + { + } + + @Override + public void func_217261_a( @Nonnull CLockDifficultyPacket packet ) + { + } + + private static class FakeNetworkManager extends NetworkManager + { + private INetHandler handler; + private ITextComponent closeReason; + + FakeNetworkManager() + { + super( PacketDirection.CLIENTBOUND ); + } + + @Override + public void channelActive( ChannelHandlerContext context ) + { + } + + @Override + public void setConnectionState( @Nonnull ProtocolType state ) + { + } + + @Override + public void channelInactive( ChannelHandlerContext context ) + { + } + + @Override + public void exceptionCaught( ChannelHandlerContext context, @Nonnull Throwable err ) + { + } + + @Override + protected void channelRead0( ChannelHandlerContext context, @Nonnull IPacket packet ) + { + } + + @Override + public void setNetHandler( INetHandler handler ) + { + this.handler = handler; + } + + @Override + public void sendPacket( @Nonnull IPacket packet ) + { + } + + @Override + public void sendPacket( @Nonnull IPacket packet, @Nullable GenericFutureListener> whenSent ) + { + } + + @Override + public void tick() + { + } + + @Override + public void closeChannel( @Nonnull ITextComponent message ) + { + this.closeReason = message; + } + + @Override + public void enableEncryption( SecretKey key ) + { + } + + @Nonnull + @Override + public INetHandler getNetHandler() + { + return handler; + } + + @Nullable + @Override + public ITextComponent getExitMessage() + { + return closeReason; + } + + @Override + public void disableAutoRead() + { + } + + @Override + public void setCompressionThreshold( int threshold ) + { + } + } +} From 2d4a87adc969d0918047cf1102190cddbe31bc9f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 13:05:26 +0000 Subject: [PATCH 099/711] Fix the eye height for turtle fake players This was causing the eye height of the turtle to be above it when placing down, causing all sorts of funkiness. Fixes #297 --- .../shared/turtle/core/TurtlePlayer.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 9c23e4f14..3715c7be1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -12,9 +12,7 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.util.FakeNetHandler; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityClassification; -import net.minecraft.entity.EntityType; +import net.minecraft.entity.*; import net.minecraft.entity.passive.horse.AbstractHorseEntity; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.INamedContainerProvider; @@ -143,6 +141,19 @@ public final class TurtlePlayer extends FakePlayer return new Vec3d( posX, posY, posZ ); } + + @Override + public float getEyeHeight( @Nonnull Pose pose ) + { + return 0; + } + + @Override + public float getStandingEyeHeight( Pose pose, EntitySize size ) + { + return 0; + } + //region Code which depends on the connection @Nonnull @Override From c4d18aa9ca8942acddf97b7df8b6dace49df7fc9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 13:21:07 +0000 Subject: [PATCH 100/711] Allow navigating `read`'s input using the mouse --- src/main/resources/assets/computercraft/lua/bios.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 417b55bc9..ecef0d2dc 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -326,7 +326,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) nScroll = (sx + nPos) - w end - local cx,cy = term.getCursorPos() + local _, cy = term.getCursorPos() term.setCursorPos( sx, cy ) local sReplace = (_bClear and " ") or _sReplaceChar if sReplace then @@ -523,6 +523,14 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end + elseif sEvent == "mouse_click" or sEvent == "mouse_drag" and param == 1 then + local _, cy = term.getCursorPos() + if param2 >= sx and param2 <= w and param2 == cy then + -- Then ensure we don't scroll beyond the current line + nPos = math.min(math.max(nScroll + x - sx, 0, #sLine)) + redraw() + end + elseif sEvent == "term_resize" then -- Terminal resized w = term.getSize() From 3c8c0d78ef5fbc1aa2c4d524273f677cb210493a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 13:24:36 +0000 Subject: [PATCH 101/711] Use correct render type for turtles This fixes them not rendering particles when broken. Particle rendering is a little janky right now, as it uses the whole texture - we should probably split up the texture into smaller images. Fixes #315 --- .../dan200/computercraft/shared/turtle/blocks/BlockTurtle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 3e7a80698..0e5871515 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -58,7 +58,7 @@ public class BlockTurtle extends BlockComputerBase @Deprecated public EnumBlockRenderType getRenderType( IBlockState state ) { - return EnumBlockRenderType.INVISIBLE; + return EnumBlockRenderType.ENTITYBLOCK_ANIMATED; } @Override From 08cf55e55fbfc9ed80ea0a6c52cf2ef2a8f35518 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 23 Nov 2019 14:36:43 +0000 Subject: [PATCH 102/711] Correct implementation of clamp That's what I get for inlining definitions. --- src/main/resources/assets/computercraft/lua/bios.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index ecef0d2dc..a6071e8c7 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -527,7 +527,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local _, cy = term.getCursorPos() if param2 >= sx and param2 <= w and param2 == cy then -- Then ensure we don't scroll beyond the current line - nPos = math.min(math.max(nScroll + x - sx, 0, #sLine)) + nPos = math.min(math.max(nScroll + x - sx, 0), #sLine) redraw() end From 121802a683fdb3d063581d69ab3d94996afbb247 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 25 Nov 2019 08:58:36 +0000 Subject: [PATCH 103/711] Bump version --- gradle.properties | 2 +- .../assets/computercraft/lua/rom/help/changelog.txt | 7 +++++++ .../assets/computercraft/lua/rom/help/whatsnew.txt | 9 +++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 30e15fd82..44f473b24 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.85.0 +mod_version=1.85.1 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index aa8214920..284d42827 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,10 @@ +# New features in CC: Tweaked 1.85.1 + +* Add basic mouse support to `read` + +And several bug fixes: +* Fix turtles not having breaking particles. + # New features in CC: Tweaked 1.85.0 * Window.reposition now allows changing the redirect buffer diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 53875ec6a..06930d735 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,11 +1,8 @@ -New features in CC: Tweaked 1.85.0 +New features in CC: Tweaked 1.85.1 -* Window.reposition now allows changing the redirect buffer -* Add cc.completion and cc.shell.completion modules -* command.exec also returns the number of affected objects, when exposed by the game. +* Add basic mouse support to `read` And several bug fixes: -* Change how turtle mining drops are handled, improving compatibility with some mods. -* Fix several GUI desyncs after a turtle moves. +* Fix turtles not having breaking particles. Type "help changelog" to see the full version history. From 3b7300543ad0cf270dbd3a2696043140f14b6b2b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 26 Nov 2019 18:16:49 +0000 Subject: [PATCH 104/711] Correctly invalidate the ROM mount cache Before it would remain the same across world reloads, and thus would be out-of-date after leaving the first world. This architecture technically allows for running multiple servers at once, though that's not going to matter that soon. --- .../dan200/computercraft/ComputerCraft.java | 9 ---- .../computercraft/ComputerCraftAPIImpl.java | 14 +++++- .../core/computer/ComputerExecutor.java | 13 +----- .../core/filesystem/ResourceMount.java | 45 +++++++++++++++++-- .../core/filesystem/ResourceMountTest.java | 2 +- 5 files changed, 58 insertions(+), 25 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index a881b4a96..76a64121f 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -6,11 +6,9 @@ package dan200.computercraft; -import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.AddressPredicate; import dan200.computercraft.core.apis.http.websocket.Websocket; -import dan200.computercraft.core.filesystem.ResourceMount; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; @@ -194,13 +192,6 @@ public final class ComputerCraft return "${version}"; } - static IMount createResourceMount( String domain, String subPath ) - { - IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); - ResourceMount mount = new ResourceMount( domain, subPath, manager ); - return mount.exists( "" ) ? mount : null; - } - public static InputStream getResourceFile( String domain, String subPath ) { IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 938c63cd9..5a9f89df4 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -6,6 +6,7 @@ package dan200.computercraft; +import com.google.common.collect.MapMaker; import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -20,20 +21,26 @@ import dan200.computercraft.api.redstone.IBundledRedstoneProvider; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.core.apis.ApiFactories; import dan200.computercraft.core.filesystem.FileMount; +import dan200.computercraft.core.filesystem.ResourceMount; import dan200.computercraft.shared.*; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.util.IDAssigner; import dan200.computercraft.shared.wired.CapabilityWiredElement; import dan200.computercraft.shared.wired.WiredNode; +import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.server.ServerLifecycleHooks; import javax.annotation.Nonnull; import java.io.File; +import java.lang.ref.WeakReference; +import java.util.Map; public final class ComputerCraftAPIImpl implements IComputerCraftAPI { @@ -43,6 +50,9 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { } + private WeakReference currentResources; + private final Map mountCache = new MapMaker().weakValues().concurrencyLevel( 1 ).makeMap(); + @Nonnull @Override public String getInstalledVersion() @@ -72,7 +82,9 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI @Override public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) { - return ComputerCraft.createResourceMount( domain, subPath ); + IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); + ResourceMount mount = ResourceMount.get( domain, subPath, manager ); + return mount.exists( "" ) ? mount : null; } @Override diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index aa621f803..6de516c42 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -56,9 +56,6 @@ final class ComputerExecutor { private static final int QUEUE_LIMIT = 256; - private static IMount romMount; - private static final Object romMountLock = new Object(); - private final Computer computer; private final List apis = new ArrayList<>(); final TimeoutState timeout = new TimeoutState(); @@ -329,16 +326,10 @@ final class ComputerExecutor private IMount getRomMount() { - if( romMount != null ) return romMount; - - synchronized( romMountLock ) - { - if( romMount != null ) return romMount; - return romMount = computer.getComputerEnvironment().createResourceMount( "computercraft", "lua/rom" ); - } + return computer.getComputerEnvironment().createResourceMount( "computercraft", "lua/rom" ); } - IWritableMount getRootMount() + private IWritableMount getRootMount() { if( rootMount == null ) { diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index 81d71f9eb..a7837bef4 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -8,13 +8,16 @@ package dan200.computercraft.core.filesystem; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import com.google.common.collect.MapMaker; import com.google.common.io.ByteStreams; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.core.apis.handles.ArrayByteChannel; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.resources.IResource; import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.ResourceLocationException; import net.minecraftforge.resource.IResourceType; import net.minecraftforge.resource.ISelectiveResourceReloadListener; @@ -29,7 +32,7 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; -public class ResourceMount implements IMount +public final class ResourceMount implements IMount { /** * Only cache files smaller than 1MiB. @@ -55,6 +58,13 @@ public class ResourceMount implements IMount .weigher( ( k, v ) -> v.length ) .build(); + private static final MapMaker CACHE_TEMPLATE = new MapMaker().weakValues().concurrencyLevel( 1 ); + + /** + * Maintain a cache of currently loaded resource mounts. This cache is invalidated when currentManager changes. + */ + private static final Map> MOUNT_CACHE = new WeakHashMap<>( 2 ); + private final String namespace; private final String subPath; private final IReloadableResourceManager manager; @@ -62,7 +72,26 @@ public class ResourceMount implements IMount @Nullable private FileEntry root; - public ResourceMount( String namespace, String subPath, IReloadableResourceManager manager ) + public static ResourceMount get( String namespace, String subPath, IReloadableResourceManager manager ) + { + Map cache; + + synchronized( MOUNT_CACHE ) + { + cache = MOUNT_CACHE.get( manager ); + if( cache == null ) MOUNT_CACHE.put( manager, cache = CACHE_TEMPLATE.makeMap() ); + } + + ResourceLocation path = new ResourceLocation( namespace, subPath ); + synchronized( cache ) + { + ResourceMount mount = cache.get( path ); + if( mount == null ) cache.put( path, mount = new ResourceMount( namespace, subPath, manager ) ); + return mount; + } + } + + private ResourceMount( String namespace, String subPath, IReloadableResourceManager manager ) { this.namespace = namespace; this.subPath = subPath; @@ -119,7 +148,17 @@ public class ResourceMount implements IMount FileEntry nextEntry = lastEntry.children.get( part ); if( nextEntry == null ) { - lastEntry.children.put( part, nextEntry = new FileEntry( new ResourceLocation( namespace, subPath + "/" + path ) ) ); + ResourceLocation childPath; + try + { + childPath = new ResourceLocation( namespace, subPath + "/" + path ); + } + catch( ResourceLocationException e ) + { + ComputerCraft.log.warn( "Cannot create resource location for {} ({})", part, e.getMessage() ); + return; + } + lastEntry.children.put( part, nextEntry = new FileEntry( childPath ) ); } lastEntry = nextEntry; diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java index 4b2bb0a14..f46e50fdb 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -31,7 +31,7 @@ public class ResourceMountTest SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA, null ); manager.addResourcePack( new FolderPack( new File( "src/main/resources" ) ) ); - mount = new ResourceMount( "computercraft", "lua/rom", manager ); + mount = ResourceMount.get( "computercraft", "lua/rom", manager ); } @Test From 0ae70fed13a7be95ff6ca29b8117987bfbb6fe82 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 29 Nov 2019 20:15:58 +0000 Subject: [PATCH 105/711] Correctly implement mouse movement within read Note to self: if you're going to modify the rom, make sure you test on a computer which doesn't overwrite the rom with something else. --- gradle.properties | 2 +- .../assets/computercraft/lua/bios.lua | 41 +++++++++++-------- .../computercraft/lua/rom/help/changelog.txt | 4 ++ .../computercraft/lua/rom/help/whatsnew.txt | 7 +--- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/gradle.properties b/gradle.properties index 44f473b24..d3002e82e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.85.1 +mod_version=1.85.2 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index a6071e8c7..cebfe1fa3 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -291,7 +291,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) sLine = "" end local nHistoryPos - local nPos = #sLine + local nPos, nScroll = #sLine, 0 if _sReplaceChar then _sReplaceChar = string.sub( _sReplaceChar, 1, 1 ) end @@ -321,16 +321,20 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local sx = term.getCursorPos() local function redraw( _bClear ) - local nScroll = 0 - if sx + nPos >= w then - nScroll = (sx + nPos) - w + local cursor_pos = nPos - nScroll + if sx + cursor_pos >= w then + -- We've moved beyond the RHS, ensure we're on the edge. + nScroll = sx + nPos - w + elseif cursor_pos < 0 then + -- We've moved beyond the LHS, ensure we're on the edge. + nScroll = nPos end local _, cy = term.getCursorPos() term.setCursorPos( sx, cy ) local sReplace = (_bClear and " ") or _sReplaceChar if sReplace then - term.write( string.rep( sReplace, math.max( string.len(sLine) - nScroll, 0 ) ) ) + term.write( string.rep( sReplace, math.max( #sLine - nScroll, 0 ) ) ) else term.write( string.sub( sLine, nScroll + 1 ) ) end @@ -345,7 +349,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) term.setBackgroundColor( colors.gray ) end if sReplace then - term.write( string.rep( sReplace, string.len( sCompletion ) ) ) + term.write( string.rep( sReplace, #sCompletion ) ) else term.write( sCompletion ) end @@ -373,7 +377,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) -- Find the common prefix of all the other suggestions which start with the same letter as the current one local sCompletion = tCompletions[ nCompletion ] sLine = sLine .. sCompletion - nPos = string.len( sLine ) + nPos = #sLine -- Redraw recomplete() @@ -381,7 +385,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end end while true do - local sEvent, param = os.pullEvent() + local sEvent, param, param1, param2 = os.pullEvent() if sEvent == "char" then -- Typed key clear() @@ -394,7 +398,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) -- Pasted text clear() sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) - nPos = nPos + string.len( param ) + nPos = nPos + #param recomplete() redraw() @@ -419,7 +423,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) elseif param == keys.right then -- Right - if nPos < string.len(sLine) then + if nPos < #sLine then -- Move right clear() nPos = nPos + 1 @@ -470,10 +474,10 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end if nHistoryPos then sLine = _tHistory[nHistoryPos] - nPos = string.len( sLine ) + nPos, nScroll = #sLine, 0 else sLine = "" - nPos = 0 + nPos, nScroll = 0, 0 end uncomplete() redraw() @@ -486,6 +490,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) clear() sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 ) nPos = nPos - 1 + if nScroll > 0 then nScroll = nScroll - 1 end recomplete() redraw() end @@ -501,7 +506,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) elseif param == keys.delete then -- Delete - if nPos < string.len(sLine) then + if nPos < #sLine then clear() sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 ) recomplete() @@ -510,9 +515,9 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) elseif param == keys["end"] then -- End - if nPos < string.len(sLine ) then + if nPos < #sLine then clear() - nPos = string.len(sLine) + nPos = #sLine recomplete() redraw() end @@ -525,9 +530,9 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) elseif sEvent == "mouse_click" or sEvent == "mouse_drag" and param == 1 then local _, cy = term.getCursorPos() - if param2 >= sx and param2 <= w and param2 == cy then - -- Then ensure we don't scroll beyond the current line - nPos = math.min(math.max(nScroll + x - sx, 0), #sLine) + if param1 >= sx and param1 <= w and param2 == cy then + -- Ensure we don't scroll beyond the current line + nPos = math.min(math.max(nScroll + param1 - sx, 0), #sLine) redraw() end diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 284d42827..99140820e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.85.2 + +* Fix crashes when using the mouse with advanced computers. + # New features in CC: Tweaked 1.85.1 * Add basic mouse support to `read` diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 06930d735..b1a6d0cff 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,8 +1,5 @@ -New features in CC: Tweaked 1.85.1 +New features in CC: Tweaked 1.85.2 -* Add basic mouse support to `read` - -And several bug fixes: -* Fix turtles not having breaking particles. +* Fix crashes when using the mouse with advanced computers. Type "help changelog" to see the full version history. From 86e0330100ca34692a06f04a743970a9a062db1f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 3 Dec 2019 23:26:13 +0000 Subject: [PATCH 106/711] Lint bios and the rom (#321) We now use illuaminate[1]'s linting facilities to check the rom and bios.lua for a couple of common bugs and other problems. Right now this doesn't detect any especially important bugs, though it has caught lots of small things (unused variables, some noisy code). In the future, the linter will grow in scope and features, which should allow us to be stricter and catch most issues. As a fun aside, we started off with ~150 bugs, and illuaminate was able to fix all but 30 of them, which is pretty neat. [1]: https://github.com/SquidDev/illuaminate --- .editorconfig | 3 ++ .github/workflows/main-ci.yml | 15 +++++++++ illuaminate.sexp | 25 +++++++++++++++ .../assets/computercraft/lua/bios.lua | 26 ++++++++-------- .../lua/rom/apis/command/commands.lua | 4 +-- .../computercraft/lua/rom/apis/disk.lua | 2 +- .../assets/computercraft/lua/rom/apis/gps.lua | 10 +++--- .../computercraft/lua/rom/apis/help.lua | 4 +-- .../computercraft/lua/rom/apis/paintutils.lua | 4 +-- .../computercraft/lua/rom/apis/peripheral.lua | 16 +++++----- .../computercraft/lua/rom/apis/rednet.lua | 10 +++--- .../computercraft/lua/rom/apis/settings.lua | 2 +- .../computercraft/lua/rom/apis/term.lua | 2 +- .../computercraft/lua/rom/apis/textutils.lua | 16 +++++----- .../computercraft/lua/rom/apis/vector.lua | 6 ++-- .../computercraft/lua/rom/apis/window.lua | 2 +- .../lua/rom/programs/advanced/multishell.lua | 7 ++--- .../computercraft/lua/rom/programs/copy.lua | 2 +- .../computercraft/lua/rom/programs/delete.lua | 2 +- .../computercraft/lua/rom/programs/drive.lua | 4 +-- .../computercraft/lua/rom/programs/edit.lua | 11 +++---- .../lua/rom/programs/fun/advanced/paint.lua | 6 ++-- .../rom/programs/fun/advanced/redirection.lua | 10 +++--- .../lua/rom/programs/fun/adventure.lua | 31 +++++++++---------- .../computercraft/lua/rom/programs/fun/dj.lua | 2 +- .../lua/rom/programs/fun/worm.lua | 11 ++----- .../computercraft/lua/rom/programs/gps.lua | 4 +-- .../computercraft/lua/rom/programs/help.lua | 2 +- .../computercraft/lua/rom/programs/list.lua | 2 +- .../computercraft/lua/rom/programs/lua.lua | 4 +-- .../computercraft/lua/rom/programs/move.lua | 2 +- .../lua/rom/programs/pocket/falling.lua | 11 +++---- .../lua/rom/programs/rednet/chat.lua | 15 +++++---- .../lua/rom/programs/rednet/repeat.lua | 4 +-- .../lua/rom/programs/redstone.lua | 6 ++-- .../computercraft/lua/rom/programs/set.lua | 2 +- .../computercraft/lua/rom/programs/shell.lua | 12 +++---- .../lua/rom/programs/turtle/dance.lua | 4 +-- .../lua/rom/programs/turtle/excavate.lua | 9 +++--- .../lua/rom/programs/turtle/refuel.lua | 2 +- .../lua/rom/programs/turtle/tunnel.lua | 2 -- .../lua/rom/programs/turtle/turn.lua | 2 +- .../assets/computercraft/lua/rom/startup.lua | 2 +- 43 files changed, 173 insertions(+), 145 deletions(-) create mode 100644 illuaminate.sexp diff --git a/.editorconfig b/.editorconfig index f04c87852..f11468850 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,5 +11,8 @@ insert_final_newline = true [*.md] trim_trailing_whitespace = false +[*.sexp] +indent_size = 2 + [*.properties] insert_final_newline = false diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 16f34b3e2..0be633a53 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -4,6 +4,7 @@ on: [push, pull_request] jobs: build: + name: Build runs-on: ubuntu-latest steps: @@ -16,3 +17,17 @@ jobs: - name: Build with Gradle run: ./gradlew build --no-daemon + + lint-lua: + name: Lint Lua + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Lint Lua code + run: | + test -d bin || mkdir bin + test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/bin/illuaminate + chmod +x bin/illuaminate + GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} bin/illuaminate lint --github diff --git a/illuaminate.sexp b/illuaminate.sexp new file mode 100644 index 000000000..2271a01e5 --- /dev/null +++ b/illuaminate.sexp @@ -0,0 +1,25 @@ +; -*- mode: Lisp;-*- + +(sources + /src/main/resources/assets/computercraft/lua/bios.lua + /src/main/resources/assets/computercraft/lua/rom/) + +(at / + (linters + ;; It'd be nice to avoid this, but right now there's a lot of instances of it. + -var:set-loop + + ;; It's useful to name arguments for documentation, so we allow this. It'd + ;; be good to find a compromise in the future, but this works for now. + -var:unused-arg)) + +;; We disable the two global linters in bios.lua and the APIs. In the future +;; hopefully we'll get illuaminate to handle this. +(at + (/src/main/resources/assets/computercraft/lua/bios.lua + /src/main/resources/assets/computercraft/lua/rom/apis/) + (linters -var:set-global -var:unused-global)) + +;; These warnings are broken right now +(at completion.lua (linters -doc:malformed-type)) +(at (bios.lua worm.lua) (linters -control:unreachable)) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index cebfe1fa3..e4b792538 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -184,7 +184,7 @@ function sleep( nTime ) expect(1, nTime, "number", "nil") local timer = os.startTimer( nTime or 0 ) repeat - local sEvent, param = os.pullEvent( "timer" ) + local _, param = os.pullEvent( "timer" ) until param == timer end @@ -233,7 +233,7 @@ function write( sText ) newLine() end term.write( text ) - text = string.sub( text, (w-x) + 2 ) + text = string.sub( text, w-x + 2 ) x,y = term.getCursorPos() end else @@ -332,7 +332,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local _, cy = term.getCursorPos() term.setCursorPos( sx, cy ) - local sReplace = (_bClear and " ") or _sReplaceChar + local sReplace = _bClear and " " or _sReplaceChar if sReplace then term.write( string.rep( sReplace, math.max( #sLine - nScroll, 0 ) ) ) else @@ -544,7 +544,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end end - local cx, cy = term.getCursorPos() + local _, cy = term.getCursorPos() term.setCursorBlink( false ) term.setCursorPos( w + 1, cy ) print() @@ -775,7 +775,7 @@ if http then if not ok then return ok, err end while true do - local event, url, ok, err = os.pullEvent( "http_check" ) + local _, url, ok, err = os.pullEvent( "http_check" ) if url == _url then return ok, err end end end @@ -808,8 +808,8 @@ function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) expect(3, bIncludeFiles, "boolean", "nil") expect(4, bIncludeDirs, "boolean", "nil") - bIncludeFiles = (bIncludeFiles ~= false) - bIncludeDirs = (bIncludeDirs ~= false) + bIncludeFiles = bIncludeFiles ~= false + bIncludeDirs = bIncludeDirs ~= false local sDir = sLocation local nStart = 1 local nSlash = string.find( sPath, "[/\\]", nStart ) @@ -836,9 +836,9 @@ function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) end if sDir ~= "" then if sPath == "" then - table.insert( tResults, (bIncludeDirs and "..") or "../" ) + table.insert( tResults, bIncludeDirs and ".." or "../" ) elseif sPath == "." then - table.insert( tResults, (bIncludeDirs and ".") or "./" ) + table.insert( tResults, bIncludeDirs and "." or "./" ) end end local tFiles = fs.list( sDir ) @@ -867,7 +867,7 @@ end -- Load APIs local bAPIError = false local tApis = fs.list( "rom/apis" ) -for n,sFile in ipairs( tApis ) do +for _,sFile in ipairs( tApis ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = fs.combine( "rom/apis", sFile ) if not fs.isDir( sPath ) then @@ -881,7 +881,7 @@ end if turtle and fs.isDir( "rom/apis/turtle" ) then -- Load turtle APIs local tApis = fs.list( "rom/apis/turtle" ) - for n,sFile in ipairs( tApis ) do + for _,sFile in ipairs( tApis ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = fs.combine( "rom/apis/turtle", sFile ) if not fs.isDir( sPath ) then @@ -896,7 +896,7 @@ end if pocket and fs.isDir( "rom/apis/pocket" ) then -- Load pocket APIs local tApis = fs.list( "rom/apis/pocket" ) - for n,sFile in ipairs( tApis ) do + for _,sFile in ipairs( tApis ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = fs.combine( "rom/apis/pocket", sFile ) if not fs.isDir( sPath ) then @@ -946,7 +946,7 @@ end -- Set default settings settings.set( "shell.allow_startup", true ) -settings.set( "shell.allow_disk_startup", (commands == nil) ) +settings.set( "shell.allow_disk_startup", commands == nil ) settings.set( "shell.autocomplete", true ) settings.set( "edit.autocomplete", true ) settings.set( "edit.default_extension", "lua" ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua index 849bf8e7c..7afd34bad 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua @@ -33,9 +33,9 @@ local tNonNBTJSONCommands = { [ "title" ] = true } local tCommands = native.list() -for n,sCommandName in ipairs(tCommands) do +for _,sCommandName in ipairs(tCommands) do if env[ sCommandName ] == nil then - local bJSONIsNBT = (tNonNBTJSONCommands[ sCommandName ] == nil) + local bJSONIsNBT = tNonNBTJSONCommands[ sCommandName ] == nil env[ sCommandName ] = function( ... ) local sCommand = collapseArgs( bJSONIsNBT, sCommandName, ... ) return native.exec( sCommand ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua index 637a48b07..2c5e6ec8b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua @@ -62,7 +62,7 @@ end function stopAudio( name ) if not name then - for n,sName in ipairs( peripheral.getNames() ) do + for _,sName in ipairs( peripheral.getNames() ) do stopAudio( sName ) end else diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index 08f698eb2..aab023209 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -13,7 +13,7 @@ local function trilaterate( A, B, C ) local d = a2b:length() local ex = a2b:normalize( ) local i = ex:dot( a2c ) - local ey = (a2c - (ex * i)):normalize() + local ey = (a2c - ex * i):normalize() local j = ey:dot( a2c ) local ez = ex:cross( ey ) @@ -24,13 +24,13 @@ local function trilaterate( A, B, C ) local x = (r1*r1 - r2*r2 + d*d) / (2*d) local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j) - local result = A.vPosition + (ex * x) + (ey * y) + local result = A.vPosition + ex * x + ey * y local zSquared = r1*r1 - x*x - y*y if zSquared > 0 then local z = math.sqrt( zSquared ) - local result1 = result + (ez * z) - local result2 = result - (ez * z) + local result1 = result + ez * z + local result2 = result - ez * z local rounded1, rounded2 = result1:round( 0.01 ), result2:round( 0.01 ) if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then @@ -66,7 +66,7 @@ function locate( _nTimeout, _bDebug ) -- Find a modem local sModemSide = nil - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then sModemSide = sSide break diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index b4e69921f..853ec09a0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -37,7 +37,7 @@ function topics() for sPath in string.gmatch(sPath, "[^:]+") do if fs.isDir( sPath ) then local tList = fs.list( sPath ) - for n,sFile in pairs( tList ) do + for _,sFile in pairs( tList ) do if string.sub( sFile, 1, 1 ) ~= "." then if not fs.isDir( fs.combine( sPath, sFile ) ) then if #sFile > 4 and sFile:sub(-4) == ".txt" then @@ -52,7 +52,7 @@ function topics() -- Sort and return local tItemList = {} - for sItem, b in pairs( tItems ) do + for sItem in pairs( tItems ) do table.insert( tItemList, sItem ) end table.sort( tItemList ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index 0988945e0..5420b029d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -147,8 +147,8 @@ function drawBox( startX, startY, endX, endY, nColour ) drawPixelInternal( x, maxY ) end - if (maxY - minY) >= 2 then - for y=(minY+1),(maxY-1) do + if maxY - minY >= 2 then + for y=minY+1,maxY-1 do drawPixelInternal( minX, y ) drawPixelInternal( maxX, y ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index 3f4fdc150..ecfccbb53 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -4,12 +4,12 @@ local native = peripheral function getNames() local tResults = {} - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if native.isPresent( sSide ) then table.insert( tResults, sSide ) if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then local tRemote = native.call( sSide, "getNamesRemote" ) - for n,sName in ipairs( tRemote ) do + for _,sName in ipairs( tRemote ) do table.insert( tResults, sName ) end end @@ -23,7 +23,7 @@ function isPresent( _sSide ) if native.isPresent( _sSide ) then return true end - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return true @@ -38,7 +38,7 @@ function getType( _sSide ) if native.isPresent( _sSide ) then return native.getType( _sSide ) end - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return native.call( sSide, "getTypeRemote", _sSide ) @@ -53,7 +53,7 @@ function getMethods( _sSide ) if native.isPresent( _sSide ) then return native.getMethods( _sSide ) end - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return native.call( sSide, "getMethodsRemote", _sSide ) @@ -69,7 +69,7 @@ function call( _sSide, _sMethod, ... ) if native.isPresent( _sSide ) then return native.call( _sSide, _sMethod, ... ) end - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return native.call( sSide, "callRemote", _sSide, _sMethod, ... ) @@ -84,7 +84,7 @@ function wrap( _sSide ) if peripheral.isPresent( _sSide ) then local tMethods = peripheral.getMethods( _sSide ) local tResult = {} - for n,sMethod in ipairs( tMethods ) do + for _,sMethod in ipairs( tMethods ) do tResult[sMethod] = function( ... ) return peripheral.call( _sSide, sMethod, ... ) end @@ -98,7 +98,7 @@ function find( sType, fnFilter ) expect(1, sType, "string") expect(2, fnFilter, "function", "nil") local tResults = {} - for n,sName in ipairs( peripheral.getNames() ) do + for _,sName in ipairs( peripheral.getNames() ) do if peripheral.getType( sName ) == sType then local wrapped = peripheral.wrap( sName ) if fnFilter == nil or fnFilter( sName, wrapped ) then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index 5af3a4706..e38084ad5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -27,7 +27,7 @@ function close( sModem ) peripheral.call( sModem, "close", CHANNEL_BROADCAST ) else -- Close all modems - for n,sModem in ipairs( peripheral.getNames() ) do + for _,sModem in ipairs( peripheral.getNames() ) do if isOpen( sModem ) then close( sModem ) end @@ -44,7 +44,7 @@ function isOpen( sModem ) end else -- Check if any modem is open - for n,sModem in ipairs( peripheral.getNames() ) do + for _,sModem in ipairs( peripheral.getNames() ) do if isOpen( sModem ) then return true end @@ -79,10 +79,10 @@ function send( nRecipient, message, sProtocol ) sent = true else -- Send on all open modems, to the target and to repeaters - for n,sModem in ipairs( peripheral.getNames() ) do + for _,sModem in ipairs( peripheral.getNames() ) do if isOpen( sModem ) then - peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage ); - peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage ); + peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage ) + peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage ) sent = true end end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index d60510937..9f9ba9822 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -47,7 +47,7 @@ end function getNames() local result = {} - for k,v in pairs( tSettings ) do + for k in pairs( tSettings ) do result[ #result + 1 ] = k end table.sort(result) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index e9ad00408..98db90be7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -1,6 +1,6 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect -local native = (term.native and term.native()) or term +local native = term.native and term.native() or term local redirectTarget = native local function wrap( _sFunction ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 447babb44..09130fbad 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -16,7 +16,7 @@ function slowWrite( sText, nRate ) term.setCursorPos( x, y ) sleep( nSleep ) local nLines = write( string.sub( sText, 1, n ) ) - local newX, newY = term.getCursorPos() + local _, newY = term.getCursorPos() y = newY - nLines end end @@ -54,11 +54,11 @@ local function makePagedScroll( _term, _nFreeLines ) local nativeScroll = _term.scroll local nFreeLines = _nFreeLines or 0 return function( _n ) - for n=1,_n do + for _=1,_n do nativeScroll( 1 ) if nFreeLines <= 0 then - local w,h = _term.getSize() + local _,h = _term.getSize() _term.setCursorPos( 1, h ) _term.write( "Press any key to continue" ) os.pullEvent( "key" ) @@ -123,7 +123,7 @@ local function tabulateCommon( bPaged, ... ) local nCols = math.floor( w / nMaxLen ) local nLines = 0 local function newLine() - if bPaged and nLines >= (h-3) then + if bPaged and nLines >= h-3 then pagedPrint() else print() @@ -133,14 +133,14 @@ local function tabulateCommon( bPaged, ... ) local function drawCols( _t ) local nCol = 1 - for n, s in ipairs( _t ) do + for _, s in ipairs( _t ) do if nCol > nCols then nCol = 1 newLine() end local cx, cy = term.getCursorPos() - cx = 1 + ((nCol - 1) * nMaxLen) + cx = 1 + (nCol - 1) * nMaxLen term.setCursorPos( cx, cy ) term.write( s ) @@ -148,7 +148,7 @@ local function tabulateCommon( bPaged, ... ) end print() end - for n, t in ipairs( tAll ) do + for _, t in ipairs( tAll ) do if type(t) == "table" then if #t > 0 then drawCols( t ) @@ -280,7 +280,7 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) nObjectSize = nObjectSize + 1 end end - for n,v in ipairs(t) do + for _,v in ipairs(t) do local sEntry = serializeJSONImpl( v, tTracking, bNBTStyle ) if nArraySize == 0 then sArrayResult = sArrayResult .. sEntry diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua index 2fd2fbdb6..7a6db14b7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua @@ -54,9 +54,9 @@ local vector = { round = function( self, nTolerance ) nTolerance = nTolerance or 1.0 return vector.new( - math.floor( (self.x + (nTolerance * 0.5)) / nTolerance ) * nTolerance, - math.floor( (self.y + (nTolerance * 0.5)) / nTolerance ) * nTolerance, - math.floor( (self.z + (nTolerance * 0.5)) / nTolerance ) * nTolerance + math.floor( (self.x + nTolerance * 0.5) / nTolerance ) * nTolerance, + math.floor( (self.y + nTolerance * 0.5) / nTolerance ) * nTolerance, + math.floor( (self.z + nTolerance * 0.5) / nTolerance ) * nTolerance ) end, tostring = function( self ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 87ede5cbd..2f20220fc 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -49,7 +49,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) createEmptyLines( nWidth ) -- Setup - local bVisible = (bStartVisible ~= false) + local bVisible = bStartVisible ~= false local nCursorX = 1 local nCursorY = 1 local bCursorBlink = false diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index 51c1c1753..b07cccf3c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -172,7 +172,6 @@ local function resizeWindows() end for n=1,#tProcesses do local tProcess = tProcesses[n] - local window = tProcess.window local x,y = tProcess.window.getCursorPos() if y > windowHeight then tProcess.window.scroll( y - windowHeight ) @@ -232,7 +231,7 @@ function multishell.launch( tProgramEnv, sProgramPath, ... ) expect(1, tProgramEnv, "table") expect(2, sProgramPath, "string") local previousTerm = term.current() - setMenuVisible( (#tProcesses + 1) >= 2 ) + setMenuVisible( #tProcesses + 1 >= 2 ) local nResult = launchProcess( false, tProgramEnv, sProgramPath, ... ) redrawMenu() term.redirect( previousTerm ) @@ -299,7 +298,7 @@ while #tProcesses > 0 do end else -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, button, x, (bShowMenu and y-1) or y ) + resumeProcess( nCurrentProcess, sEvent, button, x, bShowMenu and y-1 or y ) if cullProcess( nCurrentProcess ) then setMenuVisible( #tProcesses >= 2 ) redrawMenu() @@ -319,7 +318,7 @@ while #tProcesses > 0 do end elseif not (bShowMenu and y == 1) then -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, p1, x, (bShowMenu and y-1) or y ) + resumeProcess( nCurrentProcess, sEvent, p1, x, bShowMenu and y-1 or y ) if cullProcess( nCurrentProcess ) then setMenuVisible( #tProcesses >= 2 ) redrawMenu() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua index 70cde52a1..71ea68043 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua @@ -9,7 +9,7 @@ local sSource = shell.resolve( tArgs[1] ) local sDest = shell.resolve( tArgs[2] ) local tFiles = fs.find( sSource ) if #tFiles > 0 then - for n,sFile in ipairs( tFiles ) do + for _,sFile in ipairs( tFiles ) do if fs.isDir( sDest ) then fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) ) elseif #tFiles == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua b/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua index e2d296805..91f2e0c23 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua @@ -8,7 +8,7 @@ end for i = 1, args.n do local files = fs.find(shell.resolve(args[i])) if #files > 0 then - for n, file in ipairs(files) do + for _, file in ipairs(files) do local ok, err = pcall(fs.delete, file) if not ok then printError((err:gsub("^pcall: ", ""))) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua b/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua index c1a38e6dd..807cf88b4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua @@ -10,9 +10,9 @@ if fs.exists( sPath ) then write( fs.getDrive( sPath ) .. " (" ) local nSpace = fs.getFreeSpace( sPath ) if nSpace >= 1000 * 1000 then - print( (math.floor( nSpace / (100 * 1000) ) / 10) .. "MB remaining)" ) + print( math.floor( nSpace / (100 * 1000) ) / 10 .. "MB remaining)" ) elseif nSpace >= 1000 then - print( (math.floor( nSpace / 100 ) / 10) .. "KB remaining)" ) + print( math.floor( nSpace / 100 ) / 10 .. "KB remaining)" ) else print( nSpace .. "B remaining)" ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index e481dd9cd..2d7d9357e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -95,7 +95,7 @@ local function save( _sPath ) local function innerSave() file, fileerr = fs.open( _sPath, "w" ) if file then - for n, sLine in ipairs( tLines ) do + for _, sLine in ipairs( tLines ) do file.write( sLine .. "\n" ) end else @@ -287,7 +287,7 @@ local tMenuFuncs = { if bReadOnly then sStatus = "Access denied" else - local ok, err, fileerr = save( sPath ) + local ok, _, fileerr = save( sPath ) if ok then sStatus="Saved to "..sPath else @@ -357,7 +357,7 @@ local tMenuFuncs = { term.redirect( printerTerminal ) local ok, error = pcall( function() term.scroll() - for n, sLine in ipairs( tLines ) do + for _, sLine in ipairs( tLines ) do print( sLine ) end end ) @@ -385,7 +385,7 @@ local tMenuFuncs = { end, Run = function() local sTempPath = "/.temp" - local ok, err = save( sTempPath ) + local ok = save( sTempPath ) if ok then local nTask = shell.openTab( sTempPath ) if nTask then @@ -411,7 +411,7 @@ local function doMenuItem( _n ) end local function setCursor( newX, newY ) - local oldX, oldY = x, y + local _, oldY = x, y x, y = newX, newY local screenX = x - scrollX local screenY = y - scrollY @@ -476,7 +476,6 @@ end while bRunning do local sEvent, param, param2, param3 = os.pullEvent() if sEvent == "key" then - local oldX, oldY = x, y if param == keys.up then -- Up if not bMenu then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index bd0bb12b4..5011458ca 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -186,8 +186,8 @@ local function drawInterface() term.write("\127\127") -- Left and Right Selected Colours - for i=18,18 do - term.setCursorPos(w-1, i) + do + term.setCursorPos(w-1, 18) if leftColour ~= nil then term.setBackgroundColour( leftColour ) term.write(" ") @@ -269,7 +269,7 @@ local function accessMenu() for k,v in pairs(mChoices) do if selection==k then term.setTextColour(colours.yellow) - local ox,_ = term.getCursorPos() + local ox = term.getCursorPos() term.write("["..string.rep(" ",#v).."]") term.setCursorPos(ox+1,h) term.setTextColour(colours.white) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua index d58bb0a4a..232f6d863 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua @@ -66,8 +66,8 @@ local function printCentred( yc, stg ) end local function centerOrgin() - XOrgin = math.floor((TermW/2)-(SizeW/2)) - YOrgin = math.floor((TermH/2)-(SizeH/2)) + XOrgin = math.floor(TermW/2-SizeW/2) + YOrgin = math.floor(TermH/2-SizeH/2) end local function reMap() @@ -177,7 +177,6 @@ local function loadLevel(nNum) local sLevelD = sDir .. "/levels/" .. tostring(nNum)..".dat" if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error("Level Not Exists : "..sLevelD) end fLevel = fs.open(sLevelD,"r") - local Line = 0 local wl = true Blocks = tonumber(string.sub(fLevel.readLine(),1,1)) local xSize = string.len(fLevel.readLine())+2 @@ -557,7 +556,7 @@ function InterFace.render() elseif p3 == TermH and p2 >= TermW-4 and p2 <= TermW-3 then bPaused = not bPaused fSpeedS = false - Speed = (bPaused and 0) or nSpeed + Speed = bPaused and 0 or nSpeed if Speed > 0 then Tick = os.startTimer(Speed) else @@ -567,7 +566,7 @@ function InterFace.render() elseif p3 == TermH and p2 >= TermW-1 then bPaused = false fSpeedS = not fSpeedS - Speed = (fSpeedS and fSpeed) or nSpeed + Speed = fSpeedS and fSpeed or nSpeed Tick = os.startTimer(Speed) InterFace.drawBar() elseif p3-1 < YOrgin+SizeH+1 and p3-1 > YOrgin and @@ -596,7 +595,6 @@ local function startG(LevelN) drawStars() loadLevel(LevelN) centerOrgin() - local create = true drawMap() InterFace.drawBar() gRender("start") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua index 61f373e8e..eef035301 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua @@ -342,7 +342,7 @@ local function getTimeOfDay() end local function isSunny() - return (getTimeOfDay() < 10) + return getTimeOfDay() < 10 end local function getRoom( x, y, z, dontCreate ) @@ -365,7 +365,7 @@ local function getRoom( x, y, z, dontCreate ) -- Add animals if math.random(1,3) == 1 then - for n = 1,math.random(1,2) do + for _ = 1,math.random(1,2) do local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ] room.items[ sAnimal ] = items[ sAnimal ] end @@ -478,7 +478,7 @@ local function findItem( _tList, _sQuery ) return sItem end if tItem.aliases ~= nil then - for n, sAlias in pairs( tItem.aliases ) do + for _, sAlias in pairs( tItem.aliases ) do if sAlias == _sQuery then return sItem end @@ -613,7 +613,7 @@ local function doCommand( text ) end for sCommand, t in pairs( tMatches ) do - for n, sMatch in pairs( t ) do + for _, sMatch in pairs( t ) do local tCaptures = { string.match( text, "^" .. sMatch .. "$" ) } if #tCaptures ~= 0 then local fnCommand = commands[ sCommand ] @@ -679,7 +679,7 @@ function commands.look( _sTarget ) end if tItem then - print( tItem.desc or ("You see nothing special about "..sItem..".") ) + print( tItem.desc or "You see nothing special about "..sItem.."." ) else print( "You don't see any ".._sTarget.." here." ) end @@ -752,7 +752,7 @@ function commands.dig( _sDir, _sTool ) tTool = inventory[ sTool ] end - local bActuallyDigging = (room.exits[ _sDir ] ~= true) + local bActuallyDigging = room.exits[ _sDir ] ~= true if bActuallyDigging then if sTool == nil or tTool.toolType ~= "pick" then print( "You need to use a pickaxe to dig through stone." ) @@ -1021,7 +1021,7 @@ function commands.cbreak( _sItem, _sTool ) print( "The "..tItem.aliases[1].." dies." ) if tItem.drops then - for n, sDrop in pairs( tItem.drops ) do + for _, sDrop in pairs( tItem.drops ) do if not room.items[sDrop] then print( "The "..tItem.aliases[1].." dropped "..sDrop.."." ) room.items[sDrop] = items[sDrop] @@ -1037,7 +1037,7 @@ function commands.cbreak( _sItem, _sTool ) end if tItem.hitDrops then - for n, sDrop in pairs( tItem.hitDrops ) do + for _, sDrop in pairs( tItem.hitDrops ) do if not room.items[sDrop] then print( "The "..tItem.aliases[1].." dropped "..sDrop.."." ) room.items[sDrop] = items[sDrop] @@ -1071,18 +1071,17 @@ function commands.craft( _sItem ) return end - local room = getRoom( x,y,z ) local sItem = findItem( items, _sItem ) - local tRecipe = (sItem and tRecipes[ sItem ]) or nil + local tRecipe = sItem and tRecipes[ sItem ] or nil if tRecipe then - for n,sReq in ipairs( tRecipe ) do + for _,sReq in ipairs( tRecipe ) do if inventory[sReq] == nil then print( "You don't have the items you need to craft "..sItem.."." ) return end end - for n,sReq in ipairs( tRecipe ) do + for _,sReq in ipairs( tRecipe ) do inventory[sReq] = nil end inventory[ sItem ] = items[ sItem ] @@ -1223,7 +1222,7 @@ local function simulate() -- Spawn monsters if room.nMonsters < 2 and - ((h == 0 and not isSunny() and not room.items["a torch"]) or room.dark) and + (h == 0 and not isSunny() and not room.items["a torch"] or room.dark) and math.random(1,6) == 1 then local sMonster = tMonsters[ math.random(1,#tMonsters) ] @@ -1240,7 +1239,7 @@ local function simulate() -- Burn monsters if h == 0 and isSunny() then - for n,sMonster in ipairs( tMonsters ) do + for _,sMonster in ipairs( tMonsters ) do if room.items[sMonster] and items[sMonster].nocturnal then room.items[sMonster] = nil if sx == 0 and sy == 0 and sz == 0 and not room.dark then @@ -1258,10 +1257,10 @@ local function simulate() -- Make monsters attack local room = getRoom( x, y, z ) if nTimeInRoom >= 2 and not bNewMonstersThisRoom then - for n,sMonster in ipairs( tMonsters ) do + for _,sMonster in ipairs( tMonsters ) do if room.items[sMonster] then if math.random(1,4) == 1 and - not (y == 0 and isSunny() and (sMonster == "a spider")) then + not (y == 0 and isSunny() and sMonster == "a spider") then if sMonster == "a creeper" then if room.dark then print( "A creeper explodes." ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua index 4cc98a3ef..81775248b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua @@ -23,7 +23,7 @@ elseif sCommand == "play" or sCommand == nil then if sName == nil then -- No disc specified, pick one at random local tNames = {} - for n,sName in ipairs( peripheral.getNames() ) do + for _,sName in ipairs( peripheral.getNames() ) do if disk.isPresent( sName ) and disk.hasAudio( sName ) then table.insert( tNames, sName ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua index 33c7eed8f..58eb72fc0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua @@ -2,15 +2,13 @@ -- Display the start screen local w,h = term.getSize() -local titleColour, headingColour, textColour, wormColour, fruitColour +local headingColour, textColour, wormColour, fruitColour if term.isColour() then - titleColour = colours.red headingColour = colours.yellow textColour = colours.white wormColour = colours.green fruitColour = colours.red else - titleColour = colours.white headingColour = colours.white textColour = colours.white wormColour = colours.white @@ -27,8 +25,6 @@ end local xVel,yVel = 1,0 local xPos, yPos = math.floor(w/2), math.floor(h/2) local pxVel, pyVel = nil, nil - -local nLength = 1 local nExtraLength = 6 local bRunning = true @@ -103,7 +99,6 @@ local function drawMenu() end local function update( ) - local x,y = xPos,yPos if pxVel and pyVel then xVel, yVel = pxVel, pyVel pxVel, pyVel = nil, nil @@ -190,7 +185,7 @@ end drawMenu() drawFrontend() while true do - local e,key = os.pullEvent( "key" ) + local _,key = os.pullEvent( "key" ) if key == keys.up or key == keys.w then -- Up if nDifficulty > 1 then @@ -228,7 +223,7 @@ addFruit() -- Play the game local timer = os.startTimer(0) while bRunning do - local event, p1, p2 = os.pullEvent() + local event, p1 = os.pullEvent() if event == "timer" and p1 == timer then timer = os.startTimer(nInterval) update( false ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua index fc1ae7614..77621de75 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua @@ -28,7 +28,7 @@ elseif sCommand == "host" then -- Find a modem local sModemSide = nil - for n,sSide in ipairs( rs.getSides() ) do + for _,sSide in ipairs( rs.getSides() ) do if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then sModemSide = sSide break @@ -80,7 +80,7 @@ elseif sCommand == "host" then -- Print the number of requests handled nServed = nServed + 1 if nServed > 1 then - local x,y = term.getCursorPos() + local _,y = term.getCursorPos() term.setCursorPos(1,y-1) end print( nServed.." GPS requests served" ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/help.lua b/src/main/resources/assets/computercraft/lua/rom/programs/help.lua index 2925cf72d..c8653616a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/help.lua @@ -14,7 +14,7 @@ if sTopic == "index" then end local sFile = help.lookup( sTopic ) -local file = ((sFile ~= nil) and io.open( sFile )) or nil +local file = sFile ~= nil and io.open( sFile ) or nil if file then local sContents = file:read("*a") file:close() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/list.lua b/src/main/resources/assets/computercraft/lua/rom/programs/list.lua index 14ed40439..f493d8ae5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/list.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/list.lua @@ -18,7 +18,7 @@ local tFiles = {} local tDirs = {} local bShowHidden = settings.get( "list.show_hidden" ) -for n, sItem in pairs( tAll ) do +for _, sItem in pairs( tAll ) do if bShowHidden or string.sub( sItem, 1, 1 ) ~= "." then local sPath = fs.combine( sDir, sItem ) if fs.isDir( sPath ) then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index e1a4cb0f2..50766b973 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -67,7 +67,7 @@ while bRunning do local nForcePrint = 0 local func, e = load( s, "=lua", "t", tEnv ) - local func2, e2 = load( "return _echo("..s..");", "=lua", "t", tEnv ) + local func2 = load( "return _echo("..s..");", "=lua", "t", tEnv ) if not func then if func2 then func = func2 @@ -84,7 +84,7 @@ while bRunning do local tResults = table.pack( pcall( func ) ) if tResults[1] then local n = 1 - while n < tResults.n or (n <= nForcePrint) do + while n < tResults.n or n <= nForcePrint do local value = tResults[ n + 1 ] if type( value ) == "table" then local metatable = getmetatable( value ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua index a794c90b9..5f12588e7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua @@ -9,7 +9,7 @@ local sSource = shell.resolve( tArgs[1] ) local sDest = shell.resolve( tArgs[2] ) local tFiles = fs.find( sSource ) if #tFiles > 0 then - for n,sFile in ipairs( tFiles ) do + for _,sFile in ipairs( tFiles ) do if fs.isDir( sDest ) then fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) ) elseif #tFiles == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua index 3680b6b66..afecfa67b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua @@ -424,7 +424,7 @@ local function playGame() end if #rows>0 then - for i=1,4 do + for _=1,4 do sleep(.1) for r=1,#rows do r=rows[r] @@ -469,7 +469,6 @@ local function playGame() end local function blockFall() - local result = false if testBlockAt(curBlock,curX,curY+1,curRot) then pitBlock(curBlock,curX,curY,curRot) --detect rows that clear @@ -524,16 +523,16 @@ local function playGame() dropTimer=os.startTimer(dropSpeed) end if dx+dr~=0 then - if not testBlockAt(curBlock,curX+dx,curY+dy,(dr>0 and curRot%#curBlock+dr or curRot)) then + if not testBlockAt(curBlock,curX+dx,curY+dy,dr>0 and curRot%#curBlock+dr or curRot) then eraseBlockAt(curBlock,curX,curY,curRot) curX=curX+dx curY=curY+dy - curRot=dr==0 and curRot or (curRot%#curBlock+dr) + curRot=dr==0 and curRot or curRot%#curBlock+dr drawBlockAt(curBlock,curX,curY,curRot) end end elseif e[1]=="term_resize" then - local w,h=term.getSize() + local _,h=term.getSize() if h==20 then heightAdjust=0 else @@ -617,7 +616,7 @@ local function runMenu() level=math.max(level-1,1) drawMenu() elseif key>=keys.one and key<=keys.nine and selected==1 then - level=(key-keys.one) + 1 + level=key-keys.one + 1 drawMenu() elseif key==keys.up or key==keys.w then selected=selected-1 diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index 329f15db8..2bf5404ee 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -9,7 +9,7 @@ end local sOpenedModem = nil local function openModem() - for n,sModem in ipairs( peripheral.getNames() ) do + for _,sModem in ipairs( peripheral.getNames() ) do if peripheral.getType( sModem ) == "modem" then if not rednet.isOpen( sModem ) then rednet.open( sModem ) @@ -94,7 +94,7 @@ if sCommand == "host" then end local function printUsers() - local x,y = term.getCursorPos() + local _,y = term.getCursorPos() term.setCursorPos( 1, y - 1 ) term.clearLine() if nUsers == 1 then @@ -108,7 +108,7 @@ if sCommand == "host" then local ok, error = pcall( function() parallel.waitForAny( function() while true do - local sEvent, timer = os.pullEvent( "timer" ) + local _, timer = os.pullEvent( "timer" ) local nUserID = tPingPongTimer[ timer ] if nUserID and tUsers[ nUserID ] then local tUser = tUsers[ nUserID ] @@ -148,7 +148,7 @@ if sCommand == "host" then ["users"] = function( tUser, sContent ) send( "* Connected Users:", tUser.nUserID ) local sUsers = "*" - for nUserID, tUser in pairs( tUsers ) do + for _, tUser in pairs( tUsers ) do sUsers = sUsers .. " " .. tUser.sUsername end send( sUsers, tUser.nUserID ) @@ -156,7 +156,7 @@ if sCommand == "host" then ["help"] = function( tUser, sContent ) send( "* Available commands:", tUser.nUserID ) local sCommands = "*" - for sCommand, fnCommand in pairs( tCommands ) do + for sCommand in pairs( tCommands ) do sCommands = sCommands .. " /" .. sCommand end send( sCommands.." /logout", tUser.nUserID ) @@ -297,8 +297,7 @@ elseif sCommand == "join" then promptWindow.restoreCursor() local function drawTitle() - local x,y = titleWindow.getCursorPos() - local w,h = titleWindow.getSize() + local w = titleWindow.getSize() local sTitle = sUsername.." on "..sHostname titleWindow.setTextColour( highlightColour ) titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 ) @@ -410,7 +409,7 @@ elseif sCommand == "join" then term.redirect( parentTerm ) -- Print error notice - local w,h = term.getSize() + local _,h = term.getSize() term.setCursorPos( 1, h ) term.clearLine() term.setCursorBlink( false ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua index c8fdc89b8..452ffb587 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua @@ -1,7 +1,7 @@ -- Find modems local tModems = {} -for n,sModem in ipairs( peripheral.getNames() ) do +for _,sModem in ipairs( peripheral.getNames() ) do if peripheral.getType( sModem ) == "modem" then table.insert( tModems, sModem ) end @@ -59,7 +59,7 @@ local ok, error = pcall( function() -- Log the event nTransmittedMessages = nTransmittedMessages + 1 - local x,y = term.getCursorPos() + local _,y = term.getCursorPos() term.setCursorPos( 1, y - 1 ) term.clearLine() if nTransmittedMessages == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua index 8a6d2db86..ff38a89ef 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua @@ -17,7 +17,7 @@ if sCommand == "probe" then local count = 0 local bundledCount = 0 - for n,sSide in ipairs( redstone.getSides() ) do + for _,sSide in ipairs( redstone.getSides() ) do if redstone.getBundledInput( sSide ) > 0 then bundledCount = bundledCount + 1 end @@ -39,7 +39,7 @@ if sCommand == "probe" then if bundledCount > 0 then print() print( "Bundled inputs:" ) - for i,sSide in ipairs( redstone.getSides() ) do + for _,sSide in ipairs( redstone.getSides() ) do local nInput = redstone.getBundledInput( sSide ) if nInput ~= 0 then write( sSide..": " ) @@ -69,7 +69,7 @@ elseif sCommand == "pulse" then local sSide = tArgs[2] local nCount = tonumber( tArgs[3] ) or 1 local nPeriod = tonumber( tArgs[4] ) or 0.5 - for n=1,nCount do + for _=1,nCount do redstone.setOutput( sSide, true ) sleep( nPeriod / 2 ) redstone.setOutput( sSide, false ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua index 9acad56c2..94ef6b621 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua @@ -2,7 +2,7 @@ local tArgs = { ... } if #tArgs == 0 then -- "set" - local x,y = term.getCursorPos() + local _,y = term.getCursorPos() local tSettings = {} for n,sName in ipairs( settings.getNames() ) do tSettings[n] = textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 3c15e04b3..13c4b90c0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -9,10 +9,10 @@ if multishell then end local bExit = false -local sDir = (parentShell and parentShell.dir()) or "" -local sPath = (parentShell and parentShell.path()) or ".:/rom/programs" -local tAliases = (parentShell and parentShell.aliases()) or {} -local tCompletionInfo = (parentShell and parentShell.getCompletionInfo()) or {} +local sDir = parentShell and parentShell.dir() or "" +local sPath = parentShell and parentShell.path() or ".:/rom/programs" +local tAliases = parentShell and parentShell.aliases() or {} +local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {} local tProgramStack = {} local shell = {} @@ -287,7 +287,7 @@ function shell.programs( _bIncludeHidden ) -- Sort and return local tItemList = {} - for sItem, b in pairs( tItems ) do + for sItem in pairs( tItems ) do table.insert( tItemList, sItem ) end table.sort( tItemList ) @@ -304,7 +304,7 @@ local function completeProgram( sLine ) local tSeen = {} -- Add aliases - for sAlias, sCommand in pairs( tAliases ) do + for sAlias in pairs( tAliases ) do if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then local sResult = string.sub( sAlias, #sLine + 1 ) if not tSeen[ sResult ] then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua index 6f32a1df0..246992f78 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua @@ -81,7 +81,7 @@ textutils.slowWrite( "Preparing to get down." ) textutils.slowPrint( "..", 0.75 ) local sAudio = nil -for n,sName in pairs( peripheral.getNames() ) do +for _,sName in pairs( peripheral.getNames() ) do if disk.hasAudio( sName ) then disk.playAudio( sName ) print( "Jamming to "..disk.getAudioTitle( sName ) ) @@ -95,7 +95,7 @@ print( "Press any key to stop the groove" ) parallel.waitForAny( function() while not bEnd do - local event, key = os.pullEvent("key") + local _, key = os.pullEvent("key") if key ~= keys.escape then return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua index 677e43678..5e7f32274 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua @@ -81,7 +81,7 @@ local function collect() if nTotalItems > collected then collected = nTotalItems if math.fmod(collected + unloaded, 50) == 0 then - print( "Mined "..(collected + unloaded).." items." ) + print( "Mined "..collected + unloaded.." items." ) end end @@ -98,9 +98,8 @@ function refuel( ammount ) return true end - local needed = ammount or (xPos + zPos + depth + 2) + local needed = ammount or xPos + zPos + depth + 2 if turtle.getFuelLevel() < needed then - local fueled = false for n=1,16 do if turtle.getItemCount(n) > 0 then turtle.select(n) @@ -292,7 +291,7 @@ local alternate = 0 local done = false while not done do for n=1,size do - for m=1,size-1 do + for _=1,size-1 do if not tryForwards() then done = true break @@ -354,4 +353,4 @@ if reseal then turtle.placeDown() end -print( "Mined "..(collected + unloaded).." items total." ) +print( "Mined "..collected + unloaded.." items total." ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua index d9f606f8c..fa69de01c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua @@ -23,7 +23,7 @@ end if turtle.getFuelLevel() ~= "unlimited" then for n = 1, 16 do -- Stop if we've reached the limit, or are fully refuelled. - if (nLimit and nLimit <= 0) or turtle.getFuelLevel() >= turtle.getFuelLimit() then + if nLimit and nLimit <= 0 or turtle.getFuelLevel() >= turtle.getFuelLimit() then break end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua index 9345a6225..9bf4e2665 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua @@ -15,8 +15,6 @@ if length < 1 then print( "Tunnel length must be positive" ) return end - -local depth = 0 local collected = 0 local function collect() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua index 4ab6151ec..df90142d2 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua @@ -31,7 +31,7 @@ while nArg <= #tArgs do local fnHandler = tHandlers[string.lower(sDirection)] if fnHandler then - for n=1,nDistance do + for _=1,nDistance do fnHandler( nArg ) end else diff --git a/src/main/resources/assets/computercraft/lua/rom/startup.lua b/src/main/resources/assets/computercraft/lua/rom/startup.lua index e6b396b39..af8ff4fbc 100644 --- a/src/main/resources/assets/computercraft/lua/rom/startup.lua +++ b/src/main/resources/assets/computercraft/lua/rom/startup.lua @@ -163,7 +163,7 @@ if settings.get( "shell.allow_startup" ) then tUserStartups = findStartups( "/" ) end if settings.get( "shell.allow_disk_startup" ) then - for n,sName in pairs( peripheral.getNames() ) do + for _,sName in pairs( peripheral.getNames() ) do if disk.isPresent( sName ) and disk.hasData( sName ) then local startups = findStartups( disk.getMountPath( sName ) ) if startups then From fa70ebcac248c2360b58a014a38b8334eeb75838 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 7 Dec 2019 10:33:47 +0000 Subject: [PATCH 107/711] Fix spacing on all of the rom (#323) --- illuaminate.sexp | 3 +- .../assets/computercraft/lua/bios.lua | 34 +- .../computercraft/lua/rom/apis/colors.lua | 6 +- .../computercraft/lua/rom/apis/colours.lua | 2 +- .../lua/rom/apis/command/commands.lua | 6 +- .../computercraft/lua/rom/apis/disk.lua | 2 +- .../assets/computercraft/lua/rom/apis/gps.lua | 14 +- .../computercraft/lua/rom/apis/help.lua | 12 +- .../assets/computercraft/lua/rom/apis/io.lua | 6 +- .../computercraft/lua/rom/apis/keys.lua | 86 +-- .../computercraft/lua/rom/apis/paintutils.lua | 26 +- .../computercraft/lua/rom/apis/parallel.lua | 4 +- .../computercraft/lua/rom/apis/peripheral.lua | 16 +- .../computercraft/lua/rom/apis/rednet.lua | 10 +- .../computercraft/lua/rom/apis/settings.lua | 4 +- .../computercraft/lua/rom/apis/term.lua | 8 +- .../computercraft/lua/rom/apis/textutils.lua | 38 +- .../lua/rom/apis/turtle/turtle.lua | 2 +- .../computercraft/lua/rom/apis/vector.lua | 14 +- .../computercraft/lua/rom/apis/window.lua | 20 +- .../lua/rom/programs/advanced/multishell.lua | 26 +- .../computercraft/lua/rom/programs/alias.lua | 2 +- .../computercraft/lua/rom/programs/apis.lua | 2 +- .../lua/rom/programs/command/exec.lua | 6 +- .../computercraft/lua/rom/programs/copy.lua | 2 +- .../computercraft/lua/rom/programs/edit.lua | 94 +-- .../computercraft/lua/rom/programs/eject.lua | 2 +- .../lua/rom/programs/fun/advanced/paint.lua | 92 +-- .../rom/programs/fun/advanced/redirection.lua | 294 ++++---- .../lua/rom/programs/fun/adventure.lua | 132 ++-- .../computercraft/lua/rom/programs/fun/dj.lua | 8 +- .../lua/rom/programs/fun/hello.lua | 2 +- .../lua/rom/programs/fun/worm.lua | 84 +-- .../computercraft/lua/rom/programs/gps.lua | 16 +- .../lua/rom/programs/http/pastebin.lua | 20 +- .../computercraft/lua/rom/programs/id.lua | 10 +- .../computercraft/lua/rom/programs/label.lua | 12 +- .../computercraft/lua/rom/programs/lua.lua | 2 +- .../computercraft/lua/rom/programs/mkdir.lua | 4 +- .../lua/rom/programs/monitor.lua | 6 +- .../computercraft/lua/rom/programs/motd.lua | 4 +- .../computercraft/lua/rom/programs/move.lua | 2 +- .../lua/rom/programs/peripherals.lua | 2 +- .../lua/rom/programs/pocket/falling.lua | 630 +++++++++--------- .../lua/rom/programs/rednet/chat.lua | 40 +- .../lua/rom/programs/rednet/repeat.lua | 10 +- .../lua/rom/programs/redstone.lua | 10 +- .../computercraft/lua/rom/programs/set.lua | 6 +- .../computercraft/lua/rom/programs/shell.lua | 22 +- .../computercraft/lua/rom/programs/time.lua | 2 +- .../lua/rom/programs/turtle/craft.lua | 2 +- .../lua/rom/programs/turtle/dance.lua | 6 +- .../lua/rom/programs/turtle/excavate.lua | 38 +- .../lua/rom/programs/turtle/go.lua | 2 +- .../lua/rom/programs/turtle/refuel.lua | 2 +- .../lua/rom/programs/turtle/tunnel.lua | 10 +- .../lua/rom/programs/turtle/turn.lua | 4 +- .../lua/rom/programs/turtle/unequip.lua | 2 +- .../assets/computercraft/lua/rom/startup.lua | 22 +- src/test/resources/test-rom/mcfly.lua | 38 +- .../resources/test-rom/spec/apis/gps_spec.lua | 2 +- .../resources/test-rom/spec/apis/io_spec.lua | 6 +- .../resources/test-rom/spec/base_spec.lua | 2 +- .../spec/modules/cc/shell/completion_spec.lua | 2 +- .../spec/programs/command/commands_spec.lua | 2 +- .../spec/programs/command/exec_spec.lua | 6 +- .../test-rom/spec/programs/edit_spec.lua | 1 - .../spec/programs/http/pastebin_spec.lua | 4 +- .../test-rom/spec/programs/http/wget_spec.lua | 2 +- .../test-rom/spec/programs/id_spec.lua | 2 +- .../test-rom/spec/programs/motd_spec.lua | 4 +- .../spec/programs/pocket/equip_spec.lua | 4 +- .../spec/programs/pocket/unequip_spec.lua | 4 +- .../test-rom/spec/programs/set_spec.lua | 8 +- .../test-rom/spec/programs/time_spec.lua | 2 +- .../spec/programs/turtle/craft_spec.lua | 4 +- .../spec/programs/turtle/equip_spec.lua | 6 +- .../spec/programs/turtle/refuel_spec.lua | 6 +- .../spec/programs/turtle/unequip_spec.lua | 12 +- .../resources/test-rom/spec/test_helpers.lua | 2 +- 80 files changed, 1032 insertions(+), 1032 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index 2271a01e5..b4deb17bd 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -2,7 +2,8 @@ (sources /src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/) + /src/main/resources/assets/computercraft/lua/rom/ + /src/test/resources/test-rom) (at / (linters diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index e4b792538..4a30d22da 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -93,7 +93,7 @@ if _VERSION == "Lua 5.1" then bxor = bit32.bxor, brshift = bit32.arshift, blshift = bit32.lshift, - blogic_rshift = bit32.rshift + blogic_rshift = bit32.rshift, } end end @@ -191,8 +191,8 @@ end function write( sText ) expect(1, sText, "string", "number") - local w,h = term.getSize() - local x,y = term.getCursorPos() + local w, h = term.getSize() + local x, y = term.getCursorPos() local nLinesPrinted = 0 local function newLine() @@ -212,7 +212,7 @@ function write( sText ) if whitespace then -- Print whitespace term.write( whitespace ) - x,y = term.getCursorPos() + x, y = term.getCursorPos() sText = string.sub( sText, string.len(whitespace) + 1 ) end @@ -233,8 +233,8 @@ function write( sText ) newLine() end term.write( text ) - text = string.sub( text, w-x + 2 ) - x,y = term.getCursorPos() + text = string.sub( text, w - x + 2 ) + x, y = term.getCursorPos() end else -- Print a word normally @@ -242,7 +242,7 @@ function write( sText ) newLine() end term.write( text ) - x,y = term.getCursorPos() + x, y = term.getCursorPos() end end end @@ -613,10 +613,10 @@ function os.loadAPI( _sPath ) expect(1, _sPath, "string") local sName = fs.getName( _sPath ) if sName:sub(-4) == ".lua" then - sName = sName:sub(1,-5) + sName = sName:sub(1, -5) end if tAPIsLoading[sName] == true then - printError( "API "..sName.." is already being loaded" ) + printError( "API " .. sName .. " is already being loaded" ) return false end tAPIsLoading[sName] = true @@ -636,7 +636,7 @@ function os.loadAPI( _sPath ) end local tAPI = {} - for k,v in pairs( tEnv ) do + for k, v in pairs( tEnv ) do if k ~= "_ENV" then tAPI[k] = v end @@ -680,7 +680,7 @@ if http then local methods = { GET = true, POST = true, HEAD = true, - OPTIONS = true, PUT = true, DELETE = true + OPTIONS = true, PUT = true, DELETE = true, } local function checkKey( options, key, ty, opt ) @@ -842,7 +842,7 @@ function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) end end local tFiles = fs.list( sDir ) - for n=1,#tFiles do + for n = 1, #tFiles do local sFile = tFiles[n] if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then local bIsDir = fs.isDir( fs.combine( sDir, sFile ) ) @@ -867,7 +867,7 @@ end -- Load APIs local bAPIError = false local tApis = fs.list( "rom/apis" ) -for _,sFile in ipairs( tApis ) do +for _, sFile in ipairs( tApis ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = fs.combine( "rom/apis", sFile ) if not fs.isDir( sPath ) then @@ -881,7 +881,7 @@ end if turtle and fs.isDir( "rom/apis/turtle" ) then -- Load turtle APIs local tApis = fs.list( "rom/apis/turtle" ) - for _,sFile in ipairs( tApis ) do + for _, sFile in ipairs( tApis ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = fs.combine( "rom/apis/turtle", sFile ) if not fs.isDir( sPath ) then @@ -896,7 +896,7 @@ end if pocket and fs.isDir( "rom/apis/pocket" ) then -- Load pocket APIs local tApis = fs.list( "rom/apis/pocket" ) - for _,sFile in ipairs( tApis ) do + for _, sFile in ipairs( tApis ) do if string.sub( sFile, 1, 1 ) ~= "." then local sPath = fs.combine( "rom/apis/pocket", sFile ) if not fs.isDir( sPath ) then @@ -925,7 +925,7 @@ if commands and fs.isDir( "rom/apis/command" ) then end end return nil - end + end, } setmetatable( commands, tCaseInsensitiveMetatable ) setmetatable( commands.async, tCaseInsensitiveMetatable ) @@ -941,7 +941,7 @@ if bAPIError then print( "Press any key to continue" ) os.pullEvent( "key" ) term.clear() - term.setCursorPos( 1,1 ) + term.setCursorPos( 1, 1 ) end -- Set default settings diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua index 969f984e5..b2e665268 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua @@ -23,7 +23,7 @@ function combine( ... ) for i = 1, select('#', ...) do local c = select(i, ...) expect(i, c, "number") - r = bit32.bor(r,c) + r = bit32.bor(r, c) end return r end @@ -50,8 +50,8 @@ function packRGB( r, g, b ) expect(2, g, "number") expect(3, b, "number") return - bit32.band( r * 255, 0xFF ) * 2^16 + - bit32.band( g * 255, 0xFF ) * 2^8 + + bit32.band( r * 255, 0xFF ) * 2 ^ 16 + + bit32.band( g * 255, 0xFF ) * 2 ^ 8 + bit32.band( b * 255, 0xFF ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua index 59202ebc5..fa17c6cb3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua @@ -1,6 +1,6 @@ -- Colours (for lovers of british spelling) local colours = _ENV -for k,v in pairs(colors) do +for k, v in pairs(colors) do colours[k] = v end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua index 7afd34bad..caf86f5cf 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua @@ -22,7 +22,7 @@ end -- Put native functions into the environment local env = _ENV -for k,v in pairs( native ) do +for k, v in pairs( native ) do env[k] = v end @@ -30,10 +30,10 @@ end local tAsync = {} local tNonNBTJSONCommands = { [ "tellraw" ] = true, - [ "title" ] = true + [ "title" ] = true, } local tCommands = native.list() -for _,sCommandName in ipairs(tCommands) do +for _, sCommandName in ipairs(tCommands) do if env[ sCommandName ] == nil then local bJSONIsNBT = tNonNBTJSONCommands[ sCommandName ] == nil env[ sCommandName ] = function( ... ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua index 2c5e6ec8b..7a0dbad39 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua @@ -62,7 +62,7 @@ end function stopAudio( name ) if not name then - for _,sName in ipairs( peripheral.getNames() ) do + for _, sName in ipairs( peripheral.getNames() ) do stopAudio( sName ) end else diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index aab023209..5b556eb09 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -21,12 +21,12 @@ local function trilaterate( A, B, C ) local r2 = B.nDistance local r3 = C.nDistance - local x = (r1*r1 - r2*r2 + d*d) / (2*d) - local y = (r1*r1 - r3*r3 - x*x + (x-i)*(x-i) + j*j) / (2*j) + local x = (r1 * r1 - r2 * r2 + d * d) / (2 * d) + local y = (r1 * r1 - r3 * r3 - x * x + (x - i) * (x - i) + j * j) / (2 * j) local result = A.vPosition + ex * x + ey * y - local zSquared = r1*r1 - x*x - y*y + local zSquared = r1 * r1 - x * x - y * y if zSquared > 0 then local z = math.sqrt( zSquared ) local result1 = result + ez * z @@ -66,7 +66,7 @@ function locate( _nTimeout, _bDebug ) -- Find a modem local sModemSide = nil - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then sModemSide = sSide break @@ -109,7 +109,7 @@ function locate( _nTimeout, _bDebug ) if type(tMessage) == "table" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance } if _bDebug then - print( tFix.nDistance.." metres from "..tostring( tFix.vPosition ) ) + print( tFix.nDistance .. " metres from " .. tostring( tFix.vPosition ) ) end if tFix.nDistance == 0 then pos1, pos2 = tFix.vPosition, nil @@ -148,12 +148,12 @@ function locate( _nTimeout, _bDebug ) if pos1 and pos2 then if _bDebug then print( "Ambiguous position" ) - print( "Could be "..pos1.x..","..pos1.y..","..pos1.z.." or "..pos2.x..","..pos2.y..","..pos2.z ) + print( "Could be " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z .. " or " .. pos2.x .. "," .. pos2.y .. "," .. pos2.z ) end return nil elseif pos1 then if _bDebug then - print( "Position is "..pos1.x..","..pos1.y..","..pos1.z ) + print( "Position is " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z ) end return pos1.x, pos1.y, pos1.z else diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index 853ec09a0..ded20f2f3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -18,8 +18,8 @@ function lookup( _sTopic ) sPath = fs.combine( sPath, _sTopic ) if fs.exists( sPath ) and not fs.isDir( sPath ) then return sPath - elseif fs.exists( sPath..".txt" ) and not fs.isDir( sPath..".txt" ) then - return sPath..".txt" + elseif fs.exists( sPath .. ".txt" ) and not fs.isDir( sPath .. ".txt" ) then + return sPath .. ".txt" end end @@ -30,18 +30,18 @@ end function topics() -- Add index local tItems = { - [ "index" ] = true + [ "index" ] = true, } -- Add topics from the path for sPath in string.gmatch(sPath, "[^:]+") do if fs.isDir( sPath ) then local tList = fs.list( sPath ) - for _,sFile in pairs( tList ) do + for _, sFile in pairs( tList ) do if string.sub( sFile, 1, 1 ) ~= "." then if not fs.isDir( fs.combine( sPath, sFile ) ) then if #sFile > 4 and sFile:sub(-4) == ".txt" then - sFile = sFile:sub(1,-5) + sFile = sFile:sub(1, -5) end tItems[ sFile ] = true end @@ -63,7 +63,7 @@ function completeTopic( sText ) expect(1, sText, "string") local tTopics = topics() local tResults = {} - for n=1,#tTopics do + for n = 1, #tTopics do local sTopic = tTopics[n] if #sTopic > #sText and string.sub( sTopic, 1, #sText ) == sText then table.insert( tResults, string.sub( sTopic, #sText + 1 ) ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index efbc13b40..779d7e26d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -129,11 +129,11 @@ handleMetatable = { } local defaultInput = setmetatable({ - _handle = { readLine = _G.read } + _handle = { readLine = _G.read }, }, handleMetatable) local defaultOutput = setmetatable({ - _handle = { write = _G.write } + _handle = { write = _G.write }, }, handleMetatable) local defaultError = setmetatable({ @@ -147,7 +147,7 @@ local defaultError = setmetatable({ _G.write(...) if term.isColour() then term.setTextColour(oldColour) end end, - } + }, }, handleMetatable) local currentInput = defaultInput diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua index 8411883cf..c3ab42605 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua @@ -4,49 +4,49 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect local tKeys = { - nil, "one", "two", "three", "four", -- 1 - "five", "six", "seven", "eight", "nine", -- 6 - "zero", "minus", "equals", "backspace","tab", -- 11 - "q", "w", "e", "r", "t", -- 16 - "y", "u", "i", "o", "p", -- 21 - "leftBracket","rightBracket","enter","leftCtrl","a", -- 26 - "s", "d", "f", "g", "h", -- 31 - "j", "k", "l", "semiColon","apostrophe", -- 36 - "grave", "leftShift","backslash","z", "x", -- 41 - "c", "v", "b", "n", "m", -- 46 - "comma", "period", "slash", "rightShift","multiply", -- 51 - "leftAlt", "space", "capsLock", "f1", "f2", -- 56 - "f3", "f4", "f5", "f6", "f7", -- 61 - "f8", "f9", "f10", "numLock", "scrollLock", -- 66 - "numPad7", "numPad8", "numPad9", "numPadSubtract","numPad4", -- 71 - "numPad5", "numPad6", "numPadAdd","numPad1", "numPad2", -- 76 - "numPad3", "numPad0", "numPadDecimal",nil, nil, -- 81 - nil, "f11", "f12", nil, nil, -- 86 - nil, nil, nil, nil, nil, -- 91 - nil, nil, nil, nil, "f13", -- 96 - "f14", "f15", nil, nil, nil, -- 101 - nil, nil, nil, nil, nil, -- 106 - nil, "kana", nil, nil, nil, -- 111 - nil, nil, nil, nil, nil, -- 116 - "convert", nil, "noconvert",nil, "yen", -- 121 - nil, nil, nil, nil, nil, -- 126 - nil, nil, nil, nil, nil, -- 131 - nil, nil, nil, nil, nil, -- 136 - "numPadEquals",nil, nil, "circumflex","at", -- 141 - "colon", "underscore","kanji", "stop", "ax", -- 146 - nil, nil, nil, nil, nil, -- 151 - "numPadEnter","rightCtrl",nil, nil, nil, -- 156 - nil, nil, nil, nil, nil, -- 161 - nil, nil, nil, nil, nil, -- 166 - nil, nil, nil, nil, nil, -- 171 - nil, nil, nil, "numPadComma",nil, -- 176 - "numPadDivide",nil, nil, "rightAlt", nil, -- 181 - nil, nil, nil, nil, nil, -- 186 - nil, nil, nil, nil, nil, -- 191 - nil, "pause", nil, "home", "up", -- 196 - "pageUp", nil, "left", nil, "right", -- 201 - nil, "end", "down", "pageDown", "insert", -- 206 - "delete" -- 211 + nil, "one", "two", "three", "four", -- 1 + "five", "six", "seven", "eight", "nine", -- 6 + "zero", "minus", "equals", "backspace", "tab", -- 11 + "q", "w", "e", "r", "t", -- 16 + "y", "u", "i", "o", "p", -- 21 + "leftBracket", "rightBracket", "enter", "leftCtrl", "a", -- 26 + "s", "d", "f", "g", "h", -- 31 + "j", "k", "l", "semiColon", "apostrophe", -- 36 + "grave", "leftShift", "backslash", "z", "x", -- 41 + "c", "v", "b", "n", "m", -- 46 + "comma", "period", "slash", "rightShift", "multiply", -- 51 + "leftAlt", "space", "capsLock", "f1", "f2", -- 56 + "f3", "f4", "f5", "f6", "f7", -- 61 + "f8", "f9", "f10", "numLock", "scrollLock", -- 66 + "numPad7", "numPad8", "numPad9", "numPadSubtract", "numPad4", -- 71 + "numPad5", "numPad6", "numPadAdd", "numPad1", "numPad2", -- 76 + "numPad3", "numPad0", "numPadDecimal", nil, nil, -- 81 + nil, "f11", "f12", nil, nil, -- 86 + nil, nil, nil, nil, nil, -- 91 + nil, nil, nil, nil, "f13", -- 96 + "f14", "f15", nil, nil, nil, -- 101 + nil, nil, nil, nil, nil, -- 106 + nil, "kana", nil, nil, nil, -- 111 + nil, nil, nil, nil, nil, -- 116 + "convert", nil, "noconvert", nil, "yen", -- 121 + nil, nil, nil, nil, nil, -- 126 + nil, nil, nil, nil, nil, -- 131 + nil, nil, nil, nil, nil, -- 136 + "numPadEquals", nil, nil, "circumflex", "at", -- 141 + "colon", "underscore", "kanji", "stop", "ax", -- 146 + nil, nil, nil, nil, nil, -- 151 + "numPadEnter", "rightCtrl", nil, nil, nil, -- 156 + nil, nil, nil, nil, nil, -- 161 + nil, nil, nil, nil, nil, -- 166 + nil, nil, nil, nil, nil, -- 171 + nil, nil, nil, "numPadComma", nil, -- 176 + "numPadDivide", nil, nil, "rightAlt", nil, -- 181 + nil, nil, nil, nil, nil, -- 186 + nil, nil, nil, nil, nil, -- 191 + nil, "pause", nil, "home", "up", -- 196 + "pageUp", nil, "left", nil, "right", -- 201 + nil, "end", "down", "pageDown", "insert", -- 206 + "delete", -- 211 } local keys = _ENV diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index 5420b029d..d725367d0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -6,14 +6,14 @@ local function drawPixelInternal( xPos, yPos ) end local tColourLookup = {} -for n=1,16 do - tColourLookup[ string.byte( "0123456789abcdef",n,n ) ] = 2^(n-1) +for n = 1, 16 do + tColourLookup[ string.byte( "0123456789abcdef", n, n ) ] = 2 ^ (n - 1) end local function parseLine( tImageArg, sLine ) local tLine = {} - for x=1,sLine:len() do - tLine[x] = tColourLookup[ string.byte(sLine,x,x) ] or 0 + for x = 1, sLine:len() do + tLine[x] = tColourLookup[ string.byte(sLine, x, x) ] or 0 end table.insert( tImageArg, tLine ) end @@ -89,7 +89,7 @@ function drawLine( startX, startY, endX, endY, nColour ) if xDiff > math.abs(yDiff) then local y = minY local dy = yDiff / xDiff - for x=minX,maxX do + for x = minX, maxX do drawPixelInternal( x, math.floor( y + 0.5 ) ) y = y + dy end @@ -97,12 +97,12 @@ function drawLine( startX, startY, endX, endY, nColour ) local x = minX local dx = xDiff / yDiff if maxY >= minY then - for y=minY,maxY do + for y = minY, maxY do drawPixelInternal( math.floor( x + 0.5 ), y ) x = x + dx end else - for y=minY,maxY,-1 do + for y = minY, maxY, -1 do drawPixelInternal( math.floor( x + 0.5 ), y ) x = x - dx end @@ -142,13 +142,13 @@ function drawBox( startX, startY, endX, endY, nColour ) maxY = startY end - for x=minX,maxX do + for x = minX, maxX do drawPixelInternal( x, minY ) drawPixelInternal( x, maxY ) end if maxY - minY >= 2 then - for y=minY+1,maxY-1 do + for y = minY + 1, maxY - 1 do drawPixelInternal( minX, y ) drawPixelInternal( maxX, y ) end @@ -187,8 +187,8 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) maxY = startY end - for x=minX,maxX do - for y=minY,maxY do + for x = minX, maxX do + for y = minY, maxY do drawPixelInternal( x, y ) end end @@ -198,9 +198,9 @@ function drawImage( tImage, xPos, yPos ) expect(1, tImage, "table") expect(2, xPos, "number") expect(3, yPos, "number") - for y=1,#tImage do + for y = 1, #tImage do local tLine = tImage[y] - for x=1,#tLine do + for x = 1, #tLine do if tLine[x] > 0 then term.setBackgroundColor( tLine[x] ) drawPixelInternal( x + xPos - 1, y + yPos - 1 ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua b/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua index 7aad3519d..43b832c8b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua @@ -21,7 +21,7 @@ local function runUntilLimit( _routines, _limit ) local tFilters = {} local eventData = { n = 0 } while true do - for n=1,count do + for n = 1, count do local r = _routines[n] if r then if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == "terminate" then @@ -41,7 +41,7 @@ local function runUntilLimit( _routines, _limit ) end end end - for n=1,count do + for n = 1, count do local r = _routines[n] if r and coroutine.status( r ) == "dead" then _routines[n] = nil diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index ecfccbb53..a398d696f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -4,12 +4,12 @@ local native = peripheral function getNames() local tResults = {} - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if native.isPresent( sSide ) then table.insert( tResults, sSide ) if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then local tRemote = native.call( sSide, "getNamesRemote" ) - for _,sName in ipairs( tRemote ) do + for _, sName in ipairs( tRemote ) do table.insert( tResults, sName ) end end @@ -23,7 +23,7 @@ function isPresent( _sSide ) if native.isPresent( _sSide ) then return true end - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return true @@ -38,7 +38,7 @@ function getType( _sSide ) if native.isPresent( _sSide ) then return native.getType( _sSide ) end - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return native.call( sSide, "getTypeRemote", _sSide ) @@ -53,7 +53,7 @@ function getMethods( _sSide ) if native.isPresent( _sSide ) then return native.getMethods( _sSide ) end - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return native.call( sSide, "getMethodsRemote", _sSide ) @@ -69,7 +69,7 @@ function call( _sSide, _sMethod, ... ) if native.isPresent( _sSide ) then return native.call( _sSide, _sMethod, ... ) end - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then if native.call( sSide, "isPresentRemote", _sSide ) then return native.call( sSide, "callRemote", _sSide, _sMethod, ... ) @@ -84,7 +84,7 @@ function wrap( _sSide ) if peripheral.isPresent( _sSide ) then local tMethods = peripheral.getMethods( _sSide ) local tResult = {} - for _,sMethod in ipairs( tMethods ) do + for _, sMethod in ipairs( tMethods ) do tResult[sMethod] = function( ... ) return peripheral.call( _sSide, sMethod, ... ) end @@ -98,7 +98,7 @@ function find( sType, fnFilter ) expect(1, sType, "string") expect(2, fnFilter, "function", "nil") local tResults = {} - for _,sName in ipairs( peripheral.getNames() ) do + for _, sName in ipairs( peripheral.getNames() ) do if peripheral.getType( sName ) == sType then local wrapped = peripheral.wrap( sName ) if fnFilter == nil or fnFilter( sName, wrapped ) then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index e38084ad5..d6bf5d668 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -10,7 +10,7 @@ local tHostnames = {} function open( sModem ) expect(1, sModem, "string") if peripheral.getType( sModem ) ~= "modem" then - error( "No such modem: "..sModem, 2 ) + error( "No such modem: " .. sModem, 2 ) end peripheral.call( sModem, "open", os.getComputerID() ) peripheral.call( sModem, "open", CHANNEL_BROADCAST ) @@ -21,13 +21,13 @@ function close( sModem ) if sModem then -- Close a specific modem if peripheral.getType( sModem ) ~= "modem" then - error( "No such modem: "..sModem, 2 ) + error( "No such modem: " .. sModem, 2 ) end peripheral.call( sModem, "close", os.getComputerID() ) peripheral.call( sModem, "close", CHANNEL_BROADCAST ) else -- Close all modems - for _,sModem in ipairs( peripheral.getNames() ) do + for _, sModem in ipairs( peripheral.getNames() ) do if isOpen( sModem ) then close( sModem ) end @@ -44,7 +44,7 @@ function isOpen( sModem ) end else -- Check if any modem is open - for _,sModem in ipairs( peripheral.getNames() ) do + for _, sModem in ipairs( peripheral.getNames() ) do if isOpen( sModem ) then return true end @@ -79,7 +79,7 @@ function send( nRecipient, message, sProtocol ) sent = true else -- Send on all open modems, to the target and to repeaters - for _,sModem in ipairs( peripheral.getNames() ) do + for _, sModem in ipairs( peripheral.getNames() ) do if isOpen( sModem ) then peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage ) peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 9f9ba9822..54da34a32 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -17,7 +17,7 @@ local copy function copy( value ) if type(value) == "table" then local result = {} - for k,v in pairs(value) do + for k, v in pairs(value) do result[k] = copy(v) end return result @@ -69,7 +69,7 @@ function load( sPath ) return false end - for k,v in pairs(tFile) do + for k, v in pairs(tFile) do if type(k) == "string" and (type(v) == "string" or type(v) == "number" or type(v) == "boolean" or type(v) == "table") then set( k, v ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index 98db90be7..706bd16f6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -16,11 +16,11 @@ term.redirect = function( target ) if target == term or target == _G.term then error( "term is not a recommended redirect target, try term.current() instead", 2 ) end - for k,v in pairs( native ) do + for k, v in pairs( native ) do if type( k ) == "string" and type( v ) == "function" then if type( target[k] ) ~= "function" then target[k] = function() - error( "Redirect object is missing method "..k..".", 2 ) + error( "Redirect object is missing method " .. k .. ".", 2 ) end end end @@ -48,13 +48,13 @@ for _, method in ipairs { "nativePaletteColor", "nativePaletteColour"} do native[method] = nil end -for k,v in pairs( native ) do +for k, v in pairs( native ) do if type( k ) == "string" and type( v ) == "function" and term[k] == nil then term[k] = wrap( k ) end end local env = _ENV -for k,v in pairs( term ) do +for k, v in pairs( term ) do env[k] = v end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 09130fbad..5044d9dc3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -9,10 +9,10 @@ function slowWrite( sText, nRate ) local nSleep = 1 / nRate sText = tostring( sText ) - local x,y = term.getCursorPos() + local x, y = term.getCursorPos() local len = string.len( sText ) - for n=1,len do + for n = 1, len do term.setCursorPos( x, y ) sleep( nSleep ) local nLines = write( string.sub( sText, 1, n ) ) @@ -42,7 +42,7 @@ function formatTime( nTime, bTwentyFourHour ) end local nHour = math.floor(nTime) - local nMinute = math.floor((nTime - nHour)*60) + local nMinute = math.floor((nTime - nHour) * 60) if sTOD then return string.format( "%d:%02d %s", nHour, nMinute, sTOD ) else @@ -54,11 +54,11 @@ local function makePagedScroll( _term, _nFreeLines ) local nativeScroll = _term.scroll local nFreeLines = _nFreeLines or 0 return function( _n ) - for _=1,_n do + for _ = 1, _n do nativeScroll( 1 ) if nFreeLines <= 0 then - local _,h = _term.getSize() + local _, h = _term.getSize() _term.setCursorPos( 1, h ) _term.write( "Press any key to continue" ) os.pullEvent( "key" ) @@ -76,7 +76,7 @@ function pagedPrint( _sText, _nFreeLines ) -- Setup a redirector local oldTerm = term.current() local newTerm = {} - for k,v in pairs( oldTerm ) do + for k, v in pairs( oldTerm ) do newTerm[k] = v end newTerm.scroll = makePagedScroll( oldTerm, _nFreeLines ) @@ -108,13 +108,13 @@ local function tabulateCommon( bPaged, ... ) expect(i, tAll[i], "number", "table") end - local w,h = term.getSize() + local w, h = term.getSize() local nMaxLen = w / 8 for n, t in ipairs( tAll ) do if type(t) == "table" then for nu, sItem in pairs(t) do if type( sItem ) ~= "string" then - error( "bad argument #"..n.."."..nu.." (expected string, got " .. type( sItem ) .. ")", 3 ) + error( "bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type( sItem ) .. ")", 3 ) end nMaxLen = math.max( string.len( sItem ) + 1, nMaxLen ) end @@ -123,7 +123,7 @@ local function tabulateCommon( bPaged, ... ) local nCols = math.floor( w / nMaxLen ) local nLines = 0 local function newLine() - if bPaged and nLines >= h-3 then + if bPaged and nLines >= h - 3 then pagedPrint() else print() @@ -207,11 +207,11 @@ local function serializeImpl( t, tTracking, sIndent ) local sResult = "{\n" local sSubIndent = sIndent .. " " local tSeen = {} - for k,v in ipairs(t) do + for k, v in ipairs(t) do tSeen[k] = true sResult = sResult .. sSubIndent .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" end - for k,v in pairs(t) do + for k, v in pairs(t) do if not tSeen[k] then local sEntry if type(k) == "string" and not g_tLuaKeywords[k] and string.match( k, "^[%a_][%a%d_]*$" ) then @@ -233,7 +233,7 @@ local function serializeImpl( t, tTracking, sIndent ) return tostring(t) else - error( "Cannot serialize type "..sType, 0 ) + error( "Cannot serialize type " .. sType, 0 ) end end @@ -241,7 +241,7 @@ end empty_json_array = setmetatable({}, { __newindex = function() error("attempt to mutate textutils.empty_json_array", 2) - end + end, }) local function serializeJSONImpl( t, tTracking, bNBTStyle ) @@ -264,7 +264,7 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) local sArrayResult = "[" local nObjectSize = 0 local nArraySize = 0 - for k,v in pairs(t) do + for k, v in pairs(t) do if type(k) == "string" then local sEntry if bNBTStyle then @@ -280,7 +280,7 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) nObjectSize = nObjectSize + 1 end end - for _,v in ipairs(t) do + for _, v in ipairs(t) do local sEntry = serializeJSONImpl( v, tTracking, bNBTStyle ) if nArraySize == 0 then sArrayResult = sArrayResult .. sEntry @@ -305,7 +305,7 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) return tostring(t) else - error( "Cannot serialize type "..sType, 0 ) + error( "Cannot serialize type " .. sType, 0 ) end end @@ -317,7 +317,7 @@ end function unserialize( s ) expect(1, s, "string") - local func = load( "return "..s, "unserialize", "t", {} ) + local func = load( "return " .. s, "unserialize", "t", {} ) if func then local ok, result = pcall( func ) if ok then @@ -346,7 +346,7 @@ function urlEncode( str ) else -- Non-ASCII (encode as UTF-8) return - string.format("%%%02X", 192 + bit32.band( bit32.arshift(n,6), 31 ) ) .. + string.format("%%%02X", 192 + bit32.band( bit32.arshift(n, 6), 31 ) ) .. string.format("%%%02X", 128 + bit32.band( n, 63 ) ) end end ) @@ -393,7 +393,7 @@ function complete( sSearchText, tSearchTable ) local tResults = {} local tSeen = {} while tTable do - for k,v in pairs( tTable ) do + for k, v in pairs( tTable ) do if not tSeen[k] and type(k) == "string" then if string.find( k, sPart, 1, true ) == 1 then if not g_tLuaKeywords[k] and string.match( k, "^[%a_][%a%d_]*$" ) then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua index 069f73b8d..c471212a4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua @@ -20,7 +20,7 @@ end -- Put commands into environment table local env = _ENV -for k,v in pairs( native ) do +for k, v in pairs( native ) do if k == "equipLeft" or k == "equipRight" then env[k] = function( ... ) local result, err = v( ... ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua index 7a6db14b7..4d6c159f9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua @@ -36,17 +36,17 @@ local vector = { ) end, dot = function( self, o ) - return self.x*o.x + self.y*o.y + self.z*o.z + return self.x * o.x + self.y * o.y + self.z * o.z end, cross = function( self, o ) return vector.new( - self.y*o.z - self.z*o.y, - self.z*o.x - self.x*o.z, - self.x*o.y - self.y*o.x + self.y * o.z - self.z * o.y, + self.z * o.x - self.x * o.z, + self.x * o.y - self.y * o.x ) end, length = function( self ) - return math.sqrt( self.x*self.x + self.y*self.y + self.z*self.z ) + return math.sqrt( self.x * self.x + self.y * self.y + self.z * self.z ) end, normalize = function( self ) return self:mul( 1 / self:length() ) @@ -60,7 +60,7 @@ local vector = { ) end, tostring = function( self ) - return self.x..","..self.y..","..self.z + return self.x .. "," .. self.y .. "," .. self.z end, } @@ -78,7 +78,7 @@ function new( x, y, z ) local v = { x = tonumber(x) or 0, y = tonumber(y) or 0, - z = tonumber(z) or 0 + z = tonumber(z) or 0, } setmetatable( v, vmetatable ) return v diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 2f20220fc..0e24b7696 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -39,8 +39,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local tEmptyColorLines = {} local function createEmptyLines( nWidth ) sEmptySpaceLine = string_rep( " ", nWidth ) - for n=0,15 do - local nColor = 2^n + for n = 0, 15 do + local nColor = 2 ^ n local sHex = tHex[nColor] tEmptyColorLines[nColor] = string_rep( sHex, nWidth ) end @@ -61,7 +61,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local sEmptyText = sEmptySpaceLine local sEmptyTextColor = tEmptyColorLines[ nTextColor ] local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - for y=1,nHeight do + for y = 1, nHeight do tLines[y] = { text = sEmptyText, textColor = sEmptyTextColor, @@ -69,7 +69,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) } end - for i=0,15 do + for i = 0, 15 do local c = 2 ^ i tPalette[c] = { parent.getPaletteColour( c ) } end @@ -100,13 +100,13 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end local function redraw() - for n=1,nHeight do + for n = 1, nHeight do redrawLine( n ) end end local function updatePalette() - for k,v in pairs( tPalette ) do + for k, v in pairs( tPalette ) do parent.setPaletteColour( k, v[1], v[2], v[3] ) end end @@ -204,7 +204,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local sEmptyText = sEmptySpaceLine local sEmptyTextColor = tEmptyColorLines[ nTextColor ] local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - for y=1,nHeight do + for y = 1, nHeight do tLines[y] = { text = sEmptyText, textColor = sEmptyTextColor, @@ -351,7 +351,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local sEmptyText = sEmptySpaceLine local sEmptyTextColor = tEmptyColorLines[ nTextColor ] local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - for newY=1,nHeight do + for newY = 1, nHeight do local y = newY + n if y >= 1 and y <= nHeight then tNewLines[newY] = tLines[y] @@ -451,12 +451,12 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local sEmptyText = sEmptySpaceLine local sEmptyTextColor = tEmptyColorLines[ nTextColor ] local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - for y=1,nNewHeight do + for y = 1, nNewHeight do if y > nHeight then tNewLines[y] = { text = sEmptyText, textColor = sEmptyTextColor, - backgroundColor = sEmptyBackgroundColor + backgroundColor = sEmptyBackgroundColor, } else local tOldLine = tLines[y] diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index b07cccf3c..757691e27 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -2,7 +2,7 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect -- Setup process switching local parentTerm = term.current() -local w,h = parentTerm.getSize() +local w, h = parentTerm.getSize() local tProcesses = {} local nCurrentProcess = nil @@ -55,7 +55,7 @@ local function launchProcess( bFocus, tProgramEnv, sProgramPath, ... ) local tProcess = {} tProcess.sTitle = fs.getName( sProgramPath ) if bShowMenu then - tProcess.window = window.create( parentTerm, 1, 2, w, h-1, false ) + tProcess.window = window.create( parentTerm, 1, 2, w, h - 1, false ) else tProcess.window = window.create( parentTerm, 1, 1, w, h, false ) end @@ -102,7 +102,7 @@ end local function cullProcesses() local culled = false - for n=#tProcesses,1,-1 do + for n = #tProcesses, 1, -1 do culled = culled or cullProcess( n ) end return culled @@ -132,7 +132,7 @@ local function redrawMenu() parentTerm.write( "<" ) nCharCount = 1 end - for n=nScrollPos,#tProcesses do + for n = nScrollPos, #tProcesses do if n == nCurrentProcess then parentTerm.setTextColor( menuMainTextColor ) parentTerm.setBackgroundColor( menuMainBgColor ) @@ -165,14 +165,14 @@ local function resizeWindows() local windowY, windowHeight if bShowMenu then windowY = 2 - windowHeight = h-1 + windowHeight = h - 1 else windowY = 1 windowHeight = h end - for n=1,#tProcesses do + for n = 1, #tProcesses do local tProcess = tProcesses[n] - local x,y = tProcess.window.getCursorPos() + local x, y = tProcess.window.getCursorPos() if y > windowHeight then tProcess.window.scroll( y - windowHeight ) tProcess.window.setCursorPos( x, windowHeight ) @@ -257,7 +257,7 @@ while #tProcesses > 0 do local sEvent = tEventData[1] if sEvent == "term_resize" then -- Resize event - w,h = parentTerm.getSize() + w, h = parentTerm.getSize() resizeWindows() redrawMenu() @@ -286,7 +286,7 @@ while #tProcesses > 0 do if nScrollPos ~= 1 then tabStart = 2 end - for n=nScrollPos,#tProcesses do + for n = nScrollPos, #tProcesses do local tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1 if x >= tabStart and x <= tabEnd then selectProcess( n ) @@ -298,7 +298,7 @@ while #tProcesses > 0 do end else -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, button, x, bShowMenu and y-1 or y ) + resumeProcess( nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y ) if cullProcess( nCurrentProcess ) then setMenuVisible( #tProcesses >= 2 ) redrawMenu() @@ -318,7 +318,7 @@ while #tProcesses > 0 do end elseif not (bShowMenu and y == 1) then -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, p1, x, bShowMenu and y-1 or y ) + resumeProcess( nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y ) if cullProcess( nCurrentProcess ) then setMenuVisible( #tProcesses >= 2 ) redrawMenu() @@ -329,7 +329,7 @@ while #tProcesses > 0 do -- Other event -- Passthrough to all processes local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event - for n=1,nLimit do + for n = 1, nLimit do resumeProcess( n, table.unpack( tEventData, 1, tEventData.n ) ) end if cullProcesses() then @@ -341,7 +341,7 @@ while #tProcesses > 0 do if bWindowsResized then -- Pass term_resize to all processes local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event - for n=1,nLimit do + for n = 1, nLimit do resumeProcess( n, "term_resize" ) end bWindowsResized = false diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua b/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua index 6d7c3ff99..c4f8c5ffe 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua @@ -19,7 +19,7 @@ else local tAliases = shell.aliases() local tList = {} for sAlias, sCommand in pairs( tAliases ) do - table.insert( tList, sAlias..":"..sCommand ) + table.insert( tList, sAlias .. ":" .. sCommand ) end table.sort( tList ) textutils.pagedTabulate( tList ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua b/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua index 9a734d891..7ef16e96f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua @@ -1,6 +1,6 @@ local tApis = {} -for k,v in pairs( _G ) do +for k, v in pairs( _G ) do if type(k) == "string" and type(v) == "table" and k ~= "_G" then table.insert( tApis, k ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua b/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua index 76aebc086..c54b3f567 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua @@ -18,7 +18,7 @@ local function printSuccess( text ) end local sCommand = string.lower( tArgs[1] ) -for n=2,#tArgs do +for n = 2, #tArgs do sCommand = sCommand .. " " .. tArgs[n] end @@ -26,14 +26,14 @@ local bResult, tOutput = commands.exec( sCommand ) if bResult then printSuccess( "Success" ) if #tOutput > 0 then - for n=1,#tOutput do + for n = 1, #tOutput do print( tOutput[n] ) end end else printError( "Failed" ) if #tOutput > 0 then - for n=1,#tOutput do + for n = 1, #tOutput do print( tOutput[n] ) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua index 71ea68043..c8d66459b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua @@ -9,7 +9,7 @@ local sSource = shell.resolve( tArgs[1] ) local sDest = shell.resolve( tArgs[2] ) local tFiles = fs.find( sSource ) if #tFiles > 0 then - for _,sFile in ipairs( tFiles ) do + for _, sFile in ipairs( tFiles ) do if fs.isDir( sDest ) then fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) ) elseif #tFiles == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index 2d7d9357e..bfa682843 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -21,9 +21,9 @@ if not fs.exists( sPath ) and not string.find( sPath, "%." ) then end end -local x,y = 1,1 -local w,h = term.getSize() -local scrollX, scrollY = 0,0 +local x, y = 1, 1 +local w, h = term.getSize() +local scrollX, scrollY = 0, 0 local tLines = {} local bRunning = true @@ -99,7 +99,7 @@ local function save( _sPath ) file.write( sLine .. "\n" ) end else - error( "Failed to open ".._sPath ) + error( "Failed to open " .. _sPath ) end end @@ -130,7 +130,7 @@ local tKeywords = { ["return"] = true, ["then"] = true, ["true"] = true, - ["until"]= true, + ["until"] = true, ["while"] = true, } @@ -214,7 +214,7 @@ end local function redrawText() local cursorX, cursorY = x, y - for y=1,h-1 do + for y = 1, h - 1 do term.setCursorPos( 1 - scrollX, y ) term.clearLine() @@ -248,7 +248,7 @@ local function redrawMenu() term.clearLine() -- Draw line numbers - term.setCursorPos( w - string.len( "Ln "..y ) + 1, h ) + term.setCursorPos( w - string.len( "Ln " .. y ) + 1, h ) term.setTextColour( highlightColour ) term.write( "Ln " ) term.setTextColour( textColour ) @@ -258,7 +258,7 @@ local function redrawMenu() if bMenu then -- Draw menu term.setTextColour( textColour ) - for nItem,sItem in pairs( tMenuItems ) do + for nItem, sItem in pairs( tMenuItems ) do if nItem == nMenuItem then term.setTextColour( highlightColour ) term.write( "[" ) @@ -268,7 +268,7 @@ local function redrawMenu() term.write( "]" ) term.setTextColour( textColour ) else - term.write( " "..sItem.." " ) + term.write( " " .. sItem .. " " ) end end else @@ -289,12 +289,12 @@ local tMenuFuncs = { else local ok, _, fileerr = save( sPath ) if ok then - sStatus="Saved to "..sPath + sStatus = "Saved to " .. sPath else if fileerr then - sStatus="Error saving to "..fileerr + sStatus = "Error saving to " .. fileerr else - sStatus="Error saving to "..sPath + sStatus = "Error saving to " .. sPath end end end @@ -326,7 +326,7 @@ local tMenuFuncs = { } printerTerminal.scroll = function() if nPage == 1 then - printer.setPageTitle( sName.." (page "..nPage..")" ) + printer.setPageTitle( sName .. " (page " .. nPage .. ")" ) end while not printer.newPage() do @@ -349,7 +349,7 @@ local tMenuFuncs = { if nPage == 1 then printer.setPageTitle( sName ) else - printer.setPageTitle( sName.." (page "..nPage..")" ) + printer.setPageTitle( sName .. " (page " .. nPage .. ")" ) end end @@ -374,7 +374,7 @@ local tMenuFuncs = { bMenu = true if nPage > 1 then - sStatus = "Printed "..nPage.." Pages" + sStatus = "Printed " .. nPage .. " Pages" else sStatus = "Printed 1 Page" end @@ -391,14 +391,14 @@ local tMenuFuncs = { if nTask then shell.switchTab( nTask ) else - sStatus="Error starting Task" + sStatus = "Error starting Task" end fs.delete( sTempPath ) else - sStatus="Error saving to "..sTempPath + sStatus = "Error saving to " .. sTempPath end redrawMenu() - end + end, } local function doMenuItem( _n ) @@ -431,9 +431,9 @@ local function setCursor( newX, newY ) scrollY = y - 1 screenY = 1 bRedraw = true - elseif screenY > h-1 then - scrollY = y - (h-1) - screenY = h-1 + elseif screenY > h - 1 then + scrollY = y - (h - 1) + screenY = h - 1 bRedraw = true end @@ -456,7 +456,7 @@ load(sPath) term.setBackgroundColour( bgColour ) term.clear() -term.setCursorPos(x,y) +term.setCursorPos(x, y) term.setCursorBlink( true ) recomplete() @@ -526,7 +526,7 @@ while bRunning do else -- Indent line local sLine = tLines[y] - tLines[y] = string.sub(sLine,1,x-1) .. " " .. string.sub(sLine,x) + tLines[y] = string.sub(sLine, 1, x - 1) .. " " .. string.sub(sLine, x) setCursor( x + 4, y ) end end @@ -566,7 +566,7 @@ while bRunning do if not bMenu then -- Move cursor to the beginning if x > 1 then - setCursor(1,y) + setCursor(1, y) end end @@ -586,8 +586,8 @@ while bRunning do if x > 1 then -- Move cursor left setCursor( x - 1, y ) - elseif x==1 and y>1 then - setCursor( string.len( tLines[y-1] ) + 1, y - 1 ) + elseif x == 1 and y > 1 then + setCursor( string.len( tLines[y - 1] ) + 1, y - 1 ) end else -- Move menu left @@ -608,7 +608,7 @@ while bRunning do elseif nCompletion and x == string.len(tLines[y]) + 1 then -- Accept autocomplete acceptCompletion() - elseif x==nLimit and y<#tLines then + elseif x == nLimit and y < #tLines then -- Go to next line setCursor( 1, y + 1 ) end @@ -627,12 +627,12 @@ while bRunning do local nLimit = string.len( tLines[y] ) + 1 if x < nLimit then local sLine = tLines[y] - tLines[y] = string.sub(sLine,1,x-1) .. string.sub(sLine,x+1) + tLines[y] = string.sub(sLine, 1, x - 1) .. string.sub(sLine, x + 1) recomplete() redrawLine(y) - elseif y<#tLines then - tLines[y] = tLines[y] .. tLines[y+1] - table.remove( tLines, y+1 ) + elseif y < #tLines then + tLines[y] = tLines[y] .. tLines[y + 1] + table.remove( tLines, y + 1 ) recomplete() redrawText() end @@ -644,17 +644,17 @@ while bRunning do if x > 1 then -- Remove character local sLine = tLines[y] - if x > 4 and string.sub(sLine,x-4,x-1) == " " and not string.sub(sLine, 1, x - 1):find("%S") then - tLines[y] = string.sub(sLine,1,x-5) .. string.sub(sLine,x) + if x > 4 and string.sub(sLine, x - 4, x - 1) == " " and not string.sub(sLine, 1, x - 1):find("%S") then + tLines[y] = string.sub(sLine, 1, x - 5) .. string.sub(sLine, x) setCursor( x - 4, y ) else - tLines[y] = string.sub(sLine,1,x-2) .. string.sub(sLine,x) + tLines[y] = string.sub(sLine, 1, x - 2) .. string.sub(sLine, x) setCursor( x - 1, y ) end elseif y > 1 then -- Remove newline - local sPrevLen = string.len( tLines[y-1] ) - tLines[y-1] = tLines[y-1] .. tLines[y] + local sPrevLen = string.len( tLines[y - 1] ) + tLines[y - 1] = tLines[y - 1] .. tLines[y] table.remove( tLines, y ) setCursor( sPrevLen + 1, y - 1 ) redrawText() @@ -666,12 +666,12 @@ while bRunning do if not bMenu and not bReadOnly then -- Newline local sLine = tLines[y] - local _,spaces=string.find(sLine,"^[ ]+") + local _, spaces = string.find(sLine, "^[ ]+") if not spaces then - spaces=0 + spaces = 0 end - tLines[y] = string.sub(sLine,1,x-1) - table.insert( tLines, y+1, string.rep(' ',spaces)..string.sub(sLine,x) ) + tLines[y] = string.sub(sLine, 1, x - 1) + table.insert( tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x) ) setCursor( spaces + 1, y + 1 ) redrawText() @@ -697,13 +697,13 @@ while bRunning do if not bMenu and not bReadOnly then -- Input text local sLine = tLines[y] - tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x) + tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) setCursor( x + 1, y ) elseif bMenu then -- Select menu items - for n,sMenuItem in ipairs( tMenuItems ) do - if string.lower(string.sub(sMenuItem,1,1)) == string.lower(param) then + for n, sMenuItem in ipairs( tMenuItems ) do + if string.lower(string.sub(sMenuItem, 1, 1)) == string.lower(param) then doMenuItem( n ) break end @@ -720,7 +720,7 @@ while bRunning do end -- Input text local sLine = tLines[y] - tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x) + tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) setCursor( x + string.len( param ), y ) end @@ -728,7 +728,7 @@ while bRunning do if not bMenu then if param == 1 then -- Left click - local cx,cy = param2, param3 + local cx, cy = param2, param3 if cy < h then local newY = math.min( math.max( scrollY + cy, 1 ), #tLines ) local newX = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[newY] ) + 1 ) @@ -749,7 +749,7 @@ while bRunning do elseif param == 1 then -- Scroll down - local nMaxScroll = #tLines - (h-1) + local nMaxScroll = #tLines - (h - 1) if scrollY < nMaxScroll then -- Move cursor down scrollY = scrollY + 1 @@ -760,7 +760,7 @@ while bRunning do end elseif sEvent == "term_resize" then - w,h = term.getSize() + w, h = term.getSize() setCursor( x, y ) redrawMenu() redrawText() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua b/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua index 1e0e8b7af..ad47bbd99 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua @@ -11,7 +11,7 @@ local sDrive = tArgs[1] -- Check the disk exists local bPresent = disk.isPresent( sDrive ) if not bPresent then - print( "Nothing in "..sDrive.." drive" ) + print( "Nothing in " .. sDrive .. " drive" ) return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index 5011458ca..2e77847e0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -6,7 +6,7 @@ ------------ -- The width and height of the terminal -local w,h = term.getSize() +local w, h = term.getSize() -- The selected colours on the left and right mouse button, and the colour of the canvas local leftColour, rightColour = colours.white, nil @@ -16,7 +16,7 @@ local canvasColour = colours.black local canvas = {} -- The menu options -local mChoices = { "Save","Exit" } +local mChoices = { "Save", "Exit" } -- The message displayed in the footer bar local fMessage = "Press Ctrl to access menu" @@ -86,8 +86,8 @@ end returns: the colour number of the hex value ]] local tColourLookup = {} -for n=1,16 do - tColourLookup[ string.byte( "0123456789abcdef",n,n ) ] = 2^(n-1) +for n = 1, 16 do + tColourLookup[ string.byte( "0123456789abcdef", n, n ) ] = 2 ^ (n - 1) end local function getColourOf( char ) -- Values not in the hex table are transparent (canvas coloured) @@ -106,8 +106,8 @@ local function load(path) local sLine = file.readLine() while sLine do local line = {} - for x=1,w-2 do - line[x] = getColourOf( string.byte(sLine,x,x) ) + for x = 1, w - 2 do + line[x] = getColourOf( string.byte(sLine, x, x) ) end table.insert( canvas, line ) sLine = file.readLine() @@ -136,10 +136,10 @@ local function save(path) -- Encode (and trim) local tLines = {} local nLastLine = 0 - for y=1,h-1 do + for y = 1, h - 1 do local sLine = "" local nLastChar = 0 - for x=1,w-2 do + for x = 1, w - 2 do local c = getCharOf( getCanvasPixel( x, y ) ) sLine = sLine .. c if c ~= " " then @@ -154,7 +154,7 @@ local function save(path) end -- Save out - for n=1,nLastLine do + for n = 1, nLastLine do file.writeLine( tLines[ n ] ) end file.close() @@ -174,20 +174,20 @@ local function drawInterface() term.write(fMessage) -- Colour Picker - for i=1,16 do - term.setCursorPos(w-1, i) - term.setBackgroundColour( 2^(i-1) ) + for i = 1, 16 do + term.setCursorPos(w - 1, i) + term.setBackgroundColour( 2 ^ (i - 1) ) term.write(" ") end - term.setCursorPos(w-1, 17) + term.setCursorPos(w - 1, 17) term.setBackgroundColour( canvasColour ) term.setTextColour( colours.grey ) term.write("\127\127") -- Left and Right Selected Colours do - term.setCursorPos(w-1, 18) + term.setCursorPos(w - 1, 18) if leftColour ~= nil then term.setBackgroundColour( leftColour ) term.write(" ") @@ -208,8 +208,8 @@ local function drawInterface() -- Padding term.setBackgroundColour( canvasColour ) - for i=20,h-1 do - term.setCursorPos(w-1, i) + for i = 20, h - 1 do + term.setCursorPos(w - 1, i) term.write(" ") end end @@ -237,7 +237,7 @@ end returns: nil ]] local function drawCanvasLine( y ) - for x = 1, w-2 do + for x = 1, w - 2 do drawCanvasPixel( x, y ) end end @@ -247,7 +247,7 @@ end returns: nil ]] local function drawCanvas() - for y = 1, h-1 do + for y = 1, h - 1 do drawCanvasLine( y ) end end @@ -263,25 +263,25 @@ local function accessMenu() term.setBackgroundColour(colours.black) while true do -- Draw the menu - term.setCursorPos(1,h) + term.setCursorPos(1, h) term.clearLine() term.setTextColour(colours.white) - for k,v in pairs(mChoices) do - if selection==k then + for k, v in pairs(mChoices) do + if selection == k then term.setTextColour(colours.yellow) local ox = term.getCursorPos() - term.write("["..string.rep(" ",#v).."]") - term.setCursorPos(ox+1,h) + term.write("[" .. string.rep(" ", #v) .. "]") + term.setCursorPos(ox + 1, h) term.setTextColour(colours.white) term.write(v) - term.setCursorPos(term.getCursorPos()+1,h) + term.setCursorPos(term.getCursorPos() + 1, h) else - term.write(" "..v.." ") + term.write(" " .. v .. " ") end end -- Handle input in the menu - local id,key = os.pullEvent("key") + local id, key = os.pullEvent("key") if id == "key" then -- S and E are shortcuts if key == keys.s then @@ -308,23 +308,23 @@ local function accessMenu() elseif key == keys.enter then -- Select an option - if mChoices[selection]=="Save" then + if mChoices[selection] == "Save" then if bReadOnly then fMessage = "Access denied" return false end local success, err = save(sPath) if success then - fMessage = "Saved to "..sPath + fMessage = "Saved to " .. sPath else if err then - fMessage = "Error saving to "..err + fMessage = "Error saving to " .. err else - fMessage = "Error saving to "..sPath + fMessage = "Error saving to " .. sPath end end return false - elseif mChoices[selection]=="Exit" then + elseif mChoices[selection] == "Exit" then return true end elseif key == keys.leftCtrl or keys == keys.rightCtrl then @@ -343,19 +343,19 @@ end local function handleEvents() local programActive = true while programActive do - local id,p1,p2,p3 = os.pullEvent() - if id=="mouse_click" or id=="mouse_drag" then - if p2 >= w-1 and p3 >= 1 and p3 <= 17 then + local id, p1, p2, p3 = os.pullEvent() + if id == "mouse_click" or id == "mouse_drag" then + if p2 >= w - 1 and p3 >= 1 and p3 <= 17 then if id ~= "mouse_drag" then -- Selecting an items in the colour picker if p3 <= 16 then - if p1==1 then - leftColour = 2^(p3-1) + if p1 == 1 then + leftColour = 2 ^ (p3 - 1) else - rightColour = 2^(p3-1) + rightColour = 2 ^ (p3 - 1) end else - if p1==1 then + if p1 == 1 then leftColour = nil else rightColour = nil @@ -364,12 +364,12 @@ local function handleEvents() --drawCanvas() drawInterface() end - elseif p2 < w-1 and p3 <= h-1 then + elseif p2 < w - 1 and p3 <= h - 1 then -- Clicking on the canvas local paintColour = nil - if p1==1 then + if p1 == 1 then paintColour = leftColour - elseif p1==2 then + elseif p1 == 2 then paintColour = rightColour end if not canvas[p3] then @@ -379,13 +379,13 @@ local function handleEvents() drawCanvasPixel( p2, p3 ) end - elseif id=="key" then - if p1==keys.leftCtrl or p1==keys.rightCtrl then + elseif id == "key" then + if p1 == keys.leftCtrl or p1 == keys.rightCtrl then programActive = not accessMenu() drawInterface() end - elseif id=="term_resize" then - w,h = term.getSize() + elseif id == "term_resize" then + w, h = term.getSize() drawCanvas() drawInterface() end @@ -404,4 +404,4 @@ handleEvents() term.setBackgroundColour(colours.black) term.setTextColour(colours.white) term.clear() -term.setCursorPos(1,1) +term.setCursorPos(1, 1) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua index 232f6d863..a84117bdb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua @@ -3,12 +3,12 @@ --Clearing Screen-- --Vars-- -local TermW,TermH = term.getSize() +local TermW, TermH = term.getSize() local sLevelTitle local tScreen local oScreen -local SizeW,SizeH +local SizeW, SizeH local aExits local fExit local nSpeed @@ -18,14 +18,14 @@ local fSpeedS local bPaused local Tick local Blocks -local XOrgin,YOrgin +local XOrgin, YOrgin local fLevel local function reset() sLevelTitle = "" tScreen = {} oScreen = {} - SizeW,SizeH = TermW,TermH + SizeW, SizeH = TermW, TermH aExits = 0 fExit = "nop" nSpeed = 0.6 @@ -35,7 +35,7 @@ local function reset() bPaused = false Tick = os.startTimer(Speed) Blocks = 0 - XOrgin,YOrgin = 1,1 + XOrgin, YOrgin = 1, 1 term.setBackgroundColor(colors.black) term.setTextColor(colors.white) @@ -61,21 +61,21 @@ local tArgs = { ... } --Functions-- local function printCentred( yc, stg ) local xc = math.floor((TermW - string.len(stg)) / 2) + 1 - term.setCursorPos(xc,yc) + term.setCursorPos(xc, yc) term.write( stg ) end local function centerOrgin() - XOrgin = math.floor(TermW/2-SizeW/2) - YOrgin = math.floor(TermH/2-SizeH/2) + XOrgin = math.floor(TermW / 2 - SizeW / 2) + YOrgin = math.floor(TermH / 2 - SizeH / 2) end local function reMap() tScreen = nil tScreen = {} - for x=1,SizeW do + for x = 1, SizeW do tScreen[x] = {} - for y=1,SizeH do + for y = 1, SizeH do tScreen[x][y] = { space = true, wall = false, ground = false, robot = "zz", start = "zz", exit = "zz" } end end @@ -83,7 +83,7 @@ end local function tablecopy(t) local t2 = {} - for k,v in pairs(t) do + for k, v in pairs(t) do t2[k] = v end return t2 @@ -92,17 +92,17 @@ end local function buMap() oScreen = nil oScreen = {} - for x=1,SizeW do + for x = 1, SizeW do oScreen[x] = {} - for y=1,SizeH do + for y = 1, SizeH do oScreen[x][y] = tablecopy(tScreen[x][y]) end end end -local function addRobot(x,y,side,color) +local function addRobot(x, y, side, color) local obj = tScreen[x][y] - local data = side..color + local data = side .. color if obj.wall == nil and obj.robot == nil then tScreen[x][y].robot = data else @@ -112,9 +112,9 @@ local function addRobot(x,y,side,color) end end -local function addStart(x,y,side,color) +local function addStart(x, y, side, color) local obj = tScreen[x][y] - local data = side..color + local data = side .. color if obj.wall == nil and obj.space == nil then tScreen[x][y].start = data else @@ -122,10 +122,10 @@ local function addStart(x,y,side,color) obj.space = nil tScreen[x][y].start = data end - aExits = aExits+1 + aExits = aExits + 1 end -local function addGround(x,y) +local function addGround(x, y) local obj = tScreen[x][y] if obj.space == nil and obj.exit == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then tScreen[x][y].ground = true @@ -139,7 +139,7 @@ local function addGround(x,y) end end -local function addExit(x,y,cl) +local function addExit(x, y, cl) local obj = tScreen[x][y] if obj.space == nil and obj.ground == nil and obj.wall == nil and obj.robot == nil and obj.start == nil then tScreen[x][y].exit = cl @@ -153,10 +153,10 @@ local function addExit(x,y,cl) end end -local function addWall(x,y) +local function addWall(x, y) local obj = tScreen[x][y] if obj == nil then - return error("Here X"..x.." Y"..y) + return error("Here X" .. x .. " Y" .. y) end if obj.space == nil and obj.exit == nil and obj.ground == nil and obj.robot == nil and obj.start == nil then tScreen[x][y].wall = true @@ -171,15 +171,15 @@ local function addWall(x,y) end local function loadLevel(nNum) - sLevelTitle = "Level "..nNum + sLevelTitle = "Level " .. nNum if nNum == nil then return error("nNum == nil") end local sDir = fs.getDir( shell.getRunningProgram() ) - local sLevelD = sDir .. "/levels/" .. tostring(nNum)..".dat" - if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error("Level Not Exists : "..sLevelD) end - fLevel = fs.open(sLevelD,"r") + local sLevelD = sDir .. "/levels/" .. tostring(nNum) .. ".dat" + if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error("Level Not Exists : " .. sLevelD) end + fLevel = fs.open(sLevelD, "r") local wl = true - Blocks = tonumber(string.sub(fLevel.readLine(),1,1)) - local xSize = string.len(fLevel.readLine())+2 + Blocks = tonumber(string.sub(fLevel.readLine(), 1, 1)) + local xSize = string.len(fLevel.readLine()) + 2 local Lines = 3 while wl do local wLine = fLevel.readLine() @@ -187,43 +187,43 @@ local function loadLevel(nNum) fLevel.close() wl = false else - xSize = math.max(string.len(wLine)+2,xSize) + xSize = math.max(string.len(wLine) + 2, xSize) Lines = Lines + 1 end end - SizeW,SizeH = xSize,Lines + SizeW, SizeH = xSize, Lines reMap() - fLevel = fs.open(sLevelD,"r") + fLevel = fs.open(sLevelD, "r") fLevel.readLine() - for Line=2,Lines-1 do + for Line = 2, Lines - 1 do local sLine = fLevel.readLine() local chars = string.len(sLine) for char = 1, chars do - local el = string.sub(sLine,char,char) + local el = string.sub(sLine, char, char) if el == "8" then - addGround(char+1,Line) + addGround(char + 1, Line) elseif el == "0" then - addStart(char+1,Line,"a","a") + addStart(char + 1, Line, "a", "a") elseif el == "1" then - addStart(char+1,Line,"b","a") + addStart(char + 1, Line, "b", "a") elseif el == "2" then - addStart(char+1,Line,"c","a") + addStart(char + 1, Line, "c", "a") elseif el == "3" then - addStart(char+1,Line,"d","a") + addStart(char + 1, Line, "d", "a") elseif el == "4" then - addStart(char+1,Line,"a","b") + addStart(char + 1, Line, "a", "b") elseif el == "5" then - addStart(char+1,Line,"b","b") + addStart(char + 1, Line, "b", "b") elseif el == "6" then - addStart(char+1,Line,"c","b") + addStart(char + 1, Line, "c", "b") elseif el == "9" then - addStart(char+1,Line,"d","b") + addStart(char + 1, Line, "d", "b") elseif el == "b" then - addExit(char+1,Line,"a") + addExit(char + 1, Line, "a") elseif el == "e" then - addExit(char+1,Line,"b") + addExit(char + 1, Line, "b") elseif el == "7" then - addWall(char+1,Line) + addWall(char + 1, Line) end end end @@ -232,29 +232,29 @@ end local function drawStars() --CCR Background By : RamiLego-- - local cStar,cStarG,crStar,crStarB = colors.lightGray,colors.gray,".","*" - local DStar,BStar,nStar,gStar = 14,10,16,3 - local TermW,TermH = term.getSize() + local cStar, cStarG, crStar, crStarB = colors.lightGray, colors.gray, ".", "*" + local DStar, BStar, nStar, gStar = 14, 10, 16, 3 + local TermW, TermH = term.getSize() term.clear() - term.setCursorPos(1,1) - for x=1,TermW do - for y=1,TermH do - local StarT = math.random(1,30) + term.setCursorPos(1, 1) + for x = 1, TermW do + for y = 1, TermH do + local StarT = math.random(1, 30) if StarT == DStar then - term.setCursorPos(x,y) + term.setCursorPos(x, y) term.setTextColor(cStar) write(crStar) elseif StarT == BStar then - term.setCursorPos(x,y) + term.setCursorPos(x, y) term.setTextColor(cStar) write(crStarB) elseif StarT == nStar then - term.setCursorPos(x,y) + term.setCursorPos(x, y) term.setTextColor(cStarG) write(crStar) elseif StarT == gStar then - term.setCursorPos(x,y) + term.setCursorPos(x, y) term.setTextColor(cStarG) write(crStarB) end @@ -263,15 +263,15 @@ local function drawStars() end local function drawMap() - for x=1,SizeW do - for y=1,SizeH do + for x = 1, SizeW do + for y = 1, SizeH do local obj = tScreen[x][y] if obj.ground == true then - paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cG) + paintutils.drawPixel(XOrgin + x, YOrgin + y + 1, cG) end if obj.wall == true then - paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cW) + paintutils.drawPixel(XOrgin + x, YOrgin + y + 1, cW) end local ex = tostring(tScreen[x][y].exit) @@ -289,13 +289,13 @@ local function drawMap() end term.setBackgroundColor(cG) term.setTextColor(ex) - term.setCursorPos(XOrgin+x,YOrgin+y+1) + term.setCursorPos(XOrgin + x, YOrgin + y + 1) print("X") end local st = tostring(tScreen[x][y].start) if not(st == "zz" or st == "nil") then - local Cr = string.sub(st,2,2) + local Cr = string.sub(st, 2, 2) if Cr == "a" then Cr = cR1 elseif Cr == "b" then @@ -310,9 +310,9 @@ local function drawMap() term.setTextColor(Cr) term.setBackgroundColor(cG) - term.setCursorPos(XOrgin+x,YOrgin+y+1) + term.setCursorPos(XOrgin + x, YOrgin + y + 1) - local sSide = string.sub(st,1,1) + local sSide = string.sub(st, 1, 1) if sSide == "a" then print("^") elseif sSide == "b" then @@ -327,12 +327,12 @@ local function drawMap() end if obj.space == true then - paintutils.drawPixel(XOrgin+x,YOrgin+y+1,cS) + paintutils.drawPixel(XOrgin + x, YOrgin + y + 1, cS) end local rb = tostring(tScreen[x][y].robot) if not(rb == "zz" or rb == "nil") then - local Cr = string.sub(rb,2,2) + local Cr = string.sub(rb, 2, 2) if Cr == "a" then Cr = cR1 elseif Cr == "b" then @@ -346,8 +346,8 @@ local function drawMap() end term.setBackgroundColor(Cr) term.setTextColor(colors.white) - term.setCursorPos(XOrgin+x,YOrgin+y+1) - local sSide = string.sub(rb,1,1) + term.setCursorPos(XOrgin + x, YOrgin + y + 1) + local sSide = string.sub(rb, 1, 1) if sSide == "a" then print("^") elseif sSide == "b" then @@ -364,7 +364,7 @@ local function drawMap() end end -local function isBrick(x,y) +local function isBrick(x, y) local brb = tostring(tScreen[x][y].robot) local bobj = oScreen[x][y] if (brb == "zz" or brb == "nil") and not bobj.wall == true then @@ -376,134 +376,134 @@ end local function gRender(sContext) if sContext == "start" then - for x=1,SizeW do - for y=1,SizeH do + for x = 1, SizeW do + for y = 1, SizeH do local st = tostring(tScreen[x][y].start) if not(st == "zz" or st == "nil") then - local Cr = string.sub(st,2,2) - local sSide = string.sub(st,1,1) - addRobot(x,y,sSide,Cr) + local Cr = string.sub(st, 2, 2) + local sSide = string.sub(st, 1, 1) + addRobot(x, y, sSide, Cr) end end end elseif sContext == "tick" then buMap() - for x=1,SizeW do - for y=1,SizeH do + for x = 1, SizeW do + for y = 1, SizeH do local rb = tostring(oScreen[x][y].robot) if not(rb == "zz" or rb == "nil") then - local Cr = string.sub(rb,2,2) - local sSide = string.sub(rb,1,1) + local Cr = string.sub(rb, 2, 2) + local sSide = string.sub(rb, 1, 1) local sobj = oScreen[x][y] if sobj.space == true then tScreen[x][y].robot = "zz" if not sSide == "g" then - addRobot(x,y,"g",Cr) + addRobot(x, y, "g", Cr) end elseif sobj.exit == Cr then if sSide == "a" or sSide == "b" or sSide == "c" or sSide == "d" then tScreen[x][y].robot = "zz" - addRobot(x,y,"g",Cr) - aExits = aExits-1 + addRobot(x, y, "g", Cr) + aExits = aExits - 1 end elseif sSide == "a" then - local obj = isBrick(x,y-1) + local obj = isBrick(x, y - 1) tScreen[x][y].robot = "zz" if not obj == true then - addRobot(x,y-1,sSide,Cr) + addRobot(x, y - 1, sSide, Cr) else - local obj2 = isBrick(x-1,y) - local obj3 = isBrick(x+1,y) + local obj2 = isBrick(x - 1, y) + local obj3 = isBrick(x + 1, y) if not obj2 == true and not obj3 == true then if Cr == "a" then - addRobot(x,y,"d",Cr) + addRobot(x, y, "d", Cr) elseif Cr == "b" then - addRobot(x,y,"b",Cr) + addRobot(x, y, "b", Cr) end elseif obj == true and obj2 == true and obj3 == true then - addRobot(x,y,"c",Cr) + addRobot(x, y, "c", Cr) else if obj3 == true then - addRobot(x,y,"d",Cr) + addRobot(x, y, "d", Cr) elseif obj2 == true then - addRobot(x,y,"b",Cr) + addRobot(x, y, "b", Cr) end end end elseif sSide == "b" then - local obj = isBrick(x+1,y) + local obj = isBrick(x + 1, y) tScreen[x][y].robot = "zz" if not obj == true then - addRobot(x+1,y,sSide,Cr) + addRobot(x + 1, y, sSide, Cr) else - local obj2 = isBrick(x,y-1) - local obj3 = isBrick(x,y+1) + local obj2 = isBrick(x, y - 1) + local obj3 = isBrick(x, y + 1) if not obj2 == true and not obj3 == true then if Cr == "a" then - addRobot(x,y,"a",Cr) + addRobot(x, y, "a", Cr) elseif Cr == "b" then - addRobot(x,y,"c",Cr) + addRobot(x, y, "c", Cr) end elseif obj == true and obj2 == true and obj3 == true then - addRobot(x,y,"d",Cr) + addRobot(x, y, "d", Cr) else if obj3 == true then - addRobot(x,y,"a",Cr) + addRobot(x, y, "a", Cr) elseif obj2 == true then - addRobot(x,y,"c",Cr) + addRobot(x, y, "c", Cr) end end end elseif sSide == "c" then - local obj = isBrick(x,y+1) + local obj = isBrick(x, y + 1) tScreen[x][y].robot = "zz" if not obj == true then - addRobot(x,y+1,sSide,Cr) + addRobot(x, y + 1, sSide, Cr) else - local obj2 = isBrick(x-1,y) - local obj3 = isBrick(x+1,y) + local obj2 = isBrick(x - 1, y) + local obj3 = isBrick(x + 1, y) if not obj2 == true and not obj3 == true then if Cr == "a" then - addRobot(x,y,"b",Cr) + addRobot(x, y, "b", Cr) elseif Cr == "b" then - addRobot(x,y,"d",Cr) + addRobot(x, y, "d", Cr) end elseif obj == true and obj2 == true and obj3 == true then - addRobot(x,y,"a",Cr) + addRobot(x, y, "a", Cr) else if obj3 == true then - addRobot(x,y,"d",Cr) + addRobot(x, y, "d", Cr) elseif obj2 == true then - addRobot(x,y,"b",Cr) + addRobot(x, y, "b", Cr) end end end elseif sSide == "d" then - local obj = isBrick(x-1,y) + local obj = isBrick(x - 1, y) tScreen[x][y].robot = "zz" if not obj == true then - addRobot(x-1,y,sSide,Cr) + addRobot(x - 1, y, sSide, Cr) else - local obj2 = isBrick(x,y-1) - local obj3 = isBrick(x,y+1) + local obj2 = isBrick(x, y - 1) + local obj3 = isBrick(x, y + 1) if not obj2 == true and not obj3 == true then if Cr == "a" then - addRobot(x,y,"c",Cr) + addRobot(x, y, "c", Cr) elseif Cr == "b" then - addRobot(x,y,"a",Cr) + addRobot(x, y, "a", Cr) end elseif obj == true and obj2 == true and obj3 == true then - addRobot(x,y,"b",Cr) + addRobot(x, y, "b", Cr) else if obj3 == true then - addRobot(x,y,"a",Cr) + addRobot(x, y, "a", Cr) elseif obj2 == true then - addRobot(x,y,"c",Cr) + addRobot(x, y, "c", Cr) end end end else - addRobot(x,y,sSide,"g") + addRobot(x, y, sSide, "g") end end end @@ -514,15 +514,15 @@ end function InterFace.drawBar() term.setBackgroundColor( colors.black ) term.setTextColor( InterFace.cTitle ) - printCentred( 1, " "..sLevelTitle.." " ) + printCentred( 1, " " .. sLevelTitle .. " " ) - term.setCursorPos(1,1) + term.setCursorPos(1, 1) term.setBackgroundColor( cW ) write( " " ) term.setBackgroundColor( colors.black ) - write( " x "..tostring(Blocks).." " ) + write( " x " .. tostring(Blocks) .. " " ) - term.setCursorPos( TermW-8,TermH ) + term.setCursorPos( TermW - 8, TermH ) term.setBackgroundColor( colors.black ) term.setTextColour(InterFace.cSpeedD) write(" <<" ) @@ -539,7 +539,7 @@ function InterFace.drawBar() end write(" >>") - term.setCursorPos( TermW-1, 1 ) + term.setCursorPos( TermW - 1, 1 ) term.setBackgroundColor( colors.black ) term.setTextColour( InterFace.cExit ) write(" X") @@ -547,13 +547,13 @@ function InterFace.drawBar() end function InterFace.render() - local id,p1,p2,p3 = os.pullEvent() + local id, p1, p2, p3 = os.pullEvent() if id == "mouse_click" then if p3 == 1 and p2 == TermW then return "end" - elseif p3 == TermH and p2 >= TermW-7 and p2 <= TermW-6 then + elseif p3 == TermH and p2 >= TermW - 7 and p2 <= TermW - 6 then return "retry" - elseif p3 == TermH and p2 >= TermW-4 and p2 <= TermW-3 then + elseif p3 == TermH and p2 >= TermW - 4 and p2 <= TermW - 3 then bPaused = not bPaused fSpeedS = false Speed = bPaused and 0 or nSpeed @@ -563,19 +563,19 @@ function InterFace.render() Tick = nil end InterFace.drawBar() - elseif p3 == TermH and p2 >= TermW-1 then + elseif p3 == TermH and p2 >= TermW - 1 then bPaused = false fSpeedS = not fSpeedS Speed = fSpeedS and fSpeed or nSpeed Tick = os.startTimer(Speed) InterFace.drawBar() - elseif p3-1 < YOrgin+SizeH+1 and p3-1 > YOrgin and - p2 < XOrgin+SizeW+1 and p2 > XOrgin then - local eobj = tScreen[p2-XOrgin][p3-YOrgin-1] - local erobj = tostring(tScreen[p2-XOrgin][p3-YOrgin-1].robot) + elseif p3 - 1 < YOrgin + SizeH + 1 and p3 - 1 > YOrgin and + p2 < XOrgin + SizeW + 1 and p2 > XOrgin then + local eobj = tScreen[p2 - XOrgin][p3 - YOrgin - 1] + local erobj = tostring(tScreen[p2 - XOrgin][p3 - YOrgin - 1].robot) if (erobj == "zz" or erobj == "nil") and not eobj.wall == true and not eobj.space == true and Blocks > 0 then - addWall(p2-XOrgin,p3-YOrgin-1) - Blocks = Blocks-1 + addWall(p2 - XOrgin, p3 - YOrgin - 1) + Blocks = Blocks - 1 InterFace.drawBar() drawMap() end @@ -635,17 +635,17 @@ if ok and not sStartLevel then term.clear() drawStars() term.setTextColor( colors.red ) - printCentred( TermH/2 - 1, " REDIRECTION " ) - printCentred( TermH/2 - 0, " ComputerCraft Edition " ) + printCentred( TermH / 2 - 1, " REDIRECTION " ) + printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) term.setTextColor( colors.yellow ) - printCentred( TermH/2 + 2, " Click to Begin " ) + printCentred( TermH / 2 + 2, " Click to Begin " ) os.pullEvent( "mouse_click" ) end ) end --Game-- if ok then - ok,err = pcall( function() + ok, err = pcall( function() local nLevel if sStartLevel then nLevel = tonumber( sStartLevel ) @@ -668,18 +668,18 @@ if ok then drawStars() term.setTextColor( colors.red ) if TermW >= 40 then - printCentred( TermH/2 - 1, " Thank you for playing Redirection " ) - printCentred( TermH/2 - 0, " ComputerCraft Edition " ) - printCentred( TermH/2 + 2, " Check out the full game: " ) + printCentred( TermH / 2 - 1, " Thank you for playing Redirection " ) + printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) + printCentred( TermH / 2 + 2, " Check out the full game: " ) term.setTextColor( colors.yellow ) - printCentred( TermH/2 + 3, " http://www.redirectiongame.com " ) + printCentred( TermH / 2 + 3, " http://www.redirectiongame.com " ) else - printCentred( TermH/2 - 2, " Thank you for " ) - printCentred( TermH/2 - 1, " playing Redirection " ) - printCentred( TermH/2 - 0, " ComputerCraft Edition " ) - printCentred( TermH/2 + 2, " Check out the full game: " ) + printCentred( TermH / 2 - 2, " Thank you for " ) + printCentred( TermH / 2 - 1, " playing Redirection " ) + printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) + printCentred( TermH / 2 + 2, " Check out the full game: " ) term.setTextColor( colors.yellow ) - printCentred( TermH/2 + 3, " www.redirectiongame.com " ) + printCentred( TermH / 2 + 3, " www.redirectiongame.com " ) end parallel.waitForAll( function() sleep(2) end, @@ -689,7 +689,7 @@ if ok then end --Clear and exit-- -term.setCursorPos(1,1) +term.setCursorPos(1, 1) term.setTextColor(colors.white) term.setBackgroundColor(colors.black) term.clear() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua index eef035301..17c2b9a2b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua @@ -112,7 +112,7 @@ local items = { desc = "A perfect handle for torches or a pickaxe.", }, ["a crafting table"] = { - aliases = { "crafting table", "craft table", "work bench", "workbench", "crafting bench", "table", }, + aliases = { "crafting table", "craft table", "work bench", "workbench", "crafting bench", "table" }, desc = "It's a crafting table. I shouldn't tell you this, but these don't actually do anything in this game, you can craft tools whenever you like.", }, ["a furnace"] = { @@ -270,7 +270,7 @@ local tAnimals = { } local tMonsters = { - "a creeper", "a skeleton", "a zombie", "a spider" + "a creeper", "a skeleton", "a zombie", "a spider", } local tRecipes = { @@ -309,8 +309,8 @@ local tGoWest = { local nGoWest = 0 local bRunning = true -local tMap = { { {}, }, } -local x,y,z = 0,0,0 +local tMap = { { {} } } +local x, y, z = 0, 0, 0 local inventory = { ["no tea"] = items["no tea"], } @@ -338,7 +338,7 @@ local tDayCycle = { } local function getTimeOfDay() - return math.fmod( math.floor(nTurn/3), #tDayCycle ) + 1 + return math.fmod( math.floor(nTurn / 3), #tDayCycle ) + 1 end local function isSunny() @@ -364,21 +364,21 @@ local function getRoom( x, y, z, dontCreate ) room.trees = hasTrees( room.nBiome ) -- Add animals - if math.random(1,3) == 1 then - for _ = 1,math.random(1,2) do + if math.random(1, 3) == 1 then + for _ = 1, math.random(1, 2) do local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ] room.items[ sAnimal ] = items[ sAnimal ] end end -- Add surface ore - if math.random(1,5) == 1 or hasStone( room.nBiome ) then + if math.random(1, 5) == 1 or hasStone( room.nBiome ) then room.items[ "some stone" ] = items[ "some stone" ] end - if math.random(1,8) == 1 then + if math.random(1, 8) == 1 then room.items[ "some coal" ] = items[ "some coal" ] end - if math.random(1,8) == 1 and hasRivers( room.nBiome ) then + if math.random(1, 8) == 1 and hasRivers( room.nBiome ) then room.items[ "a river" ] = items[ "a river" ] end @@ -389,7 +389,7 @@ local function getRoom( x, y, z, dontCreate ) ["east"] = true, ["west"] = true, } - if math.random(1,8) == 1 then + if math.random(1, 8) == 1 then room.exits["down"] = true room.items["a cave entrance"] = items["a cave entrance"] end @@ -404,7 +404,7 @@ local function getRoom( x, y, z, dontCreate ) room.exits[sDir] = true end else - if math.random(1,3) == 1 then + if math.random(1, 3) == 1 then room.exits[sDir] = true end end @@ -431,13 +431,13 @@ local function getRoom( x, y, z, dontCreate ) -- Add ores room.items[ "some stone" ] = items[ "some stone" ] - if math.random(1,3) == 1 then + if math.random(1, 3) == 1 then room.items[ "some coal" ] = items[ "some coal" ] end - if math.random(1,8) == 1 then + if math.random(1, 8) == 1 then room.items[ "some iron" ] = items[ "some iron" ] end - if y == -3 and math.random(1,15) == 1 then + if y == -3 and math.random(1, 15) == 1 then room.items[ "some diamond" ] = items[ "some diamond" ] end @@ -634,7 +634,7 @@ function commands.wait() end function commands.look( _sTarget ) - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) if room.dark then print( "It is pitch dark." ) return @@ -648,7 +648,7 @@ function commands.look( _sTarget ) else io.write( "You are underground. " ) if next( room.exits ) ~= nil then - print( "You can travel "..itemize( room.exits ).."." ) + print( "You can travel " .. itemize( room.exits ) .. "." ) else print() end @@ -679,16 +679,16 @@ function commands.look( _sTarget ) end if tItem then - print( tItem.desc or "You see nothing special about "..sItem.."." ) + print( tItem.desc or "You see nothing special about " .. sItem .. "." ) else - print( "You don't see any ".._sTarget.." here." ) + print( "You don't see any " .. _sTarget .. " here." ) end end end end function commands.go( _sDir ) - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) if _sDir == nil then print( "Go where?" ) return @@ -735,7 +735,7 @@ function commands.go( _sDir ) end function commands.dig( _sDir, _sTool ) - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) if _sDir == nil then print( "Dig where?" ) return @@ -746,7 +746,7 @@ function commands.dig( _sDir, _sTool ) if _sTool ~= nil then sTool = findItem( inventory, _sTool ) if not sTool then - print( "You're not carrying a ".._sTool.."." ) + print( "You're not carrying a " .. _sTool .. "." ) return end tTool = inventory[ sTool ] @@ -827,10 +827,10 @@ function commands.dig( _sDir, _sTool ) _sDir == "up" and y == 0 then inventory[ "some dirt" ] = items[ "some dirt" ] inventory[ "some stone" ] = items[ "some stone" ] - print( "You dig ".._sDir.." using "..sTool.." and collect some dirt and stone." ) + print( "You dig " .. _sDir .. " using " .. sTool .. " and collect some dirt and stone." ) else inventory[ "some stone" ] = items[ "some stone" ] - print( "You dig ".._sDir.." using "..sTool.." and collect some stone." ) + print( "You dig " .. _sDir .. " using " .. sTool .. " and collect some stone." ) end end @@ -848,7 +848,7 @@ function commands.drop( _sItem ) return end - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) local sItem = findItem( inventory, _sItem ) if sItem then local tItem = inventory[ sItem ] @@ -860,7 +860,7 @@ function commands.drop( _sItem ) print( "Dropped." ) end else - print( "You don't have a ".._sItem.."." ) + print( "You don't have a " .. _sItem .. "." ) end end @@ -871,7 +871,7 @@ function commands.place( _sItem ) end if _sItem == "torch" or _sItem == "a torch" then - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) if inventory["some torches"] or inventory["a torch"] then inventory["a torch"] = nil room.items["a torch"] = items["a torch"] @@ -898,12 +898,12 @@ function commands.take( _sItem ) return end - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) local sItem = findItem( room.items, _sItem ) if sItem then local tItem = room.items[ sItem ] if tItem.heavy == true then - print( "You can't carry "..sItem.."." ) + print( "You can't carry " .. sItem .. "." ) elseif tItem.ore == true then print( "You need to mine this ore." ) else @@ -923,7 +923,7 @@ function commands.take( _sItem ) end end else - print( "You don't see a ".._sItem.." here." ) + print( "You don't see a " .. _sItem .. " here." ) end end @@ -933,7 +933,7 @@ function commands.mine( _sItem, _sTool ) return end if _sTool == nil then - print( "Mine ".._sItem.." with what?" ) + print( "Mine " .. _sItem .. " with what?" ) return end commands.cbreak( _sItem, _sTool ) @@ -957,12 +957,12 @@ function commands.cbreak( _sItem, _sTool ) if _sTool ~= nil then sTool = findItem( inventory, _sTool ) if sTool == nil then - print( "You're not carrying a ".._sTool.."." ) + print( "You're not carrying a " .. _sTool .. "." ) return end end - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) if _sItem == "tree" or _sItem == "trees" or _sItem == "a tree" then print( "The tree breaks into blocks of wood, which you pick up." ) inventory[ "some wood" ] = items[ "some wood" ] @@ -990,18 +990,18 @@ function commands.cbreak( _sItem, _sTool ) local tTool = inventory[ sTool ] if tTool.tool then if tTool.toolLevel < tItem.toolLevel then - print( sTool .." is not strong enough to break this ore." ) + print( sTool .. " is not strong enough to break this ore." ) elseif tTool.toolType ~= tItem.toolType then print( "You need a different kind of tool to break this ore." ) else - print( "The ore breaks, dropping "..sItem..", which you pick up." ) + print( "The ore breaks, dropping " .. sItem .. ", which you pick up." ) inventory[ sItem ] = items[ sItem ] if tItem.infinite ~= true then room.items[ sItem ] = nil end end else - print( "You can't break "..sItem.." with "..sTool..".") + print( "You can't break " .. sItem .. " with " .. sTool .. ".") end elseif tItem.creature == true then @@ -1018,12 +1018,12 @@ function commands.cbreak( _sItem, _sTool ) local tChances = { 0.2, 0.4, 0.55, 0.8, 1 } if math.random() <= tChances[ toolLevel + 1 ] then room.items[ sItem ] = nil - print( "The "..tItem.aliases[1].." dies." ) + print( "The " .. tItem.aliases[1] .. " dies." ) if tItem.drops then for _, sDrop in pairs( tItem.drops ) do if not room.items[sDrop] then - print( "The "..tItem.aliases[1].." dropped "..sDrop.."." ) + print( "The " .. tItem.aliases[1] .. " dropped " .. sDrop .. "." ) room.items[sDrop] = items[sDrop] end end @@ -1033,23 +1033,23 @@ function commands.cbreak( _sItem, _sTool ) room.nMonsters = room.nMonsters - 1 end else - print( "The "..tItem.aliases[1].." is injured by your blow." ) + print( "The " .. tItem.aliases[1] .. " is injured by your blow." ) end if tItem.hitDrops then for _, sDrop in pairs( tItem.hitDrops ) do if not room.items[sDrop] then - print( "The "..tItem.aliases[1].." dropped "..sDrop.."." ) + print( "The " .. tItem.aliases[1] .. " dropped " .. sDrop .. "." ) room.items[sDrop] = items[sDrop] end end end else - print( "You can't break "..sItem.."." ) + print( "You can't break " .. sItem .. "." ) end else - print( "You don't see a ".._sItem.." here." ) + print( "You don't see a " .. _sItem .. " here." ) end end @@ -1074,14 +1074,14 @@ function commands.craft( _sItem ) local sItem = findItem( items, _sItem ) local tRecipe = sItem and tRecipes[ sItem ] or nil if tRecipe then - for _,sReq in ipairs( tRecipe ) do + for _, sReq in ipairs( tRecipe ) do if inventory[sReq] == nil then - print( "You don't have the items you need to craft "..sItem.."." ) + print( "You don't have the items you need to craft " .. sItem .. "." ) return end end - for _,sReq in ipairs( tRecipe ) do + for _, sReq in ipairs( tRecipe ) do inventory[sReq] = nil end inventory[ sItem ] = items[ sItem ] @@ -1090,7 +1090,7 @@ function commands.craft( _sItem ) end print( "Crafted." ) else - print( "You don't know how to make "..(sItem or _sItem).."." ) + print( "You don't know how to make " .. (sItem or _sItem) .. "." ) end end @@ -1115,12 +1115,12 @@ function commands.build( _sThing, _sMaterial ) else sMaterial = findItem( inventory, _sMaterial ) if not sMaterial then - print( "You don't have any ".._sMaterial ) + print( "You don't have any " .. _sMaterial ) return end if inventory[sMaterial].material ~= true then - print( sMaterial.." is not a good building material." ) + print( sMaterial .. " is not a good building material." ) return end end @@ -1130,12 +1130,12 @@ function commands.build( _sThing, _sMaterial ) alias = string.match( _sThing, "a ([%a ]+)" ) end - local room = getRoom( x,y,z ) + local room = getRoom( x, y, z ) inventory[sMaterial] = nil room.items[ _sThing ] = { heavy = true, aliases = { alias }, - desc = "As you look at your creation (made from "..sMaterial.."), you feel a swelling sense of pride.", + desc = "As you look at your creation (made from " .. sMaterial .. "), you feel a swelling sense of pride.", } print( "Your construction is complete." ) @@ -1158,7 +1158,7 @@ function commands.eat( _sItem ) local sItem = findItem( inventory, _sItem ) if not sItem then - print( "You don't have any ".._sItem.."." ) + print( "You don't have any " .. _sItem .. "." ) return end @@ -1172,7 +1172,7 @@ function commands.eat( _sItem ) bInjured = false end else - print( "You can't eat "..sItem.."." ) + print( "You can't eat " .. sItem .. "." ) end end @@ -1195,7 +1195,7 @@ function commands.badinput() "That doesn't make any sense.", "What?", } - print( tResponses[ math.random(1,#tResponses) ] ) + print( tResponses[ math.random(1, #tResponses) ] ) end function commands.noinput() @@ -1206,16 +1206,16 @@ function commands.noinput() "Don't be shy.", "Use your words.", } - print( tResponses[ math.random(1,#tResponses) ] ) + print( tResponses[ math.random(1, #tResponses) ] ) end local function simulate() local bNewMonstersThisRoom = false -- Spawn monsters in nearby rooms - for sx = -2,2 do - for sy = -1,1 do - for sz = -2,2 do + for sx = -2, 2 do + for sy = -1, 1 do + for sz = -2, 2 do local h = y + sy if h >= -3 and h <= 0 then local room = getRoom( x + sx, h, z + sz ) @@ -1223,15 +1223,15 @@ local function simulate() -- Spawn monsters if room.nMonsters < 2 and (h == 0 and not isSunny() and not room.items["a torch"] or room.dark) and - math.random(1,6) == 1 then + math.random(1, 6) == 1 then - local sMonster = tMonsters[ math.random(1,#tMonsters) ] + local sMonster = tMonsters[ math.random(1, #tMonsters) ] if room.items[ sMonster ] == nil then room.items[ sMonster ] = items[ sMonster ] room.nMonsters = room.nMonsters + 1 if sx == 0 and sy == 0 and sz == 0 and not room.dark then - print( "From the shadows, "..sMonster.." appears." ) + print( "From the shadows, " .. sMonster .. " appears." ) bNewMonstersThisRoom = true end end @@ -1239,11 +1239,11 @@ local function simulate() -- Burn monsters if h == 0 and isSunny() then - for _,sMonster in ipairs( tMonsters ) do + for _, sMonster in ipairs( tMonsters ) do if room.items[sMonster] and items[sMonster].nocturnal then room.items[sMonster] = nil if sx == 0 and sy == 0 and sz == 0 and not room.dark then - print( "With the sun high in the sky, the "..items[sMonster].aliases[1].." bursts into flame and dies." ) + print( "With the sun high in the sky, the " .. items[sMonster].aliases[1] .. " bursts into flame and dies." ) end room.nMonsters = room.nMonsters - 1 end @@ -1257,9 +1257,9 @@ local function simulate() -- Make monsters attack local room = getRoom( x, y, z ) if nTimeInRoom >= 2 and not bNewMonstersThisRoom then - for _,sMonster in ipairs( tMonsters ) do + for _, sMonster in ipairs( tMonsters ) do if room.items[sMonster] then - if math.random(1,4) == 1 and + if math.random(1, 4) == 1 and not (y == 0 and isSunny() and sMonster == "a spider") then if sMonster == "a creeper" then if room.dark then @@ -1271,9 +1271,9 @@ local function simulate() room.nMonsters = room.nMonsters - 1 else if room.dark then - print( "A "..items[sMonster].aliases[1].." attacks you." ) + print( "A " .. items[sMonster].aliases[1] .. " attacks you." ) else - print( "The "..items[sMonster].aliases[1].." attacks you." ) + print( "The " .. items[sMonster].aliases[1] .. " attacks you." ) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua index 81775248b..78b259fe0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua @@ -23,7 +23,7 @@ elseif sCommand == "play" or sCommand == nil then if sName == nil then -- No disc specified, pick one at random local tNames = {} - for _,sName in ipairs( peripheral.getNames() ) do + for _, sName in ipairs( peripheral.getNames() ) do if disk.isPresent( sName ) and disk.hasAudio( sName ) then table.insert( tNames, sName ) end @@ -32,15 +32,15 @@ elseif sCommand == "play" or sCommand == nil then print( "No Music Discs in attached disk drives" ) return end - sName = tNames[ math.random(1,#tNames) ] + sName = tNames[ math.random(1, #tNames) ] end -- Play the disc if disk.isPresent( sName ) and disk.hasAudio( sName ) then - print( "Playing "..disk.getAudioTitle( sName ) ) + print( "Playing " .. disk.getAudioTitle( sName ) ) disk.playAudio( sName ) else - print( "No Music Disc in disk drive: "..sName ) + print( "No Music Disc in disk drive: " .. sName ) return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua index c1118bd9f..d22399410 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua @@ -1,5 +1,5 @@ if term.isColour() then - term.setTextColour( 2^math.random(0,15) ) + term.setTextColour( 2 ^ math.random(0, 15) ) end textutils.slowPrint( "Hello World!" ) term.setTextColour( colours.white ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua index 58eb72fc0..cc55288fb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua @@ -1,6 +1,6 @@ -- Display the start screen -local w,h = term.getSize() +local w, h = term.getSize() local headingColour, textColour, wormColour, fruitColour if term.isColour() then @@ -17,27 +17,27 @@ end local function printCentred( y, s ) local x = math.floor((w - string.len(s)) / 2) - term.setCursorPos(x,y) + term.setCursorPos(x, y) --term.clearLine() term.write( s ) end -local xVel,yVel = 1,0 -local xPos, yPos = math.floor(w/2), math.floor(h/2) +local xVel, yVel = 1, 0 +local xPos, yPos = math.floor(w / 2), math.floor(h / 2) local pxVel, pyVel = nil, nil local nExtraLength = 6 local bRunning = true -local tailX,tailY = xPos,yPos +local tailX, tailY = xPos, yPos local nScore = 0 local nDifficulty = 2 local nSpeed, nInterval -- Setup the screen local screen = {} -for x=1,w do +for x = 1, w do screen[x] = {} - for y=1,h do + for y = 1, h do screen[x][y] = {} end end @@ -54,17 +54,17 @@ local tFruits = { "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", - "@", "$", "%", "#", "&", "!", "?", "+", "*", "~" + "@", "$", "%", "#", "&", "!", "?", "+", "*", "~", } local function addFruit() while true do - local x = math.random(1,w) - local y = math.random(2,h) + local x = math.random(1, w) + local y = math.random(2, h) local fruit = screen[x][y] if fruit.snake == nil and fruit.wall == nil and fruit.fruit == nil then screen[x][y] = { fruit = true } - term.setCursorPos(x,y) + term.setCursorPos(x, y) term.setBackgroundColour( fruitColour ) term.write(" ") term.setBackgroundColour( colours.black ) @@ -80,19 +80,19 @@ end local function drawMenu() term.setTextColour( headingColour ) - term.setCursorPos(1,1) + term.setCursorPos(1, 1) term.write( "SCORE " ) term.setTextColour( textColour ) - term.setCursorPos(7,1) + term.setCursorPos(7, 1) term.write( tostring(nScore) ) term.setTextColour( headingColour ) - term.setCursorPos(w-11,1) + term.setCursorPos(w - 11, 1) term.write( "DIFFICULTY ") term.setTextColour( textColour ) - term.setCursorPos(w,1) + term.setCursorPos(w, 1) term.write( tostring(nDifficulty or "?") ) term.setTextColour( colours.white ) @@ -108,7 +108,7 @@ local function update( ) if nExtraLength == 0 then local tail = screen[tailX][tailY] screen[tailX][tailY] = {} - term.setCursorPos(tailX,tailY) + term.setCursorPos(tailX, tailY) term.write(" ") tailX = tail.nextX tailY = tail.nextY @@ -149,7 +149,7 @@ local function update( ) end - term.setCursorPos(xPos,yPos) + term.setCursorPos(xPos, yPos) term.setBackgroundColour( wormColour ) term.write(" ") term.setBackgroundColour( colours.black ) @@ -164,20 +164,20 @@ local function drawFrontend() --printCentred( math.floor(h/2) - 4, " W O R M " ) term.setTextColour( headingColour ) - printCentred( math.floor(h/2) - 3, "" ) - printCentred( math.floor(h/2) - 2, " SELECT DIFFICULTY " ) - printCentred( math.floor(h/2) - 1, "" ) + printCentred( math.floor(h / 2) - 3, "" ) + printCentred( math.floor(h / 2) - 2, " SELECT DIFFICULTY " ) + printCentred( math.floor(h / 2) - 1, "" ) - printCentred( math.floor(h/2) + 0, " " ) - printCentred( math.floor(h/2) + 1, " " ) - printCentred( math.floor(h/2) + 2, " " ) - printCentred( math.floor(h/2) - 1 + nDifficulty, " [ ] " ) + printCentred( math.floor(h / 2) + 0, " " ) + printCentred( math.floor(h / 2) + 1, " " ) + printCentred( math.floor(h / 2) + 2, " " ) + printCentred( math.floor(h / 2) - 1 + nDifficulty, " [ ] " ) term.setTextColour( textColour ) - printCentred( math.floor(h/2) + 0, "EASY" ) - printCentred( math.floor(h/2) + 1, "MEDIUM" ) - printCentred( math.floor(h/2) + 2, "HARD" ) - printCentred( math.floor(h/2) + 3, "" ) + printCentred( math.floor(h / 2) + 0, "EASY" ) + printCentred( math.floor(h / 2) + 1, "MEDIUM" ) + printCentred( math.floor(h / 2) + 2, "HARD" ) + printCentred( math.floor(h / 2) + 3, "" ) term.setTextColour( colours.white ) end @@ -185,7 +185,7 @@ end drawMenu() drawFrontend() while true do - local _,key = os.pullEvent( "key" ) + local _, key = os.pullEvent( "key" ) if key == keys.up or key == keys.w then -- Up if nDifficulty > 1 then @@ -233,23 +233,23 @@ while bRunning do if key == keys.up or key == keys.w then -- Up if yVel == 0 then - pxVel,pyVel = 0,-1 + pxVel, pyVel = 0, -1 end elseif key == keys.down or key == keys.s then -- Down if yVel == 0 then - pxVel,pyVel = 0,1 + pxVel, pyVel = 0, 1 end elseif key == keys.left or key == keys.a then -- Left if xVel == 0 then - pxVel,pyVel = -1,0 + pxVel, pyVel = -1, 0 end elseif key == keys.right or key == keys.d then -- Right if xVel == 0 then - pxVel,pyVel = 1,0 + pxVel, pyVel = 1, 0 end end @@ -258,25 +258,25 @@ end -- Display the gameover screen term.setTextColour( headingColour ) -printCentred( math.floor(h/2) - 2, " " ) -printCentred( math.floor(h/2) - 1, " G A M E O V E R " ) +printCentred( math.floor(h / 2) - 2, " " ) +printCentred( math.floor(h / 2) - 1, " G A M E O V E R " ) term.setTextColour( textColour ) -printCentred( math.floor(h/2) + 0, " " ) -printCentred( math.floor(h/2) + 1, " FINAL SCORE "..nScore.." " ) -printCentred( math.floor(h/2) + 2, " " ) +printCentred( math.floor(h / 2) + 0, " " ) +printCentred( math.floor(h / 2) + 1, " FINAL SCORE " .. nScore .. " " ) +printCentred( math.floor(h / 2) + 2, " " ) term.setTextColour( colours.white ) local timer = os.startTimer(2.5) repeat - local e,p = os.pullEvent() + local e, p = os.pullEvent() if e == "timer" and p == timer then term.setTextColour( textColour ) - printCentred( math.floor(h/2) + 2, " PRESS ANY KEY " ) - printCentred( math.floor(h/2) + 3, " " ) + printCentred( math.floor(h / 2) + 2, " PRESS ANY KEY " ) + printCentred( math.floor(h / 2) + 3, " " ) term.setTextColour( colours.white ) end until e == "char" term.clear() -term.setCursorPos(1,1) +term.setCursorPos(1, 1) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua index 77621de75..c5556c079 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua @@ -28,7 +28,7 @@ elseif sCommand == "host" then -- Find a modem local sModemSide = nil - for _,sSide in ipairs( rs.getSides() ) do + for _, sSide in ipairs( rs.getSides() ) do if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then sModemSide = sSide break @@ -41,7 +41,7 @@ elseif sCommand == "host" then end -- Determine position - local x,y,z + local x, y, z if #tArgs >= 4 then -- Position is manually specified x = tonumber(tArgs[2]) @@ -51,10 +51,10 @@ elseif sCommand == "host" then printUsage() return end - print( "Position is "..x..","..y..","..z ) + print( "Position is " .. x .. "," .. y .. "," .. z ) else -- Position is to be determined using locate - x,y,z = gps.locate( 2, true ) + x, y, z = gps.locate( 2, true ) if x == nil then print( "Run \"gps host \" to set position manually" ) return @@ -63,7 +63,7 @@ elseif sCommand == "host" then -- Open a channel local modem = peripheral.wrap( sModemSide ) - print( "Opening channel on modem "..sModemSide ) + print( "Opening channel on modem " .. sModemSide ) modem.open( gps.CHANNEL_GPS ) -- Serve requests indefinately @@ -80,10 +80,10 @@ elseif sCommand == "host" then -- Print the number of requests handled nServed = nServed + 1 if nServed > 1 then - local _,y = term.getCursorPos() - term.setCursorPos(1,y-1) + local _, y = term.getCursorPos() + term.setCursorPos(1, y - 1) end - print( nServed.." GPS requests served" ) + print( nServed .. " GPS requests served" ) end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua index e31edd7f1..3e28a2f7a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua @@ -46,9 +46,9 @@ local function get(url) write( "Connecting to pastebin.com... " ) -- Add a cache buster so that spam protection is re-checked - local cacheBuster = ("%x"):format(math.random(0, 2^30)) + local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30)) local response, err = http.get( - "https://pastebin.com/raw/"..textutils.urlEncode( paste ).."?cb="..cacheBuster + "https://pastebin.com/raw/" .. textutils.urlEncode( paste ) .. "?cb=" .. cacheBuster ) if response then @@ -93,11 +93,11 @@ if sCommand == "put" then local key = "0ec2eb25b6166c0c27a394ae118ad829" local response = http.post( "https://pastebin.com/api/api_post.php", - "api_option=paste&".. - "api_dev_key="..key.."&".. - "api_paste_format=lua&".. - "api_paste_name="..textutils.urlEncode(sName).."&".. - "api_paste_code="..textutils.urlEncode(sText) + "api_option=paste&" .. + "api_dev_key=" .. key .. "&" .. + "api_paste_format=lua&" .. + "api_paste_name=" .. textutils.urlEncode(sName) .. "&" .. + "api_paste_code=" .. textutils.urlEncode(sText) ) if response then @@ -107,8 +107,8 @@ if sCommand == "put" then response.close() local sCode = string.match( sResponse, "[^/]+$" ) - print( "Uploaded as "..sResponse ) - print( "Run \"pastebin get "..sCode.."\" to download anywhere" ) + print( "Uploaded as " .. sResponse ) + print( "Run \"pastebin get " .. sCode .. "\" to download anywhere" ) else print( "Failed." ) @@ -137,7 +137,7 @@ elseif sCommand == "get" then file.write( res ) file.close() - print( "Downloaded as "..sFile ) + print( "Downloaded as " .. sFile ) end elseif sCommand == "run" then local sCode = tArgs[2] diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/id.lua b/src/main/resources/assets/computercraft/lua/rom/programs/id.lua index bacf2851e..439fc9f3c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/id.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/id.lua @@ -6,24 +6,24 @@ if #tArgs > 0 then end if sDrive == nil then - print( "This is computer #"..os.getComputerID() ) + print( "This is computer #" .. os.getComputerID() ) local label = os.getComputerLabel() if label then - print( "This computer is labelled \""..label.."\"" ) + print( "This computer is labelled \"" .. label .. "\"" ) end else local bData = disk.hasData( sDrive ) if not bData then - print( "No disk in drive "..sDrive ) + print( "No disk in drive " .. sDrive ) return end - print( "The disk is #"..disk.getID( sDrive ) ) + print( "The disk is #" .. disk.getID( sDrive ) ) local label = disk.getLabel( sDrive ) if label then - print( "The disk is labelled \""..label.."\"" ) + print( "The disk is labelled \"" .. label .. "\"" ) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/label.lua b/src/main/resources/assets/computercraft/lua/rom/programs/label.lua index cee4179b4..ea23277a9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/label.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/label.lua @@ -14,11 +14,11 @@ local function checkDrive( sDrive ) -- Check the disk exists local bData = disk.hasData( sDrive ) if not bData then - print( "No disk in "..sDrive.." drive" ) + print( "No disk in " .. sDrive .. " drive" ) return false end else - print( "No disk drive named "..sDrive ) + print( "No disk drive named " .. sDrive ) return false end return true @@ -29,7 +29,7 @@ local function get( sDrive ) if checkDrive( sDrive ) then local sLabel = disk.getLabel( sDrive ) if sLabel then - print( "Disk label is \""..sLabel.."\"" ) + print( "Disk label is \"" .. sLabel .. "\"" ) else print( "No Disk label" ) end @@ -37,7 +37,7 @@ local function get( sDrive ) else local sLabel = os.getComputerLabel() if sLabel then - print( "Computer label is \""..sLabel.."\"" ) + print( "Computer label is \"" .. sLabel .. "\"" ) else print( "No Computer label" ) end @@ -50,7 +50,7 @@ local function set( sDrive, sText ) disk.setLabel( sDrive, sText ) local sLabel = disk.getLabel( sDrive ) if sLabel then - print( "Disk label set to \""..sLabel.."\"" ) + print( "Disk label set to \"" .. sLabel .. "\"" ) else print( "Disk label cleared" ) end @@ -59,7 +59,7 @@ local function set( sDrive, sText ) os.setComputerLabel( sText ) local sLabel = os.getComputerLabel() if sLabel then - print( "Computer label set to \""..sLabel.."\"" ) + print( "Computer label set to \"" .. sLabel .. "\"" ) else print( "Computer label cleared" ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 50766b973..3535b19df 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -67,7 +67,7 @@ while bRunning do local nForcePrint = 0 local func, e = load( s, "=lua", "t", tEnv ) - local func2 = load( "return _echo("..s..");", "=lua", "t", tEnv ) + local func2 = load( "return _echo(" .. s .. ");", "=lua", "t", tEnv ) if not func then if func2 then func = func2 diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua b/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua index ad3d5a059..3bdb5e840 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua @@ -8,9 +8,9 @@ end for _, v in ipairs( tArgs ) do local sNewDir = shell.resolve( v ) if fs.exists( sNewDir ) and not fs.isDir( sNewDir ) then - printError( v..": Destination exists" ) + printError( v .. ": Destination exists" ) elseif fs.isReadOnly( sNewDir ) then - printError( v..": Access denied" ) + printError( v .. ": Access denied" ) else fs.makeDir( sNewDir ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua index 985cc0246..16afddd29 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua @@ -11,18 +11,18 @@ end local sName = tArgs[1] if peripheral.getType( sName ) ~= "monitor" then - print( "No monitor named ".. sName ) + print( "No monitor named " .. sName ) return end local sProgram = tArgs[2] local sPath = shell.resolveProgram( sProgram ) if sPath == nil then - print( "No such program: "..sProgram ) + print( "No such program: " .. sProgram ) return end -print( "Running "..sProgram.." on monitor "..sName ) +print( "Running " .. sProgram .. " on monitor " .. sName ) local monitor = peripheral.wrap( sName ) local previousTerm = term.redirect( monitor ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua b/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua index 317938b31..a7142fb85 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua @@ -3,7 +3,7 @@ local tMotd = {} for sPath in string.gmatch(settings.get( "motd.path" ), "[^:]+") do if fs.exists(sPath) then for sLine in io.lines(sPath) do - table.insert(tMotd,sLine) + table.insert(tMotd, sLine) end end end @@ -11,5 +11,5 @@ end if #tMotd == 0 then print("missingno") else - print(tMotd[math.random(1,#tMotd)]) + print(tMotd[math.random(1, #tMotd)]) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua index 5f12588e7..5b2dd6266 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua @@ -9,7 +9,7 @@ local sSource = shell.resolve( tArgs[1] ) local sDest = shell.resolve( tArgs[2] ) local tFiles = fs.find( sSource ) if #tFiles > 0 then - for _,sFile in ipairs( tFiles ) do + for _, sFile in ipairs( tFiles ) do if fs.isDir( sDest ) then fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) ) elseif #tFiles == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua b/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua index b5b5e65f3..33b7e9c9a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua @@ -1,7 +1,7 @@ local tPeripherals = peripheral.getNames() print( "Attached Peripherals:" ) if #tPeripherals > 0 then - for n=1,#tPeripherals do + for n = 1, #tPeripherals do local sPeripheral = tPeripherals[n] print( sPeripheral .. " (" .. peripheral.getType( sPeripheral ) .. ")" ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua index afecfa67b..bdc922e4f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua @@ -4,178 +4,178 @@ This version written by Gopher, at the request of Dan200, for ComputerCraft v1.6. No particular rights are reserved. --]] -local function colorass(c,bw) +local function colorass(c, bw) return term.isColor() and c or bw end -local block_s1= { +local block_s1 = { { - { 1,0,0,0, }, - { 1,1,0,0, }, - { 0,1,0,0, }, - { 0,0,0,0, }, + { 1, 0, 0, 0 }, + { 1, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,0,0,0, }, - { 0,1,1,0, }, - { 1,1,0,0, }, - { 0,0,0,0, }, + { 0, 0, 0, 0 }, + { 0, 1, 1, 0 }, + { 1, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","{}"), - fg=colorass(colors.blue,colors.black), - bg=colorass(colors.cyan,colors.white), + ch = colorass(" ", "{}"), + fg = colorass(colors.blue, colors.black), + bg = colorass(colors.cyan, colors.white), } -local block_s2= { +local block_s2 = { { - { 0,1,0,0, }, - { 1,1,0,0, }, - { 1,0,0,0, }, - { 0,0,0,0, }, + { 0, 1, 0, 0 }, + { 1, 1, 0, 0 }, + { 1, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,0,0,0, }, - { 1,1,0,0, }, - { 0,1,1,0, }, - { 0,0,0,0, }, + { 0, 0, 0, 0 }, + { 1, 1, 0, 0 }, + { 0, 1, 1, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","{}"), - fg=colorass(colors.green,colors.black), - bg=colorass(colors.lime,colors.white), + ch = colorass(" ", "{}"), + fg = colorass(colors.green, colors.black), + bg = colorass(colors.lime, colors.white), } local block_line = { { - { 0,1,0,0, }, - { 0,1,0,0, }, - { 0,1,0,0, }, - { 0,1,0,0, }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, }, { - { 0,0,0,0, }, - { 1,1,1,1, }, - { 0,0,0,0, }, - { 0,0,0,0, }, + { 0, 0, 0, 0 }, + { 1, 1, 1, 1 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","[]"), - fg=colorass(colors.pink,colors.black), - bg=colorass(colors.red,colors.white), + ch = colorass(" ", "[]"), + fg = colorass(colors.pink, colors.black), + bg = colorass(colors.red, colors.white), } local block_square = { { - { 1,1,0,0, }, - { 1,1,0,0, }, - { 0,0,0,0, }, - { 0,0,0,0, }, + { 1, 1, 0, 0 }, + { 1, 1, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","[]"), - fg=colorass(colors.lightBlue,colors.black), - bg=colorass(colors.blue,colors.white), + ch = colorass(" ", "[]"), + fg = colorass(colors.lightBlue, colors.black), + bg = colorass(colors.blue, colors.white), } local block_L1 = { { - { 1,1,0,0, }, - { 0,1,0,0, }, - { 0,1,0,0, }, - { 0,0,0,0, }, + { 1, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,0,0,0, }, - { 1,1,1,0, }, - { 1,0,0,0, }, - { 0,0,0,0, }, + { 0, 0, 0, 0 }, + { 1, 1, 1, 0 }, + { 1, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,1,0,0, }, - { 0,1,0,0, }, - { 0,1,1,0, }, - { 0,0,0,0, }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 1, 1, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,0,1,0, }, - { 1,1,1,0, }, - { 0,0,0,0, }, - { 0,0,0,0, }, + { 0, 0, 1, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","()"), - fg=colorass(colors.orange,colors.black), - bg=colorass(colors.yellow,colors.white), + ch = colorass(" ", "()"), + fg = colorass(colors.orange, colors.black), + bg = colorass(colors.yellow, colors.white), } local block_L2 = { { - { 0,1,0,0, }, - { 0,1,0,0, }, - { 1,1,0,0, }, - { 0,0,0,0, }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 1, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,0,0,0, }, - { 1,1,1,0, }, - { 0,0,1,0, }, - { 0,0,0,0, }, + { 0, 0, 0, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,1,1,0, }, - { 0,1,0,0, }, - { 0,1,0,0, }, - { 0,0,0,0, }, + { 0, 1, 1, 0 }, + { 0, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 1,0,0,0, }, - { 1,1,1,0, }, - { 0,0,0,0, }, - { 0,0,0,0, }, + { 1, 0, 0, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","()"), - fg=colorass(colors.brown,colors.black), - bg=colorass(colors.orange,colors.white), + ch = colorass(" ", "()"), + fg = colorass(colors.brown, colors.black), + bg = colorass(colors.orange, colors.white), } local block_T = { { - { 0,1,0,0, }, - { 1,1,0,0, }, - { 0,1,0,0, }, - { 0,0,0,0, }, + { 0, 1, 0, 0 }, + { 1, 1, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,0,0,0, }, - { 1,1,1,0, }, - { 0,1,0,0, }, - { 0,0,0,0, }, + { 0, 0, 0, 0 }, + { 1, 1, 1, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,1,0,0, }, - { 0,1,1,0, }, - { 0,1,0,0, }, - { 0,0,0,0, }, + { 0, 1, 0, 0 }, + { 0, 1, 1, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 0, 0 }, }, { - { 0,1,0,0, }, - { 1,1,1,0, }, - { 0,0,0,0, }, - { 0,0,0,0, }, + { 0, 1, 0, 0 }, + { 1, 1, 1, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, }, - ch=colorass(" ","<>"), - fg=colorass(colors.cyan,colors.black), - bg=colorass(colors.purple,colors.white), + ch = colorass(" ", "<>"), + fg = colorass(colors.cyan, colors.black), + bg = colorass(colors.purple, colors.white), } -local blocks={ block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T} +local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T} -local points={4,10,30,120} +local points = {4, 10, 30, 120} -local function lpad(text,amt) - text=tostring(text) - return string.rep(" ",amt-#text)..text +local function lpad(text, amt) + text = tostring(text) + return string.rep(" ", amt - #text) .. text end -local width,height=term.getSize() +local width, height = term.getSize() -if height<19 or width<26 then +if height < 19 or width < 26 then print("Your screen is too small to play :(") return end -local speedsByLevel={ +local speedsByLevel = { 1.2, 1.0, .8, @@ -187,23 +187,23 @@ local speedsByLevel={ .2, .15, .1, - .05,} + .05, } -local level=1 +local level = 1 local function playGame() - local score=0 - local lines=0 - local initialLevel=level - local next=blocks[math.random(1,#blocks)] + local score = 0 + local lines = 0 + local initialLevel = level + local next = blocks[math.random(1, #blocks)] - local pit={} + local pit = {} - local heightAdjust=0 + local heightAdjust = 0 - if height<=19 then - heightAdjust=1 + if height <= 19 then + heightAdjust = 1 end @@ -215,56 +215,56 @@ local function playGame() term.setTextColor(colors.black) term.setBackgroundColor(colorass(colors.lightGray, colors.white)) - term.setCursorPos(22,2) + term.setCursorPos(22, 2) term.write("Score") --score - term.setCursorPos(22,5) + term.setCursorPos(22, 5) term.write("Level") --level - term.setCursorPos(22,8) + term.setCursorPos(22, 8) term.write("Lines") --lines - term.setCursorPos(22,12) + term.setCursorPos(22, 12) term.write("Next") --next - term.setCursorPos(21,1) + term.setCursorPos(21, 1) term.write(" ") - term.setCursorPos(21,2) + term.setCursorPos(21, 2) term.write(" ") --score - term.setCursorPos(21,3) + term.setCursorPos(21, 3) term.write(" ") - term.setCursorPos(21,4) + term.setCursorPos(21, 4) term.write(" ") - term.setCursorPos(21,5) + term.setCursorPos(21, 5) term.write(" ") --level - term.setCursorPos(21,6) + term.setCursorPos(21, 6) term.write(" ") - term.setCursorPos(21,7) + term.setCursorPos(21, 7) term.write(" ") - term.setCursorPos(21,8) + term.setCursorPos(21, 8) term.write(" ") --lines - term.setCursorPos(21,9) + term.setCursorPos(21, 9) term.write(" ") - term.setCursorPos(21,10) + term.setCursorPos(21, 10) term.write(" ") - term.setCursorPos(21,11) + term.setCursorPos(21, 11) term.write(" ") - term.setCursorPos(21,12) + term.setCursorPos(21, 12) term.write(" ") --next - term.setCursorPos(26,12) + term.setCursorPos(26, 12) term.write(" ") --next - term.setCursorPos(21,13) + term.setCursorPos(21, 13) term.write(" ") - term.setCursorPos(21,14) + term.setCursorPos(21, 14) term.write(" ") - term.setCursorPos(21,15) + term.setCursorPos(21, 15) term.write(" ") - term.setCursorPos(21,16) + term.setCursorPos(21, 16) term.write(" ") - term.setCursorPos(21,17) + term.setCursorPos(21, 17) term.write(" ") - term.setCursorPos(21,18) + term.setCursorPos(21, 18) term.write(" ") - term.setCursorPos(21,19) + term.setCursorPos(21, 19) term.write(" ") - term.setCursorPos(21,20) + term.setCursorPos(21, 20) term.write(" ") end @@ -272,47 +272,47 @@ local function playGame() term.setTextColor(colors.white) term.setBackgroundColor(colors.black) - term.setCursorPos(22,3) - term.write(lpad(score,5)) --score - term.setCursorPos(22,6) - term.write(lpad(level,5)) --level - term.setCursorPos(22,9) - term.write(lpad(lines,5)) --lines + term.setCursorPos(22, 3) + term.write(lpad(score, 5)) --score + term.setCursorPos(22, 6) + term.write(lpad(level, 5)) --level + term.setCursorPos(22, 9) + term.write(lpad(lines, 5)) --lines end - local function drawBlockAt(block,xp,yp,rot) + local function drawBlockAt(block, xp, yp, rot) term.setTextColor(block.fg) term.setBackgroundColor(block.bg) - for y=1,4 do - for x=1,4 do - if block[rot][y][x]==1 then - term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust) + for y = 1, 4 do + for x = 1, 4 do + if block[rot][y][x] == 1 then + term.setCursorPos((xp + x) * 2 - 3, yp + y - 1 - heightAdjust) term.write(block.ch) end end end end - local function eraseBlockAt(block,xp,yp,rot) + local function eraseBlockAt(block, xp, yp, rot) term.setTextColor(colors.white) term.setBackgroundColor(colors.black) - for y=1,4 do - for x=1,4 do - if block[rot][y][x]==1 then - term.setCursorPos((xp+x)*2-3,yp+y-1-heightAdjust) + for y = 1, 4 do + for x = 1, 4 do + if block[rot][y][x] == 1 then + term.setCursorPos((xp + x) * 2 - 3, yp + y - 1 - heightAdjust) term.write(" ") end end end end - local function testBlockAt(block,xp,yp,rot) - for y=1,4 do - local ty=yp+y-1 - for x=1,4 do - local tx=xp+x-1 - if block[rot][y][x]==1 then - if tx>10 or tx<1 or ty>20 or pit[ty][tx]~=0 then + local function testBlockAt(block, xp, yp, rot) + for y = 1, 4 do + local ty = yp + y - 1 + for x = 1, 4 do + local tx = xp + x - 1 + if block[rot][y][x] == 1 then + if tx > 10 or tx < 1 or ty > 20 or pit[ty][tx] ~= 0 then return true end end @@ -320,11 +320,11 @@ local function playGame() end end - local function pitBlock(block,xp,yp,rot) - for y=1,4 do - for x=1,4 do - if block[rot][y][x]==1 then - pit[yp+y-1][xp+x-1]=block + local function pitBlock(block, xp, yp, rot) + for y = 1, 4 do + for x = 1, 4 do + if block[rot][y][x] == 1 then + pit[yp + y - 1][xp + x - 1] = block end end end @@ -332,10 +332,10 @@ local function playGame() local function clearPit() - for row=1,20 do - pit[row]={} - for col=1,10 do - pit[row][col]=0 + for row = 1, 20 do + pit[row] = {} + for col = 1, 10 do + pit[row][col] = 0 end end end @@ -350,24 +350,24 @@ local function playGame() - local halt=false - local dropSpeed=speedsByLevel[math.min(level,12)] + local halt = false + local dropSpeed = speedsByLevel[math.min(level, 12)] - local curBlock=next - next=blocks[math.random(1,7)] + local curBlock = next + next = blocks[math.random(1, 7)] - local curX, curY, curRot=4, 1, 1 - local dropTimer=os.startTimer(dropSpeed) + local curX, curY, curRot = 4, 1, 1 + local dropTimer = os.startTimer(dropSpeed) - drawBlockAt(next,11.5,15+heightAdjust,1) - drawBlockAt(curBlock,curX,curY,curRot) + drawBlockAt(next, 11.5, 15 + heightAdjust, 1) + drawBlockAt(curBlock, curX, curY, curRot) local function redrawPit() - for r=1+heightAdjust,20 do - term.setCursorPos(1,r-heightAdjust) - for c=1,10 do - if pit[r][c]==0 then + for r = 1 + heightAdjust, 20 do + term.setCursorPos(1, r - heightAdjust) + for c = 1, 10 do + if pit[r][c] == 0 then term.setTextColor(colors.black) term.setBackgroundColor(colors.black) term.write(" ") @@ -381,8 +381,8 @@ local function playGame() end local function hidePit() - for r=1+heightAdjust,20 do - term.setCursorPos(1,r-heightAdjust) + for r = 1 + heightAdjust, 20 do + term.setCursorPos(1, r - heightAdjust) term.setTextColor(colors.black) term.setBackgroundColor(colors.black) term.write(" ") @@ -390,56 +390,56 @@ local function playGame() end local function msgBox(message) - local x=math.floor((17-#message)/2) - term.setBackgroundColor(colorass(colors.lightGray,colors.white)) + local x = math.floor((17 - #message) / 2) + term.setBackgroundColor(colorass(colors.lightGray, colors.white)) term.setTextColor(colors.black) - term.setCursorPos(x,9) - term.write("+"..string.rep("-",#message+2).."+") - term.setCursorPos(x,10) + term.setCursorPos(x, 9) + term.write("+" .. string.rep("-", #message + 2) .. "+") + term.setCursorPos(x, 10) term.write("|") - term.setCursorPos(x+#message+3,10) + term.setCursorPos(x + #message + 3, 10) term.write("|") - term.setCursorPos(x,11) - term.write("+"..string.rep("-",#message+2).."+") + term.setCursorPos(x, 11) + term.write("+" .. string.rep("-", #message + 2) .. "+") term.setTextColor(colors.white) term.setBackgroundColor(colors.black) - term.setCursorPos(x+1,10) - term.write(" "..message.." ") + term.setCursorPos(x + 1, 10) + term.write(" " .. message .. " ") end local function clearRows() - local rows={} - for r=1,20 do - local count=0 - for c=1,10 do - if pit[r][c]~=0 then - count=count+1 + local rows = {} + for r = 1, 20 do + local count = 0 + for c = 1, 10 do + if pit[r][c] ~= 0 then + count = count + 1 else break end end - if count==10 then - rows[#rows+1]=r + if count == 10 then + rows[#rows + 1] = r end end - if #rows>0 then - for _=1,4 do + if #rows > 0 then + for _ = 1, 4 do sleep(.1) - for r=1,#rows do - r=rows[r] - term.setCursorPos(1,r-heightAdjust) - for c=1,10 do + for r = 1, #rows do + r = rows[r] + term.setCursorPos(1, r - heightAdjust) + for c = 1, 10 do term.setTextColor(pit[r][c].bg) term.setBackgroundColor(pit[r][c].fg) term.write(pit[r][c].ch) end end sleep(.1) - for r=1,#rows do - r=rows[r] - term.setCursorPos(1,r-heightAdjust) - for c=1,10 do + for r = 1, #rows do + r = rows[r] + term.setCursorPos(1, r - heightAdjust) + for c = 1, 10 do term.setTextColor(pit[r][c].fg) term.setBackgroundColor(pit[r][c].bg) term.write(pit[r][c].ch) @@ -448,154 +448,154 @@ local function playGame() end --now remove the rows and drop everythign else term.setBackgroundColor(colors.black) - for r=1,#rows do - r=rows[r] - term.setCursorPos(1,r-heightAdjust) + for r = 1, #rows do + r = rows[r] + term.setCursorPos(1, r - heightAdjust) term.write(" ") end sleep(.25) - for r=1,#rows do - table.remove(pit,rows[r]) - table.insert(pit,1,{0,0,0,0,0,0,0,0,0,0}) + for r = 1, #rows do + table.remove(pit, rows[r]) + table.insert(pit, 1, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) end redrawPit() - lines=lines+#rows - score=score+points[#rows]*math.min(level,20) - level=math.floor(lines/10)+initialLevel - dropSpeed=speedsByLevel[math.min(level,12)] + lines = lines + #rows + score = score + points[#rows] * math.min(level, 20) + level = math.floor(lines / 10) + initialLevel + dropSpeed = speedsByLevel[math.min(level, 12)] updateNumbers() end sleep(.25) end local function blockFall() - if testBlockAt(curBlock,curX,curY+1,curRot) then - pitBlock(curBlock,curX,curY,curRot) + if testBlockAt(curBlock, curX, curY + 1, curRot) then + pitBlock(curBlock, curX, curY, curRot) --detect rows that clear clearRows() - curBlock=next - curX=4 - curY=1 - curRot=1 - if testBlockAt(curBlock,curX,curY,curRot) then - halt=true + curBlock = next + curX = 4 + curY = 1 + curRot = 1 + if testBlockAt(curBlock, curX, curY, curRot) then + halt = true end - drawBlockAt(curBlock,curX,curY,curRot) - eraseBlockAt(next,11.5,15+heightAdjust,1) - next=blocks[math.random(1,7)] - drawBlockAt(next,11.5,15+heightAdjust,1) + drawBlockAt(curBlock, curX, curY, curRot) + eraseBlockAt(next, 11.5, 15 + heightAdjust, 1) + next = blocks[math.random(1, 7)] + drawBlockAt(next, 11.5, 15 + heightAdjust, 1) return true else - eraseBlockAt(curBlock,curX,curY,curRot) - curY=curY+1 - drawBlockAt(curBlock,curX,curY,curRot) + eraseBlockAt(curBlock, curX, curY, curRot) + curY = curY + 1 + drawBlockAt(curBlock, curX, curY, curRot) return false end end while not halt do - local e={os.pullEvent()} - if e[1]=="timer" then - if e[2]==dropTimer then + local e = {os.pullEvent()} + if e[1] == "timer" then + if e[2] == dropTimer then blockFall() - dropTimer=os.startTimer(dropSpeed) + dropTimer = os.startTimer(dropSpeed) end - elseif e[1]=="key" then - local key=e[2] - local dx,dy,dr=0,0,0 - if key==keys.left or key==keys.a then - dx=-1 - elseif key==keys.right or key==keys.d then - dx=1 - elseif key==keys.up or key==keys.w then - dr=1 - elseif key==keys.down or key==keys.s then + elseif e[1] == "key" then + local key = e[2] + local dx, dy, dr = 0, 0, 0 + if key == keys.left or key == keys.a then + dx = -1 + elseif key == keys.right or key == keys.d then + dx = 1 + elseif key == keys.up or key == keys.w then + dr = 1 + elseif key == keys.down or key == keys.s then while not blockFall() do end - dropTimer=os.startTimer(dropSpeed) - elseif key==keys.space then + dropTimer = os.startTimer(dropSpeed) + elseif key == keys.space then hidePit() msgBox("Paused") - while ({os.pullEvent("key")})[2]~=keys.space do end + while ({os.pullEvent("key")})[2] ~= keys.space do end redrawPit() - drawBlockAt(curBlock,curX,curY,curRot) - dropTimer=os.startTimer(dropSpeed) + drawBlockAt(curBlock, curX, curY, curRot) + dropTimer = os.startTimer(dropSpeed) end - if dx+dr~=0 then - if not testBlockAt(curBlock,curX+dx,curY+dy,dr>0 and curRot%#curBlock+dr or curRot) then - eraseBlockAt(curBlock,curX,curY,curRot) - curX=curX+dx - curY=curY+dy - curRot=dr==0 and curRot or curRot%#curBlock+dr - drawBlockAt(curBlock,curX,curY,curRot) + if dx + dr ~= 0 then + if not testBlockAt(curBlock, curX + dx, curY + dy, dr > 0 and curRot % #curBlock + dr or curRot) then + eraseBlockAt(curBlock, curX, curY, curRot) + curX = curX + dx + curY = curY + dy + curRot = dr == 0 and curRot or curRot % #curBlock + dr + drawBlockAt(curBlock, curX, curY, curRot) end end - elseif e[1]=="term_resize" then - local _,h=term.getSize() - if h==20 then - heightAdjust=0 + elseif e[1] == "term_resize" then + local _, h = term.getSize() + if h == 20 then + heightAdjust = 0 else - heightAdjust=1 + heightAdjust = 1 end redrawPit() - drawBlockAt(curBlock,curX,curY,curRot) + drawBlockAt(curBlock, curX, curY, curRot) end end msgBox("Game Over!") while true do - local _,k=os.pullEvent("key") - if k==keys.space or k==keys.enter then + local _, k = os.pullEvent("key") + if k == keys.space or k == keys.enter then break end end - level = math.min(level,9) + level = math.min(level, 9) end -local selected=1 -local playersDetected=false +local selected = 1 +local playersDetected = false local function drawMenu() term.setBackgroundColor(colors.black) - term.setTextColor(colorass(colors.red,colors.white)) + term.setTextColor(colorass(colors.red, colors.white)) term.clear() - local cx,cy=math.floor(width/2),math.floor(height/2) + local cx, cy = math.floor(width / 2), math.floor(height / 2) - term.setCursorPos(cx-6,cy-2) + term.setCursorPos(cx - 6, cy - 2) term.write("F A L L I N G") if playersDetected then - if selected==0 then - term.setTextColor(colorass(colors.blue,colors.black)) - term.setBackgroundColor(colorass(colors.gray,colors.white)) + if selected == 0 then + term.setTextColor(colorass(colors.blue, colors.black)) + term.setBackgroundColor(colorass(colors.gray, colors.white)) else - term.setTextColor(colorass(colors.lightBlue,colors.white)) + term.setTextColor(colorass(colors.lightBlue, colors.white)) term.setBackgroundColor(colors.black) end - term.setCursorPos(cx-12,cy) + term.setCursorPos(cx - 12, cy) term.write(" Play head-to-head game! ") end - term.setCursorPos(cx-10,cy+1) - if selected==1 then - term.setTextColor(colorass(colors.blue,colors.black)) - term.setBackgroundColor(colorass(colors.lightGray,colors.white)) + term.setCursorPos(cx - 10, cy + 1) + if selected == 1 then + term.setTextColor(colorass(colors.blue, colors.black)) + term.setBackgroundColor(colorass(colors.lightGray, colors.white)) else - term.setTextColor(colorass(colors.lightBlue,colors.white)) + term.setTextColor(colorass(colors.lightBlue, colors.white)) term.setBackgroundColor(colors.black) end term.write(" Play from level: <" .. level .. "> ") - term.setCursorPos(cx-3,cy+3) - if selected==2 then - term.setTextColor(colorass(colors.blue,colors.black)) - term.setBackgroundColor(colorass(colors.lightGray,colors.white)) + term.setCursorPos(cx - 3, cy + 3) + if selected == 2 then + term.setTextColor(colorass(colors.blue, colors.black)) + term.setBackgroundColor(colorass(colors.lightGray, colors.white)) else - term.setTextColor(colorass(colors.lightBlue,colors.white)) + term.setTextColor(colorass(colors.lightBlue, colors.white)) term.setBackgroundColor(colors.black) end term.write(" Quit ") @@ -606,28 +606,28 @@ local function runMenu() drawMenu() while true do - local event={os.pullEvent()} - if event[1]=="key" then - local key=event[2] - if key==keys.right or key==keys.d and selected==1 then - level=math.min(level+1,9) + local event = {os.pullEvent()} + if event[1] == "key" then + local key = event[2] + if key == keys.right or key == keys.d and selected == 1 then + level = math.min(level + 1, 9) drawMenu() - elseif key==keys.left or key==keys.a and selected==1 then - level=math.max(level-1,1) + elseif key == keys.left or key == keys.a and selected == 1 then + level = math.max(level - 1, 1) drawMenu() - elseif key>=keys.one and key<=keys.nine and selected==1 then - level=key-keys.one + 1 + elseif key >= keys.one and key <= keys.nine and selected == 1 then + level = key - keys.one + 1 drawMenu() - elseif key==keys.up or key==keys.w then - selected=selected-1 - if selected==0 then - selected=2 + elseif key == keys.up or key == keys.w then + selected = selected - 1 + if selected == 0 then + selected = 2 end drawMenu() - elseif key==keys.down or key==keys.s then - selected=selected%2+1 + elseif key == keys.down or key == keys.s then + selected = selected % 2 + 1 drawMenu() - elseif key==keys.enter or key==keys.space then + elseif key == keys.enter or key == keys.space then break --begin play! end end @@ -636,7 +636,7 @@ end while true do runMenu() - if selected==2 then + if selected == 2 then break end @@ -647,4 +647,4 @@ end term.setTextColor(colors.white) term.setBackgroundColor(colors.black) term.clear() -term.setCursorPos(1,1) +term.setCursorPos(1, 1) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index 2bf5404ee..3a772804a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -9,7 +9,7 @@ end local sOpenedModem = nil local function openModem() - for _,sModem in ipairs( peripheral.getNames() ) do + for _, sModem in ipairs( peripheral.getNames() ) do if peripheral.getType( sModem ) == "modem" then if not rednet.isOpen( sModem ) then rednet.open( sModem ) @@ -94,7 +94,7 @@ if sCommand == "host" then end local function printUsers() - local _,y = term.getCursorPos() + local _, y = term.getCursorPos() term.setCursorPos( 1, y - 1 ) term.clearLine() if nUsers == 1 then @@ -114,7 +114,7 @@ if sCommand == "host" then local tUser = tUsers[ nUserID ] if tUser then if not tUser.bPingPonged then - send( "* "..tUser.sUsername.." has timed out" ) + send( "* " .. tUser.sUsername .. " has timed out" ) tUsers[ nUserID ] = nil nUsers = nUsers - 1 printUsers() @@ -131,7 +131,7 @@ if sCommand == "host" then tCommands = { ["me"] = function( tUser, sContent ) if string.len(sContent) > 0 then - send( "* "..tUser.sUsername.." "..sContent ) + send( "* " .. tUser.sUsername .. " " .. sContent ) else send( "* Usage: /me [words]", tUser.nUserID ) end @@ -140,7 +140,7 @@ if sCommand == "host" then if string.len(sContent) > 0 then local sOldName = tUser.sUsername tUser.sUsername = sContent - send( "* "..sOldName.." is now known as "..tUser.sUsername ) + send( "* " .. sOldName .. " is now known as " .. tUser.sUsername ) else send( "* Usage: /nick [nickname]", tUser.nUserID ) end @@ -159,7 +159,7 @@ if sCommand == "host" then for sCommand in pairs( tCommands ) do sCommands = sCommands .. " /" .. sCommand end - send( sCommands.." /logout", tUser.nUserID ) + send( sCommands .. " /logout", tUser.nUserID ) end, } @@ -177,7 +177,7 @@ if sCommand == "host" then } nUsers = nUsers + 1 printUsers() - send( "* "..sUsername.." has joined the chat" ) + send( "* " .. sUsername .. " has joined the chat" ) ping( nUserID ) end @@ -187,7 +187,7 @@ if sCommand == "host" then local tUser = tUsers[ nUserID ] if tUser and tUser.nID == nSenderID then if tMessage.sType == "logout" then - send( "* "..tUser.sUsername.." has left the chat" ) + send( "* " .. tUser.sUsername .. " has left the chat" ) tUsers[ nUserID ] = nil nUsers = nUsers - 1 printUsers() @@ -199,13 +199,13 @@ if sCommand == "host" then if sCommand then local fnCommand = tCommands[ sCommand ] if fnCommand then - local sContent = string.sub( sMessage, string.len(sCommand)+3 ) + local sContent = string.sub( sMessage, string.len(sCommand) + 3 ) fnCommand( tUser, sContent ) else - send( "* Unrecognised command: /"..sCommand, tUser.nUserID ) + send( "* Unrecognised command: /" .. sCommand, tUser.nUserID ) end else - send( "<"..tUser.sUsername.."> "..tMessage.sText ) + send( "<" .. tUser.sUsername .. "> " .. tMessage.sText ) end end @@ -284,12 +284,12 @@ elseif sCommand == "join" then end -- Handle messages - local w,h = term.getSize() + local w, h = term.getSize() local parentTerm = term.current() local titleWindow = window.create( parentTerm, 1, 1, w, 1, true ) - local historyWindow = window.create( parentTerm, 1, 2, w, h-2, true ) + local historyWindow = window.create( parentTerm, 1, 2, w, h - 2, true ) local promptWindow = window.create( parentTerm, 1, h, w, 1, true ) - historyWindow.setCursorPos( 1, h-2 ) + historyWindow.setCursorPos( 1, h - 2 ) term.clear() term.setTextColour( textColour ) @@ -298,9 +298,9 @@ elseif sCommand == "join" then local function drawTitle() local w = titleWindow.getSize() - local sTitle = sUsername.." on "..sHostname + local sTitle = sUsername .. " on " .. sHostname titleWindow.setTextColour( highlightColour ) - titleWindow.setCursorPos( math.floor( w/2 - string.len(sTitle)/2 ), 1 ) + titleWindow.setCursorPos( math.floor( w / 2 - string.len(sTitle) / 2 ), 1 ) titleWindow.clearLine() titleWindow.write( sTitle ) promptWindow.restoreCursor() @@ -347,9 +347,9 @@ elseif sCommand == "join" then end elseif sEvent == "term_resize" then - local w,h = parentTerm.getSize() + local w, h = parentTerm.getSize() titleWindow.reposition( 1, 1, w, 1 ) - historyWindow.reposition( 1, 2, w, h-2 ) + historyWindow.reposition( 1, 2, w, h - 2 ) promptWindow.reposition( 1, h, w, 1 ) end @@ -384,7 +384,7 @@ elseif sCommand == "join" then function() local tSendHistory = {} while true do - promptWindow.setCursorPos( 1,1 ) + promptWindow.setCursorPos( 1, 1 ) promptWindow.clearLine() promptWindow.setTextColor( highlightColour ) promptWindow.write( ": ") @@ -409,7 +409,7 @@ elseif sCommand == "join" then term.redirect( parentTerm ) -- Print error notice - local _,h = term.getSize() + local _, h = term.getSize() term.setCursorPos( 1, h ) term.clearLine() term.setCursorBlink( false ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua index 452ffb587..c6bad5634 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua @@ -1,7 +1,7 @@ -- Find modems local tModems = {} -for _,sModem in ipairs( peripheral.getNames() ) do +for _, sModem in ipairs( peripheral.getNames() ) do if peripheral.getType( sModem ) == "modem" then table.insert( tModems, sModem ) end @@ -16,14 +16,14 @@ else end local function open( nChannel ) - for n=1,#tModems do + for n = 1, #tModems do local sModem = tModems[n] peripheral.call( sModem, "open", nChannel ) end end local function close( nChannel ) - for n=1,#tModems do + for n = 1, #tModems do local sModem = tModems[n] peripheral.call( sModem, "close", nChannel ) end @@ -51,7 +51,7 @@ local ok, error = pcall( function() tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID -- Send on all other open modems, to the target and to other repeaters - for n=1,#tModems do + for n = 1, #tModems do local sOtherModem = tModems[n] peripheral.call( sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage ) peripheral.call( sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage ) @@ -59,7 +59,7 @@ local ok, error = pcall( function() -- Log the event nTransmittedMessages = nTransmittedMessages + 1 - local _,y = term.getCursorPos() + local _, y = term.getCursorPos() term.setCursorPos( 1, y - 1 ) term.clearLine() if nTransmittedMessages == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua index ff38a89ef..ff7f87a48 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua @@ -17,7 +17,7 @@ if sCommand == "probe" then local count = 0 local bundledCount = 0 - for _,sSide in ipairs( redstone.getSides() ) do + for _, sSide in ipairs( redstone.getSides() ) do if redstone.getBundledInput( sSide ) > 0 then bundledCount = bundledCount + 1 end @@ -39,12 +39,12 @@ if sCommand == "probe" then if bundledCount > 0 then print() print( "Bundled inputs:" ) - for _,sSide in ipairs( redstone.getSides() ) do + for _, sSide in ipairs( redstone.getSides() ) do local nInput = redstone.getBundledInput( sSide ) if nInput ~= 0 then - write( sSide..": " ) + write( sSide .. ": " ) local count = 0 - for sColour,nColour in pairs( colors ) do + for sColour, nColour in pairs( colors ) do if type( nColour ) == "number" and colors.test( nInput, nColour ) then if count > 0 then write( ", " ) @@ -69,7 +69,7 @@ elseif sCommand == "pulse" then local sSide = tArgs[2] local nCount = tonumber( tArgs[3] ) or 1 local nPeriod = tonumber( tArgs[4] ) or 0.5 - for _=1,nCount do + for _ = 1, nCount do redstone.setOutput( sSide, true ) sleep( nPeriod / 2 ) redstone.setOutput( sSide, false ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua index 94ef6b621..f2bacabcc 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua @@ -2,12 +2,12 @@ local tArgs = { ... } if #tArgs == 0 then -- "set" - local _,y = term.getCursorPos() + local _, y = term.getCursorPos() local tSettings = {} - for n,sName in ipairs( settings.getNames() ) do + for n, sName in ipairs( settings.getNames() ) do tSettings[n] = textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) end - textutils.pagedPrint(table.concat(tSettings,"\n"),y-3) + textutils.pagedPrint(table.concat(tSettings, "\n"), y - 3) elseif #tArgs == 1 then -- "set foo" diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 13c4b90c0..5628f0c6f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -33,9 +33,9 @@ local function createShellEnv( sDir ) } package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" if turtle then - package.path = package.path..";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" + package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" elseif command then - package.path = package.path..";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" + package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" end package.config = "/\n;\n?\n!\n-" package.preload = {} @@ -52,7 +52,7 @@ local function createShellEnv( sDir ) local sError = "" for pattern in string.gmatch(package.path, "[^;]+") do local sPath = string.gsub(pattern, "%?", fname) - if sPath:sub(1,1) ~= "/" then + if sPath:sub(1, 1) ~= "/" then sPath = fs.combine(sDir, sPath) end if fs.exists(sPath) and not fs.isDir(sPath) then @@ -70,7 +70,7 @@ local function createShellEnv( sDir ) end end return nil, sError - end + end, } local sentinel = {} @@ -125,7 +125,7 @@ local function run( _sCommand, ... ) if multishell then local sTitle = fs.getName( sPath ) if sTitle:sub(-4) == ".lua" then - sTitle = sTitle:sub(1,-5) + sTitle = sTitle:sub(1, -5) end multishell.setTitle( multishell.getCurrent(), sTitle ) end @@ -140,7 +140,7 @@ local function run( _sCommand, ... ) if #tProgramStack > 0 then local sTitle = fs.getName( tProgramStack[#tProgramStack] ) if sTitle:sub(-4) == ".lua" then - sTitle = sTitle:sub(1,-5) + sTitle = sTitle:sub(1, -5) end multishell.setTitle( multishell.getCurrent(), sTitle ) else @@ -272,12 +272,12 @@ function shell.programs( _bIncludeHidden ) sPath = shell.resolve( sPath ) if fs.isDir( sPath ) then local tList = fs.list( sPath ) - for n=1,#tList do + for n = 1, #tList do local sFile = tList[n] if not fs.isDir( fs.combine( sPath, sFile ) ) and (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then if #sFile > 4 and sFile:sub(-4) == ".lua" then - sFile = sFile:sub(1,-5) + sFile = sFile:sub(1, -5) end tItems[ sFile ] = true end @@ -326,7 +326,7 @@ local function completeProgram( sLine ) -- Add programs from the path local tPrograms = shell.programs() - for n=1,#tPrograms do + for n = 1, #tPrograms do local sProgram = tPrograms[n] if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then local sResult = string.sub( sProgram, #sLine + 1 ) @@ -366,7 +366,7 @@ function shell.complete( sLine ) return { " " } else local tResults = completeProgram( sBit ) - for n=1,#tResults do + for n = 1, #tResults do local sResult = tResults[n] local sPath = shell.resolveProgram( sBit .. sResult ) if tCompletionInfo[ sPath ] then @@ -397,7 +397,7 @@ function shell.setCompletionFunction( sProgram, fnComplete ) expect(1, sProgram, "string") expect(2, fnComplete, "function") tCompletionInfo[ sProgram ] = { - fnComplete = fnComplete + fnComplete = fnComplete, } end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/time.lua b/src/main/resources/assets/computercraft/lua/rom/programs/time.lua index ff5fac8f2..ccd83d4ec 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/time.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/time.lua @@ -1,3 +1,3 @@ local nTime = os.time() local nDay = os.day() -print( "The time is "..textutils.formatTime( nTime, false ).." on Day "..nDay ) +print( "The time is " .. textutils.formatTime( nTime, false ) .. " on Day " .. nDay ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua index 8b273c2d6..8b8923e71 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua @@ -29,7 +29,7 @@ if turtle.craft( nLimit ) then end if nCrafted > 1 then - print( nCrafted.." items crafted" ) + print( nCrafted .. " items crafted" ) elseif nCrafted == 1 then print( "1 item crafted" ) else diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua index 246992f78..696c15747 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua @@ -81,10 +81,10 @@ textutils.slowWrite( "Preparing to get down." ) textutils.slowPrint( "..", 0.75 ) local sAudio = nil -for _,sName in pairs( peripheral.getNames() ) do +for _, sName in pairs( peripheral.getNames() ) do if disk.hasAudio( sName ) then disk.playAudio( sName ) - print( "Jamming to "..disk.getAudioTitle( sName ) ) + print( "Jamming to " .. disk.getAudioTitle( sName ) ) sAudio = sName break end @@ -103,7 +103,7 @@ parallel.waitForAny( end, function() while true do - local fnMove = tMoves[math.random(1,#tMoves)] + local fnMove = tMoves[math.random(1, #tMoves)] fnMove() end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua index 5e7f32274..2edc5b1fa 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua @@ -20,15 +20,15 @@ local depth = 0 local unloaded = 0 local collected = 0 -local xPos,zPos = 0,0 -local xDir,zDir = 0,1 +local xPos, zPos = 0, 0 +local xDir, zDir = 0, 1 local goTo -- Filled in further down local refuel -- Filled in further down local function unload( _bKeepOneFuelStack ) print( "Unloading items..." ) - for n=1,16 do + for n = 1, 16 do local nCount = turtle.getItemCount(n) if nCount > 0 then turtle.select(n) @@ -48,11 +48,11 @@ local function unload( _bKeepOneFuelStack ) end local function returnSupplies() - local x,y,z,xd,zd = xPos,depth,zPos,xDir,zDir + local x, y, z, xd, zd = xPos, depth, zPos, xDir, zDir print( "Returning to surface..." ) - goTo( 0,0,0,0,-1 ) + goTo( 0, 0, 0, 0, -1 ) - local fuelNeeded = 2*(x+y+z) + 1 + local fuelNeeded = 2 * (x + y + z) + 1 if not refuel( fuelNeeded ) then unload( true ) print( "Waiting for fuel" ) @@ -64,13 +64,13 @@ local function returnSupplies() end print( "Resuming mining..." ) - goTo( x,y,z,xd,zd ) + goTo( x, y, z, xd, zd ) end local function collect() local bFull = true local nTotalItems = 0 - for n=1,16 do + for n = 1, 16 do local nCount = turtle.getItemCount(n) if nCount == 0 then bFull = false @@ -81,7 +81,7 @@ local function collect() if nTotalItems > collected then collected = nTotalItems if math.fmod(collected + unloaded, 50) == 0 then - print( "Mined "..collected + unloaded.." items." ) + print( "Mined " .. collected + unloaded .. " items." ) end end @@ -100,7 +100,7 @@ function refuel( ammount ) local needed = ammount or xPos + zPos + depth + 2 if turtle.getFuelLevel() < needed then - for n=1,16 do + for n = 1, 16 do if turtle.getItemCount(n) > 0 then turtle.select(n) if turtle.refuel(1) then @@ -176,7 +176,7 @@ local function tryDown() depth = depth + 1 if math.fmod( depth, 10 ) == 0 then - print( "Descended "..depth.." metres." ) + print( "Descended " .. depth .. " metres." ) end return true @@ -290,8 +290,8 @@ end local alternate = 0 local done = false while not done do - for n=1,size do - for _=1,size-1 do + for n = 1, size do + for _ = 1, size - 1 do if not tryForwards() then done = true break @@ -300,8 +300,8 @@ while not done do if done then break end - if n 1 then - if math.fmod(size,2) == 0 then + if math.fmod(size, 2) == 0 then turnRight() else if alternate == 0 then @@ -344,13 +344,13 @@ end print( "Returning to surface..." ) -- Return to where we started -goTo( 0,0,0,0,-1 ) +goTo( 0, 0, 0, 0, -1 ) unload( false ) -goTo( 0,0,0,0,1 ) +goTo( 0, 0, 0, 0, 1 ) -- Seal the hole if reseal then turtle.placeDown() end -print( "Mined "..collected + unloaded.." items total." ) +print( "Mined " .. collected + unloaded .. " items total." ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua index c84120ce0..c8b43b0e9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua @@ -50,7 +50,7 @@ while nArg <= #tArgs do end end else - print( "No such direction: "..sDirection ) + print( "No such direction: " .. sDirection ) print( "Try: forward, back, up, down" ) return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua index fa69de01c..77f796196 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua @@ -36,7 +36,7 @@ if turtle.getFuelLevel() ~= "unlimited" then end end end - print( "Fuel level is "..turtle.getFuelLevel() ) + print( "Fuel level is " .. turtle.getFuelLevel() ) if turtle.getFuelLevel() == turtle.getFuelLimit() then print( "Fuel limit reached" ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua index 9bf4e2665..50183d013 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua @@ -20,7 +20,7 @@ local collected = 0 local function collect() collected = collected + 1 if math.fmod(collected, 25) == 0 then - print( "Mined "..collected.." items." ) + print( "Mined " .. collected .. " items." ) end end @@ -67,7 +67,7 @@ local function refuel() end local function tryRefuel() - for n=1,16 do + for n = 1, 16 do if turtle.getItemCount(n) > 0 then turtle.select(n) if turtle.refuel(1) then @@ -139,7 +139,7 @@ end print( "Tunnelling..." ) -for n=1,length do +for n = 1, length do turtle.placeDown() tryDigUp() turtle.turnLeft() @@ -153,7 +153,7 @@ for n=1,length do tryDig() turtle.turnLeft() - if n 0 then info = info .. (" Skipped %d pending test(s)."):format(test_status.pending) diff --git a/src/test/resources/test-rom/spec/apis/gps_spec.lua b/src/test/resources/test-rom/spec/apis/gps_spec.lua index 8d61a5c37..1e0a49f87 100644 --- a/src/test/resources/test-rom/spec/apis/gps_spec.lua +++ b/src/test/resources/test-rom/spec/apis/gps_spec.lua @@ -2,7 +2,7 @@ describe("The gps library", function() describe("gps.locate", function() it("validates arguments", function() stub(_G, "commands", { getBlockPosition = function() - end }) + end, }) gps.locate() gps.locate(1) diff --git a/src/test/resources/test-rom/spec/apis/io_spec.lua b/src/test/resources/test-rom/spec/apis/io_spec.lua index 9dad5f7ec..484588014 100644 --- a/src/test/resources/test-rom/spec/apis/io_spec.lua +++ b/src/test/resources/test-rom/spec/apis/io_spec.lua @@ -60,10 +60,10 @@ describe("The io library", function() expect(io.output():seek()):equal(0) assert(io.write("alo alo")) - expect(io.output():seek()):equal(#("alo alo")) - expect(io.output():seek("cur", -3)):equal(#("alo alo") - 3) + expect(io.output():seek()):equal(#"alo alo") + expect(io.output():seek("cur", -3)):equal(#"alo alo" - 3) assert(io.write("joao")) - expect(io.output():seek("end"):equal(#("alo joao"))) + expect(io.output():seek("end"):equal(#"alo joao")) expect(io.output():seek("set")):equal(0) diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua index 43de8239d..8ce2213bf 100644 --- a/src/test/resources/test-rom/spec/base_spec.lua +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -70,7 +70,7 @@ describe("The Lua base library", function() it("does not prefix for unnamed chunks", function() local info = debug.getinfo(loadstring("return 1"), "S") - expect(info):matches { short_src = '[string "return 1"]', source = "return 1", } + expect(info):matches { short_src = '[string "return 1"]', source = "return 1" } end) it("does not prefix when already prefixed", function() diff --git a/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua index 7f7fd0a40..ffcd3b7f3 100644 --- a/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua @@ -5,7 +5,7 @@ describe("cc.shell.completion", function() it("completes both", function() expect(c.dirOrFile(shell, "rom/")):same { "apis/", "apis", "autorun/", "autorun", "help/", "help", - "modules/", "modules", "motd.txt", "programs/", "programs", "startup.lua" + "modules/", "modules", "motd.txt", "programs/", "programs", "startup.lua", } end) diff --git a/src/test/resources/test-rom/spec/programs/command/commands_spec.lua b/src/test/resources/test-rom/spec/programs/command/commands_spec.lua index d7261b9d1..6c9d87cdc 100644 --- a/src/test/resources/test-rom/spec/programs/command/commands_spec.lua +++ b/src/test/resources/test-rom/spec/programs/command/commands_spec.lua @@ -10,7 +10,7 @@ describe("The commands program", function() it("lists commands", function() local pagedTabulate = stub(textutils, "pagedTabulate", function(x) print(table.unpack(x)) end) stub(_G, "commands", { - list = function() return { "computercraft" } end + list = function() return { "computercraft" } end, }) expect(capture(stub, "/rom/programs/command/commands.lua")) diff --git a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua index 869222b2c..0c12b18a7 100644 --- a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua +++ b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua @@ -15,7 +15,7 @@ describe("The exec program", function() it("runs a command", function() stub(_G, "commands", { - exec = function() return true, {"Hello World!"} end + exec = function() return true, {"Hello World!"} end, }) expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) @@ -23,8 +23,8 @@ describe("The exec program", function() end) it("reports command failures", function() - stub(_G,"commands",{ - exec = function() return false, {"Hello World!"} end + stub(_G, "commands", { + exec = function() return false, {"Hello World!"} end, }) expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) diff --git a/src/test/resources/test-rom/spec/programs/edit_spec.lua b/src/test/resources/test-rom/spec/programs/edit_spec.lua index 137c39c83..7ca0b04f2 100644 --- a/src/test/resources/test-rom/spec/programs/edit_spec.lua +++ b/src/test/resources/test-rom/spec/programs/edit_spec.lua @@ -1,5 +1,4 @@ local capture = require "test_helpers".capture_program -local testFile = require "test_helpers".testFile describe("The edit program", function() diff --git a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua index eb55f53d4..5b13d59a9 100644 --- a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -17,7 +17,7 @@ describe("The pastebin program", function() local tHeader = {} tHeader["Content-Type"] = "text/plain; charset=utf-8" return tHeader - end + end, } end, post = function() @@ -28,7 +28,7 @@ describe("The pastebin program", function() close = function() end, } - end + end, }) end diff --git a/src/test/resources/test-rom/spec/programs/http/wget_spec.lua b/src/test/resources/test-rom/spec/programs/http/wget_spec.lua index b6b88b34b..75d82c671 100644 --- a/src/test/resources/test-rom/spec/programs/http/wget_spec.lua +++ b/src/test/resources/test-rom/spec/programs/http/wget_spec.lua @@ -14,7 +14,7 @@ describe("The wget program", function() close = function() end, } - end + end, }) end diff --git a/src/test/resources/test-rom/spec/programs/id_spec.lua b/src/test/resources/test-rom/spec/programs/id_spec.lua index a4e4657d3..73206e7fb 100644 --- a/src/test/resources/test-rom/spec/programs/id_spec.lua +++ b/src/test/resources/test-rom/spec/programs/id_spec.lua @@ -6,6 +6,6 @@ describe("The id program", function() local id = os.getComputerID() expect(capture(stub, "id")) - :matches { ok = true, output = "This is computer #"..id.."\n", error = "" } + :matches { ok = true, output = "This is computer #" .. id .. "\n", error = "" } end) end) diff --git a/src/test/resources/test-rom/spec/programs/motd_spec.lua b/src/test/resources/test-rom/spec/programs/motd_spec.lua index 052cd8fa4..3781e2e16 100644 --- a/src/test/resources/test-rom/spec/programs/motd_spec.lua +++ b/src/test/resources/test-rom/spec/programs/motd_spec.lua @@ -3,10 +3,10 @@ local capture = require "test_helpers".capture_program describe("The motd program", function() it("displays MODT", function() - local file = fs.open("/modt_check.txt","w") + local file = fs.open("/modt_check.txt", "w") file.write("Hello World!") file.close() - settings.set("motd.path","/modt_check.txt") + settings.set("motd.path", "/modt_check.txt") expect(capture(stub, "motd")) :matches { ok = true, output = "Hello World!\n", error = "" } diff --git a/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua b/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua index 0c3fb3183..32144051b 100644 --- a/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua +++ b/src/test/resources/test-rom/spec/programs/pocket/equip_spec.lua @@ -9,7 +9,7 @@ describe("The pocket equip program", function() it("can equip an upgrade", function() stub(_G, "pocket", { - equipBack = function() return true end + equipBack = function() return true end, }) expect(capture(stub, "/rom/programs/pocket/equip.lua")) @@ -18,7 +18,7 @@ describe("The pocket equip program", function() it("handles when an upgrade cannot be equipped", function() stub(_G, "pocket", { - equipBack = function() return false, "Cannot equip this item." end + equipBack = function() return false, "Cannot equip this item." end, }) expect(capture(stub, "/rom/programs/pocket/equip.lua")) diff --git a/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua index 85a1e640f..9cb0f7481 100644 --- a/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua +++ b/src/test/resources/test-rom/spec/programs/pocket/unequip_spec.lua @@ -9,7 +9,7 @@ describe("The pocket unequip program", function() it("unequips an upgrade", function() stub(_G, "pocket", { - unequipBack = function() return true end + unequipBack = function() return true end, }) expect(capture(stub, "/rom/programs/pocket/unequip.lua")) @@ -18,7 +18,7 @@ describe("The pocket unequip program", function() it("handles when an upgrade cannot be equipped", function() stub(_G, "pocket", { - unequipBack = function() return false, "Nothing to remove." end + unequipBack = function() return false, "Nothing to remove." end, }) expect(capture(stub, "/rom/programs/pocket/unequip.lua")) diff --git a/src/test/resources/test-rom/spec/programs/set_spec.lua b/src/test/resources/test-rom/spec/programs/set_spec.lua index dc81dcfe3..64dba1447 100644 --- a/src/test/resources/test-rom/spec/programs/set_spec.lua +++ b/src/test/resources/test-rom/spec/programs/set_spec.lua @@ -4,8 +4,8 @@ describe("The set program", function() it("displays all settings", function() settings.clear() - settings.set("Test","Hello World!") - settings.set("123",456) + settings.set("Test", "Hello World!") + settings.set("123", 456) expect(capture(stub, "set")) :matches { ok = true, output = '"123" is 456\n"Test" is "Hello World!"\n', error = "" } @@ -13,8 +13,8 @@ describe("The set program", function() it("displays a single settings", function() settings.clear() - settings.set("Test","Hello World!") - settings.set("123",456) + settings.set("Test", "Hello World!") + settings.set("123", 456) expect(capture(stub, "set Test")) :matches { ok = true, output = '"Test" is "Hello World!"\n', error = "" } diff --git a/src/test/resources/test-rom/spec/programs/time_spec.lua b/src/test/resources/test-rom/spec/programs/time_spec.lua index 8ec10044e..e9c1eff31 100644 --- a/src/test/resources/test-rom/spec/programs/time_spec.lua +++ b/src/test/resources/test-rom/spec/programs/time_spec.lua @@ -7,6 +7,6 @@ describe("The time program", function() local day = os.day() expect(capture(stub, "time")) - :matches { ok = true, output = "The time is "..time.." on Day "..day.."\n", error = "" } + :matches { ok = true, output = "The time is " .. time .. " on Day " .. day .. "\n", error = "" } end) end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua index 43b7ea982..11934b7ec 100644 --- a/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua +++ b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua @@ -39,7 +39,7 @@ describe("The craft program", function() it("craft a single item", function() local item_count = 2 - stub(_G,"turtle",{ + stub(_G, "turtle", { craft = function() item_count = 1 return true @@ -54,7 +54,7 @@ describe("The craft program", function() it("crafts no items", function() local item_count = 2 - stub(_G,"turtle",{ + stub(_G, "turtle", { craft = function() item_count = 1 return false diff --git a/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua index 2e637fc82..09284f8a6 100644 --- a/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua +++ b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua @@ -29,7 +29,7 @@ describe("The turtle equip program", function() end) it("swaps existing upgrades", function() - stub(_G,"turtle",{ + stub(_G, "turtle", { select = function() end, getItemCount = function() return 1 end, equipLeft = function() return true end, @@ -45,7 +45,7 @@ describe("The turtle equip program", function() describe("equips a new upgrade", function() local function setup() local item_count = 1 - stub(_G,"turtle",{ + stub(_G, "turtle", { select = function() end, getItemCount = function() return item_count end, equipLeft = function() @@ -73,7 +73,7 @@ describe("The turtle equip program", function() end) it("handles when an upgrade cannot be equipped", function() - stub(_G,"turtle",{ + stub(_G, "turtle", { select = function() end, getItemCount = function() return 1 end, equipLeft = function() return false end, diff --git a/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua index 3b6283260..986d028c1 100644 --- a/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua +++ b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua @@ -17,7 +17,7 @@ describe("The refuel program", function() end, getFuelLimit = function() return fuel_limit - end + end, }) end @@ -49,13 +49,13 @@ describe("The refuel program", function() end) it("reports when the fuel limit is reached", function() - setup_turtle(0,5,5) + setup_turtle(0, 5, 5) expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) :matches { ok = true, output = "Fuel level is 5\nFuel limit reached\n", error = "" } end) it("reports when the fuel level is unlimited", function() - setup_turtle("unlimited",5,5) + setup_turtle("unlimited", 5, 5) expect(capture(stub, "/rom/programs/turtle/refuel.lua 5")) :matches { ok = true, output = "Fuel level is unlimited\n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua index 1cb97b440..eea58f78f 100644 --- a/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua +++ b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua @@ -17,11 +17,11 @@ describe("The turtle unequip program", function() end) it("says when nothing was unequipped", function() - stub(_G,"turtle",{ + stub(_G, "turtle", { select = function() end, getItemCount = function() return 0 end, equipRight = function() return true end, - equipLeft = function() return true end + equipLeft = function() return true end, }) expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) @@ -32,7 +32,7 @@ describe("The turtle unequip program", function() it("unequips a upgrade", function() local item_count = 0 - stub(_G,"turtle",{ + stub(_G, "turtle", { select = function() end, getItemCount = function() return item_count end, equipRight = function() @@ -42,7 +42,7 @@ describe("The turtle unequip program", function() equipLeft = function() item_count = 1 return true - end + end, }) expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) @@ -53,11 +53,11 @@ describe("The turtle unequip program", function() end) it("fails when the turtle is full", function() - stub(_G,"turtle",{ + stub(_G, "turtle", { select = function() end, getItemCount = function() return 1 end, equipRight = function() return true end, - equipLeft = function() return true end + equipLeft = function() return true end, }) expect(capture(stub, "/rom/programs/turtle/unequip.lua left")) diff --git a/src/test/resources/test-rom/spec/test_helpers.lua b/src/test/resources/test-rom/spec/test_helpers.lua index 6ffe3942d..74b94b7e2 100644 --- a/src/test/resources/test-rom/spec/test_helpers.lua +++ b/src/test/resources/test-rom/spec/test_helpers.lua @@ -37,7 +37,7 @@ local function capture_program(stub, program, ...) output = table.concat(output), error = table.concat(error), combined = table.concat(combined), - ok = ok + ok = ok, } end From b0397ed3c533a011e52b32d6e03a2accd3477ecb Mon Sep 17 00:00:00 2001 From: Jared Allard Date: Sun, 8 Dec 2019 09:10:58 -0800 Subject: [PATCH 108/711] Add support for HTTP PATCH and TRACE (#324) --- .github/workflows/main-ci.yml | 2 +- src/main/resources/assets/computercraft/lua/bios.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 0be633a53..649c36da6 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -30,4 +30,4 @@ jobs: test -d bin || mkdir bin test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/bin/illuaminate chmod +x bin/illuaminate - GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} bin/illuaminate lint --github + bin/illuaminate lint diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 4a30d22da..42ae840f1 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -681,6 +681,7 @@ if http then local methods = { GET = true, POST = true, HEAD = true, OPTIONS = true, PUT = true, DELETE = true, + PATCH = true, TRACE = true, } local function checkKey( options, key, ty, opt ) From 03b6d2f1aba131fdaa3e28a0f50ae769d76c296b Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 10 Dec 2019 18:54:43 +0000 Subject: [PATCH 109/711] Replace string.len with # --- .luacheckrc | 35 ----------------- illuaminate.sexp | 10 +++-- .../assets/computercraft/lua/bios.lua | 14 +++---- .../computercraft/lua/rom/apis/textutils.lua | 6 +-- .../lua/rom/programs/advanced/multishell.lua | 2 +- .../computercraft/lua/rom/programs/edit.lua | 38 +++++++++---------- .../lua/rom/programs/fun/advanced/paint.lua | 2 +- .../rom/programs/fun/advanced/redirection.lua | 8 ++-- .../lua/rom/programs/fun/worm.lua | 2 +- .../lua/rom/programs/rednet/chat.lua | 10 ++--- 10 files changed, 47 insertions(+), 80 deletions(-) delete mode 100644 .luacheckrc diff --git a/.luacheckrc b/.luacheckrc deleted file mode 100644 index 3bf2c2c41..000000000 --- a/.luacheckrc +++ /dev/null @@ -1,35 +0,0 @@ -std = "max" - -ignore = { - -- Allow access to undefined globals or their fields. In the future we'll - -- define all of CC's globals within this file - '113', '143', - - -- FIXME: Ignore unused arguments and loop variables - '212', '213', - - -- Disable line is too long for now. It would be possible to clean - -- this up in the future. - '631', -} - --- Only run the linter on ROM and bios for now, as the treasure disks --- are largely unsupported. -include_files = { - 'src/main/resources/assets/computercraft/lua/rom', - 'src/main/resources/assets/computercraft/lua/bios.lua', - 'src/test/resources/test-rom', -} - -files['src/main/resources/assets/computercraft/lua/bios.lua'] = { - -- Allow declaring and mutating globals - allow_defined_top = true, - ignore = { '112', '121', '122', '131', '142' }, -} - -files['src/main/resources/assets/computercraft/lua/rom/apis'] = { - -- APIs may define globals on the top level. We'll ignore unused globals, - -- as obviously they may be used outside that API. - allow_defined_top = true, - ignore = { '131' }, -} diff --git a/illuaminate.sexp b/illuaminate.sexp index b4deb17bd..b37f34928 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -7,20 +7,22 @@ (at / (linters - ;; It'd be nice to avoid this, but right now there's a lot of instances of it. + ;; It'd be nice to avoid this, but right now there's a lot of instances of + ;; it. -var:set-loop ;; It's useful to name arguments for documentation, so we allow this. It'd ;; be good to find a compromise in the future, but this works for now. -var:unused-arg)) -;; We disable the two global linters in bios.lua and the APIs. In the future +;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. (at (/src/main/resources/assets/computercraft/lua/bios.lua /src/main/resources/assets/computercraft/lua/rom/apis/) - (linters -var:set-global -var:unused-global)) + (linters -var:unused-global) + (lint + (allow-toplevel-global true))) ;; These warnings are broken right now -(at completion.lua (linters -doc:malformed-type)) (at (bios.lua worm.lua) (linters -control:unreachable)) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 42ae840f1..0cceccf99 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -207,13 +207,13 @@ function write( sText ) end -- Print the line with proper word wrapping - while string.len(sText) > 0 do + while #sText > 0 do local whitespace = string.match( sText, "^[ \t]+" ) if whitespace then -- Print whitespace term.write( whitespace ) x, y = term.getCursorPos() - sText = string.sub( sText, string.len(whitespace) + 1 ) + sText = string.sub( sText, #whitespace + 1 ) end local newline = string.match( sText, "^\n" ) @@ -225,10 +225,10 @@ function write( sText ) local text = string.match( sText, "^[^ \t\n]+" ) if text then - sText = string.sub( sText, string.len(text) + 1 ) - if string.len(text) > w then + sText = string.sub( sText, #text + 1 ) + if #text > w then -- Print a multiline word - while string.len( text ) > 0 do + while #text > 0 do if x > w then newLine() end @@ -238,7 +238,7 @@ function write( sText ) end else -- Print a word normally - if x + string.len(text) - 1 > w then + if x + #text - 1 > w then newLine() end term.write( text ) @@ -299,7 +299,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local tCompletions local nCompletion local function recomplete() - if _fnComplete and nPos == string.len(sLine) then + if _fnComplete and nPos == #sLine then tCompletions = _fnComplete( sLine ) if tCompletions and #tCompletions > 0 then nCompletion = 1 diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 5044d9dc3..38360ea71 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -10,7 +10,7 @@ function slowWrite( sText, nRate ) sText = tostring( sText ) local x, y = term.getCursorPos() - local len = string.len( sText ) + local len = #sText for n = 1, len do term.setCursorPos( x, y ) @@ -116,7 +116,7 @@ local function tabulateCommon( bPaged, ... ) if type( sItem ) ~= "string" then error( "bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type( sItem ) .. ")", 3 ) end - nMaxLen = math.max( string.len( sItem ) + 1, nMaxLen ) + nMaxLen = math.max( #sItem + 1, nMaxLen ) end end end @@ -388,7 +388,7 @@ function complete( sSearchText, tSearchTable ) end local sPart = string.sub( sSearchText, nStart ) - local nPartLength = string.len( sPart ) + local nPartLength = #sPart local tResults = {} local tSeen = {} diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index 757691e27..75dd3b3da 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -287,7 +287,7 @@ while #tProcesses > 0 do tabStart = 2 end for n = nScrollPos, #tProcesses do - local tabEnd = tabStart + string.len( tProcesses[n].sTitle ) + 1 + local tabEnd = tabStart + #tProcesses[n].sTitle + 1 if x >= tabStart and x <= tabEnd then selectProcess( n ) redrawMenu() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index bfa682843..5e6cfee1c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -62,7 +62,7 @@ end table.insert( tMenuItems, "Exit" ) local sStatus = "Press Ctrl to access menu" -if string.len( sStatus ) > w - 5 then +if #sStatus > w - 5 then sStatus = "Press Ctrl for menu" end @@ -144,13 +144,13 @@ local function tryWrite( sLine, regex, colour ) end term.write( match ) term.setTextColour( textColour ) - return string.sub( sLine, string.len(match) + 1 ) + return string.sub( sLine, #match + 1 ) end return nil end local function writeHighlighted( sLine ) - while string.len(sLine) > 0 do + while #sLine > 0 do sLine = tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or tryWrite( sLine, "^%-%-.*", commentColour ) or @@ -188,7 +188,7 @@ end local function recomplete() local sLine = tLines[y] - if not bMenu and not bReadOnly and x == string.len(sLine) + 1 then + if not bMenu and not bReadOnly and x == #sLine + 1 then tCompletions = complete( sLine ) if tCompletions and #tCompletions > 0 then nCompletion = 1 @@ -248,7 +248,7 @@ local function redrawMenu() term.clearLine() -- Draw line numbers - term.setCursorPos( w - string.len( "Ln " .. y ) + 1, h ) + term.setCursorPos( w - #( "Ln " .. y ) + 1, h ) term.setTextColour( highlightColour ) term.write( "Ln " ) term.setTextColour( textColour ) @@ -468,7 +468,7 @@ local function acceptCompletion() -- Append the completion local sCompletion = tCompletions[ nCompletion ] tLines[y] = tLines[y] .. sCompletion - setCursor( x + string.len( sCompletion ), y ) + setCursor( x + #sCompletion , y ) end end @@ -490,7 +490,7 @@ while bRunning do elseif y > 1 then -- Move cursor up setCursor( - math.min( x, string.len( tLines[y - 1] ) + 1 ), + math.min( x, #tLines[y - 1] + 1 ), y - 1 ) end @@ -511,7 +511,7 @@ while bRunning do elseif y < #tLines then -- Move cursor down setCursor( - math.min( x, string.len( tLines[y + 1] ) + 1 ), + math.min( x, #tLines[y + 1] + 1 ), y + 1 ) end @@ -520,7 +520,7 @@ while bRunning do elseif param == keys.tab then -- Tab if not bMenu and not bReadOnly then - if nCompletion and x == string.len(tLines[y]) + 1 then + if nCompletion and x == #tLines[y] + 1 then -- Accept autocomplete acceptCompletion() else @@ -542,7 +542,7 @@ while bRunning do newY = 1 end setCursor( - math.min( x, string.len( tLines[newY] ) + 1 ), + math.min( x, #tLines[newY] + 1 ), newY ) end @@ -557,7 +557,7 @@ while bRunning do else newY = #tLines end - local newX = math.min( x, string.len( tLines[newY] ) + 1 ) + local newX = math.min( x, #tLines[newY] + 1 ) setCursor( newX, newY ) end @@ -574,7 +574,7 @@ while bRunning do -- End if not bMenu then -- Move cursor to the end - local nLimit = string.len( tLines[y] ) + 1 + local nLimit = #tLines[y] + 1 if x < nLimit then setCursor( nLimit, y ) end @@ -587,7 +587,7 @@ while bRunning do -- Move cursor left setCursor( x - 1, y ) elseif x == 1 and y > 1 then - setCursor( string.len( tLines[y - 1] ) + 1, y - 1 ) + setCursor( #tLines[y - 1] + 1, y - 1 ) end else -- Move menu left @@ -601,11 +601,11 @@ while bRunning do elseif param == keys.right then -- Right if not bMenu then - local nLimit = string.len( tLines[y] ) + 1 + local nLimit = #tLines[y] + 1 if x < nLimit then -- Move cursor right setCursor( x + 1, y ) - elseif nCompletion and x == string.len(tLines[y]) + 1 then + elseif nCompletion and x == #tLines[y] + 1 then -- Accept autocomplete acceptCompletion() elseif x == nLimit and y < #tLines then @@ -624,7 +624,7 @@ while bRunning do elseif param == keys.delete then -- Delete if not bMenu and not bReadOnly then - local nLimit = string.len( tLines[y] ) + 1 + local nLimit = #tLines[y] + 1 if x < nLimit then local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. string.sub(sLine, x + 1) @@ -653,7 +653,7 @@ while bRunning do end elseif y > 1 then -- Remove newline - local sPrevLen = string.len( tLines[y - 1] ) + local sPrevLen = #tLines[y - 1] tLines[y - 1] = tLines[y - 1] .. tLines[y] table.remove( tLines, y ) setCursor( sPrevLen + 1, y - 1 ) @@ -721,7 +721,7 @@ while bRunning do -- Input text local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) - setCursor( x + string.len( param ), y ) + setCursor( x + #param , y ) end elseif sEvent == "mouse_click" then @@ -731,7 +731,7 @@ while bRunning do local cx, cy = param2, param3 if cy < h then local newY = math.min( math.max( scrollY + cy, 1 ), #tLines ) - local newX = math.min( math.max( scrollX + cx, 1 ), string.len( tLines[newY] ) + 1 ) + local newX = math.min( math.max( scrollX + cx, 1 ), #tLines[newY] + 1 ) setCursor( newX, newY ) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index 2e77847e0..758e82074 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -148,7 +148,7 @@ local function save(path) end sLine = string.sub( sLine, 1, nLastChar ) tLines[y] = sLine - if string.len( sLine ) > 0 then + if #sLine > 0 then nLastLine = y end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua index a84117bdb..fc6e0f038 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua @@ -60,7 +60,7 @@ local tArgs = { ... } --Functions-- local function printCentred( yc, stg ) - local xc = math.floor((TermW - string.len(stg)) / 2) + 1 + local xc = math.floor((TermW - #stg) / 2) + 1 term.setCursorPos(xc, yc) term.write( stg ) end @@ -179,7 +179,7 @@ local function loadLevel(nNum) fLevel = fs.open(sLevelD, "r") local wl = true Blocks = tonumber(string.sub(fLevel.readLine(), 1, 1)) - local xSize = string.len(fLevel.readLine()) + 2 + local xSize = #fLevel.readLine() + 2 local Lines = 3 while wl do local wLine = fLevel.readLine() @@ -187,7 +187,7 @@ local function loadLevel(nNum) fLevel.close() wl = false else - xSize = math.max(string.len(wLine) + 2, xSize) + xSize = math.max(#wLine + 2, xSize) Lines = Lines + 1 end end @@ -197,7 +197,7 @@ local function loadLevel(nNum) fLevel.readLine() for Line = 2, Lines - 1 do local sLine = fLevel.readLine() - local chars = string.len(sLine) + local chars = #sLine for char = 1, chars do local el = string.sub(sLine, char, char) if el == "8" then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua index cc55288fb..507763cb4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua @@ -16,7 +16,7 @@ else end local function printCentred( y, s ) - local x = math.floor((w - string.len(s)) / 2) + local x = math.floor((w - #s) / 2) term.setCursorPos(x, y) --term.clearLine() term.write( s ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index 3a772804a..58a513f36 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -130,14 +130,14 @@ if sCommand == "host" then local tCommands tCommands = { ["me"] = function( tUser, sContent ) - if string.len(sContent) > 0 then + if #sContent > 0 then send( "* " .. tUser.sUsername .. " " .. sContent ) else send( "* Usage: /me [words]", tUser.nUserID ) end end, ["nick"] = function( tUser, sContent ) - if string.len(sContent) > 0 then + if #sContent > 0 then local sOldName = tUser.sUsername tUser.sUsername = sContent send( "* " .. sOldName .. " is now known as " .. tUser.sUsername ) @@ -199,7 +199,7 @@ if sCommand == "host" then if sCommand then local fnCommand = tCommands[ sCommand ] if fnCommand then - local sContent = string.sub( sMessage, string.len(sCommand) + 3 ) + local sContent = string.sub( sMessage, #sCommand + 3 ) fnCommand( tUser, sContent ) else send( "* Unrecognised command: /" .. sCommand, tUser.nUserID ) @@ -300,7 +300,7 @@ elseif sCommand == "join" then local w = titleWindow.getSize() local sTitle = sUsername .. " on " .. sHostname titleWindow.setTextColour( highlightColour ) - titleWindow.setCursorPos( math.floor( w / 2 - string.len(sTitle) / 2 ), 1 ) + titleWindow.setCursorPos( math.floor( w / 2 - #sTitle / 2 ), 1 ) titleWindow.clearLine() titleWindow.write( sTitle ) promptWindow.restoreCursor() @@ -321,7 +321,7 @@ elseif sCommand == "join" then term.setTextColour( highlightColour ) write( sUsernameBit ) term.setTextColour( textColour ) - write( string.sub( sMessage, string.len( sUsernameBit ) + 1 ) ) + write( string.sub( sMessage, #sUsernameBit + 1 ) ) else write( sMessage ) end From 3a5d50e572263d96695c7dea61abea02e7a542f3 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 18 Dec 2019 15:29:24 +0000 Subject: [PATCH 110/711] Basic Minetweaker support (#327) This provides the following methods: - dan200.computercraft.turtle.removeUpgrade(id: String) - dan200.computercraft.turtle.removeUpgrade(stack: IItemStack) - dan200.computercraft.turtle.addTool(id: String, craftItem: IItemStack[, toolItem: IItemStack][, kind: string]) While it's pretty minimal, it should allow for a reasonable amount of functionality. Closes #327 and #97. --- build.gradle | 7 +- .../computercraft/shared/TurtleUpgrades.java | 109 ++++++++++++------ .../crafttweaker/TurtleTweaker.java | 70 +++++++++++ .../crafttweaker/actions/AddTurtleTool.java | 96 +++++++++++++++ .../crafttweaker/actions/IAction.java | 32 +++++ .../actions/RemoveTurtleUpgradeByItem.java | 50 ++++++++ .../actions/RemoveTurtleUpgradeByName.java | 49 ++++++++ .../shared/turtle/items/ItemTurtleBase.java | 12 +- .../shared/turtle/upgrades/TurtleAxe.java | 6 + .../shared/turtle/upgrades/TurtleHoe.java | 5 + .../shared/turtle/upgrades/TurtleShovel.java | 5 + .../shared/turtle/upgrades/TurtleSword.java | 6 + .../shared/turtle/upgrades/TurtleTool.java | 8 +- 13 files changed, 409 insertions(+), 46 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java create mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java create mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java create mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java create mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java diff --git a/build.gradle b/build.gradle index 4632fcf19..a10121df1 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,10 @@ repositories { name "Amadornes" url "https://maven.amadornes.com/" } + maven { + name "CraftTweaker" + url "https://maven.blamejared.com/" + } } configurations { @@ -70,9 +74,10 @@ configurations { dependencies { checkstyle "com.puppycrawl.tools:checkstyle:8.25" + deobfProvided "CraftTweaker2:CraftTweaker2-MC1120-Main:1.12-4.1.20.554" + deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" deobfProvided "mezz.jei:jei_1.12.2:4.15.0.269:api" deobfProvided "pl.asie:Charset-Lib:0.5.4.6" - deobfProvided "MCMultiPart2:MCMultiPart:2.5.3" runtime "mezz.jei:jei_1.12.2:4.15.0.269" diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 921be39d9..ad62ff310 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -19,12 +19,35 @@ import net.minecraftforge.fml.common.ModContainer; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import java.util.stream.Stream; public final class TurtleUpgrades { + public static class Wrapper + { + final ITurtleUpgrade upgrade; + final int legacyId; + final String id; + final String modId; + boolean enabled; + + public Wrapper( ITurtleUpgrade upgrade ) + { + ModContainer mc = Loader.instance().activeModContainer(); + + this.upgrade = upgrade; + this.legacyId = upgrade.getLegacyUpgradeID(); + this.id = upgrade.getUpgradeID().toString(); + this.modId = mc != null && mc.getModId() != null ? mc.getModId() : null; + this.enabled = true; + } + } + + private static ITurtleUpgrade[] vanilla; + private static final Map upgrades = new HashMap<>(); private static final Int2ObjectMap legacyUpgrades = new Int2ObjectOpenHashMap<>(); - private static final IdentityHashMap upgradeOwners = new IdentityHashMap<>(); + private static final IdentityHashMap wrappers = new IdentityHashMap<>(); private TurtleUpgrades() {} @@ -35,9 +58,7 @@ public final class TurtleUpgrades int id = upgrade.getLegacyUpgradeID(); if( id >= 0 && id < 64 ) { - String message = getMessage( upgrade, "Legacy UpgradeID '" + id + "' is reserved by ComputerCraft" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); + throw registrationError( upgrade, "Legacy Upgrade ID '" + id + "' is reserved by ComputerCraft" ); } registerInternal( upgrade ); @@ -47,58 +68,63 @@ public final class TurtleUpgrades { Objects.requireNonNull( upgrade, "upgrade cannot be null" ); + Wrapper wrapper = new Wrapper( upgrade ); + // Check conditions - int legacyId = upgrade.getLegacyUpgradeID(); + int legacyId = wrapper.legacyId; if( legacyId >= 0 ) { if( legacyId >= Short.MAX_VALUE ) { - String message = getMessage( upgrade, "UpgradeID '" + legacyId + "' is out of range" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); + throw registrationError( upgrade, "Upgrade ID '" + legacyId + "' is out of range" ); } ITurtleUpgrade existing = legacyUpgrades.get( legacyId ); if( existing != null ) { - String message = getMessage( upgrade, "UpgradeID '" + legacyId + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); + throw registrationError( upgrade, "Upgrade ID '" + legacyId + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); } } - String id = upgrade.getUpgradeID().toString(); + String id = wrapper.id; ITurtleUpgrade existing = upgrades.get( id ); if( existing != null ) { - String message = getMessage( upgrade, "UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); - ComputerCraft.log.error( message ); - throw new RuntimeException( message ); + throw registrationError( upgrade, "Upgrade '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); } // Register if( legacyId >= 0 ) legacyUpgrades.put( legacyId, upgrade ); upgrades.put( id, upgrade ); - - ModContainer mc = Loader.instance().activeModContainer(); - if( mc != null && mc.getModId() != null ) upgradeOwners.put( upgrade, mc.getModId() ); + wrappers.put( upgrade, wrapper ); } - private static String getMessage( ITurtleUpgrade upgrade, String rest ) + private static RuntimeException registrationError( ITurtleUpgrade upgrade, String rest ) { - return "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. " + rest; + String message = "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. " + rest; + ComputerCraft.log.error( message ); + throw new IllegalArgumentException( message ); } + @Nullable public static ITurtleUpgrade get( String id ) { return upgrades.get( id ); } + @Nullable public static ITurtleUpgrade get( int id ) { return legacyUpgrades.get( id ); } + @Nullable + public static String getOwner( @Nonnull ITurtleUpgrade upgrade ) + { + Wrapper wrapper = wrappers.get( upgrade ); + return wrapper != null ? wrapper.modId : null; + } + public static ITurtleUpgrade get( @Nonnull ItemStack stack ) { if( stack.isEmpty() ) return null; @@ -115,25 +141,24 @@ public final class TurtleUpgrades return null; } - public static Iterable getVanillaUpgrades() + public static Stream getVanillaUpgrades() { - List vanilla = new ArrayList<>(); - vanilla.add( ComputerCraft.TurtleUpgrades.diamondPickaxe ); - vanilla.add( ComputerCraft.TurtleUpgrades.diamondAxe ); - vanilla.add( ComputerCraft.TurtleUpgrades.diamondSword ); - vanilla.add( ComputerCraft.TurtleUpgrades.diamondShovel ); - vanilla.add( ComputerCraft.TurtleUpgrades.diamondHoe ); - vanilla.add( ComputerCraft.TurtleUpgrades.craftingTable ); - vanilla.add( ComputerCraft.TurtleUpgrades.wirelessModem ); - vanilla.add( ComputerCraft.TurtleUpgrades.advancedModem ); - vanilla.add( ComputerCraft.TurtleUpgrades.speaker ); - return vanilla; - } + if( vanilla == null ) + { + vanilla = new ITurtleUpgrade[] { + ComputerCraft.TurtleUpgrades.diamondPickaxe, + ComputerCraft.TurtleUpgrades.diamondAxe, + ComputerCraft.TurtleUpgrades.diamondSword, + ComputerCraft.TurtleUpgrades.diamondShovel, + ComputerCraft.TurtleUpgrades.diamondHoe, + ComputerCraft.TurtleUpgrades.craftingTable, + ComputerCraft.TurtleUpgrades.wirelessModem, + ComputerCraft.TurtleUpgrades.advancedModem, + ComputerCraft.TurtleUpgrades.speaker, + }; + } - @Nullable - public static String getOwner( @Nonnull ITurtleUpgrade upgrade ) - { - return upgradeOwners.get( upgrade ); + return Arrays.stream( vanilla ).filter( x -> x != null && wrappers.get( x ).enabled ); } public static Iterable getUpgrades() @@ -145,4 +170,14 @@ public final class TurtleUpgrades { return true; } + + public static void disable( ITurtleUpgrade upgrade ) + { + Wrapper wrapper = wrappers.get( upgrade ); + if( !wrapper.enabled ) return; + + wrapper.enabled = false; + upgrades.remove( wrapper.id ); + if( wrapper.legacyId >= 0 ) legacyUpgrades.remove( wrapper.legacyId ); + } } diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java new file mode 100644 index 000000000..8f1439233 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java @@ -0,0 +1,70 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.crafttweaker; + +import crafttweaker.CraftTweakerAPI; +import crafttweaker.annotations.ModOnly; +import crafttweaker.annotations.ZenDoc; +import crafttweaker.annotations.ZenRegister; +import crafttweaker.api.item.IItemStack; +import crafttweaker.api.minecraft.CraftTweakerMC; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.integration.crafttweaker.actions.AddTurtleTool; +import dan200.computercraft.shared.integration.crafttweaker.actions.RemoveTurtleUpgradeByItem; +import dan200.computercraft.shared.integration.crafttweaker.actions.RemoveTurtleUpgradeByName; +import stanhebben.zenscript.annotations.ZenClass; +import stanhebben.zenscript.annotations.ZenMethod; + +@ZenRegister +@ZenClass( "dan200.computercraft.turtle" ) +@ModOnly( ComputerCraft.MOD_ID ) +public class TurtleTweaker +{ + @ZenMethod + @ZenDoc( "Remove a turtle upgrade with the given id" ) + public static void removeUpgrade( String upgrade ) + { + CraftTweakerAPI.apply( new RemoveTurtleUpgradeByName( upgrade ) ); + } + + @ZenMethod + @ZenDoc( "Remove a turtle upgrade crafted with the given item stack" ) + public static void removeUpgrade( IItemStack stack ) + { + CraftTweakerAPI.apply( new RemoveTurtleUpgradeByItem( CraftTweakerMC.getItemStack( stack ) ) ); + } + + @ZenMethod + @ZenDoc( "Add a new turtle tool with the given id, which crafts and acts using the given stack." ) + public static void addTool( String id, IItemStack stack ) + { + addTool( id, stack, stack, "tool" ); + } + + @ZenMethod + @ZenDoc( "Add a new turtle tool with the given id, which is crafted with one item, and uses another." ) + public static void addTool( String id, IItemStack craftingStack, IItemStack toolStack ) + { + addTool( id, craftingStack, toolStack, "tool" ); + } + + @ZenMethod + @ZenDoc( "Add a new turtle tool with the given id, which crafts and acts using the given stack. You may also" + + "specify a 'kind' of tool, which limits what blocks the turtle can break (for instance, an 'axe' may only break wood)." ) + public static void addTool( String id, IItemStack stack, String kind ) + { + addTool( id, stack, stack, kind ); + } + + @ZenMethod + @ZenDoc( "Add a new turtle tool with the given id, which is crafted with one item, and uses another. You may also" + + "specify a 'kind' of tool, which limits what blocks the turtle can break (for instance, an 'axe' may only break wood)." ) + public static void addTool( String id, IItemStack craftingStack, IItemStack toolStack, String kind ) + { + CraftTweakerAPI.apply( new AddTurtleTool( id, CraftTweakerMC.getItemStack( craftingStack ), CraftTweakerMC.getItemStack( toolStack ), kind ) ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java new file mode 100644 index 000000000..3b34cf5d7 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java @@ -0,0 +1,96 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.crafttweaker.actions; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.TurtleUpgrades; +import dan200.computercraft.shared.turtle.upgrades.*; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Register a new turtle tool. + */ +public class AddTurtleTool implements IAction +{ + private interface Factory + { + TurtleTool create( ResourceLocation location, ItemStack craftItem, ItemStack toolItem ); + } + + private static final Map kinds = new HashMap<>(); + + static + { + kinds.put( "tool", TurtleTool::new ); + kinds.put( "axe", TurtleAxe::new ); + kinds.put( "hoe", TurtleHoe::new ); + kinds.put( "shovel", TurtleShovel::new ); + kinds.put( "sword", TurtleSword::new ); + } + + private final String id; + private final ItemStack craftItem; + private final ItemStack toolItem; + private final String kind; + + public AddTurtleTool( String id, ItemStack craftItem, ItemStack toolItem, String kind ) + { + this.id = id; + this.craftItem = craftItem; + this.toolItem = toolItem; + this.kind = kind; + } + + @Override + public void apply() + { + Factory factory = kinds.get( kind ); + if( factory == null ) + { + ComputerCraft.log.error( "Unknown turtle upgrade kind '{}' (this should have been rejected by verify!)", kind ); + return; + } + + try + { + TurtleUpgrades.register( factory.create( new ResourceLocation( id ), craftItem, toolItem ) ); + } + catch( RuntimeException e ) + { + ComputerCraft.log.error( "Registration of turtle tool failed", e ); + } + } + + @Override + public String describe() + { + return String.format( "Add new turtle %s '%s' (crafted with '%s', uses a '%s')", kind, id, craftItem, toolItem ); + } + + public Optional getValidationProblem() + { + if( craftItem.isEmpty() ) return Optional.of( "Crafting item stack is empty." ); + if( craftItem.hasTagCompound() && !craftItem.getTagCompound().isEmpty() ) + { + return Optional.of( "Crafting item has NBT." ); + } + if( toolItem.isEmpty() ) return Optional.of( "Tool item stack is empty." ); + if( !kinds.containsKey( kind ) ) return Optional.of( String.format( "Unknown kind '%s'.", kind ) ); + + if( TurtleUpgrades.get( id ) != null ) + { + return Optional.of( String.format( "An upgrade with the same name ('%s') has already been registered.", id ) ); + } + + return Optional.empty(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java new file mode 100644 index 000000000..d726c7090 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java @@ -0,0 +1,32 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.crafttweaker.actions; + +import java.util.Optional; + +/** + * An extension of {@link IAction} with a single validation function, rather than two. + */ +public interface IAction extends crafttweaker.IAction +{ + default Optional getValidationProblem() + { + return Optional.empty(); + } + + @Override + default boolean validate() + { + return !getValidationProblem().isPresent(); + } + + @Override + default String describeInvalid() + { + return getValidationProblem().orElse( "No problems found." ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java new file mode 100644 index 000000000..939e72592 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java @@ -0,0 +1,50 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.crafttweaker.actions; + +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.shared.TurtleUpgrades; +import net.minecraft.item.ItemStack; + +import java.util.Optional; + +/** + * Removes a turtle upgrade crafted with the given stack. + */ +public class RemoveTurtleUpgradeByItem implements IAction +{ + private final ItemStack stack; + + public RemoveTurtleUpgradeByItem( ItemStack stack ) + { + this.stack = stack; + } + + @Override + public void apply() + { + ITurtleUpgrade upgrade = TurtleUpgrades.get( stack ); + if( upgrade != null ) TurtleUpgrades.disable( upgrade ); + } + + @Override + public String describe() + { + return String.format( "Remove turtle upgrades crafted with '%s'", stack ); + } + + @Override + public Optional getValidationProblem() + { + if( TurtleUpgrades.get( stack ) == null ) + { + return Optional.of( String.format( "Unknown turtle upgrade crafted with '%s'.", stack ) ); + } + + return Optional.empty(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java new file mode 100644 index 000000000..ce41a17d9 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java @@ -0,0 +1,49 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.crafttweaker.actions; + +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.shared.TurtleUpgrades; + +import java.util.Optional; + +/** + * Removes a turtle upgrade with the given id. + */ +public class RemoveTurtleUpgradeByName implements IAction +{ + private final String id; + + public RemoveTurtleUpgradeByName( String id ) + { + this.id = id; + } + + @Override + public void apply() + { + ITurtleUpgrade upgrade = TurtleUpgrades.get( id ); + if( upgrade != null ) TurtleUpgrades.disable( upgrade ); + } + + @Override + public String describe() + { + return String.format( "Remove turtle upgrade '%s'", id ); + } + + @Override + public Optional getValidationProblem() + { + if( TurtleUpgrades.get( id ) == null ) + { + return Optional.of( String.format( "Unknown turtle upgrade '%s'.", id ) ); + } + + return Optional.empty(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java index 6234d0b62..3fdf3a01a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java @@ -48,13 +48,11 @@ public abstract class ItemTurtleBase extends ItemComputerBase implements ITurtle ItemStack normalStack = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ); if( !normalStack.isEmpty() && normalStack.getItem() == this ) list.add( normalStack ); - for( ITurtleUpgrade upgrade : TurtleUpgrades.getVanillaUpgrades() ) - { - if( !TurtleUpgrades.suitableForFamily( family, upgrade ) ) continue; - - ItemStack stack = TurtleItemFactory.create( -1, null, -1, family, null, upgrade, 0, null ); - if( !stack.isEmpty() && stack.getItem() == this ) list.add( stack ); - } + TurtleUpgrades.getVanillaUpgrades() + .filter( x -> TurtleUpgrades.suitableForFamily( family, x ) ) + .map( x -> TurtleItemFactory.create( -1, null, -1, family, null, x, 0, null ) ) + .filter( x -> !x.isEmpty() && x.getItem() == this ) + .forEach( list::add ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java index c623a2066..02342eb8a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.turtle.upgrades; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; public class TurtleAxe extends TurtleTool @@ -21,6 +22,11 @@ public class TurtleAxe extends TurtleTool super( id, legacyId, item ); } + public TurtleAxe( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) + { + super( id, craftItem, toolItem ); + } + @Override protected float getDamageMultiplier() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index 4e6a2de00..e29a17d46 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -35,6 +35,11 @@ public class TurtleHoe extends TurtleTool super( id, legacyId, item ); } + public TurtleHoe( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) + { + super( id, craftItem, toolItem ); + } + @Override protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index 4e1c44689..face19e6d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -35,6 +35,11 @@ public class TurtleShovel extends TurtleTool super( id, legacyId, item ); } + public TurtleShovel( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) + { + super( id, craftItem, toolItem ); + } + @Override protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 8f5f13619..853def832 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -10,6 +10,7 @@ import dan200.computercraft.shared.turtle.core.TurtlePlayer; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -26,6 +27,11 @@ public class TurtleSword extends TurtleTool super( id, legacyId, item ); } + public TurtleSword( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) + { + super( id, craftItem, toolItem ); + } + @Override protected boolean canBreakBlock( IBlockState state, World world, BlockPos pos, TurtlePlayer player ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index d7c40e27a..cf6b09ac7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -62,6 +62,12 @@ public class TurtleTool extends AbstractTurtleUpgrade this.item = new ItemStack( item, 1, 0 ); } + public TurtleTool( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) + { + super( id, -1, TurtleUpgradeType.Tool, craftItem ); + this.item = toolItem; + } + @Nonnull @Override @SideOnly( Side.CLIENT ) @@ -76,7 +82,7 @@ public class TurtleTool extends AbstractTurtleUpgrade ); Minecraft mc = Minecraft.getMinecraft(); return Pair.of( - mc.getRenderItem().getItemModelMesher().getItemModel( item ), + mc.getRenderItem().getItemModelMesher().getItemModel( getCraftingItem() ), transform ); } From d254c6464bbc2cdf786cea2892ff17d24c86df6c Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 23 Dec 2019 15:43:48 +0100 Subject: [PATCH 111/711] Add more MOTD messages again (#241) --- .../assets/computercraft/lua/rom/motd.txt | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/motd.txt b/src/main/resources/assets/computercraft/lua/rom/motd.txt index d81dc2fd0..d82c3a995 100644 --- a/src/main/resources/assets/computercraft/lua/rom/motd.txt +++ b/src/main/resources/assets/computercraft/lua/rom/motd.txt @@ -1,7 +1,7 @@ View the source code at https://github.com/SquidDev-CC/CC-Tweaked View the documentation at https://wiki.computercraft.cc Visit the forum at https://forums.computercraft.cc -You can disable these messages by running "set motd.enable false" +You can disable these messages by running "set motd.enable false". You can create directories with "mkdir". Want to see hidden files? Run "set list.show_hidden true". Run "list" or "ls" to see all files in a directory. @@ -13,3 +13,22 @@ Use the "edit" program to create and edit your programs. You can copy files with "copy" or "cp". You can use "wget run " to run a program from the internet. You can use "wget" to download a file from the internet. +On an advanced computer you can use "fg" or "bg" to run multiple programs at the same time. +Use "type" to see if a path is a file or a directory. +Get a list of all programs with "programs". +Use an advanced computer to use colours and the mouse. +With a speaker you can play sounds. +Use "motd" to print the Message of the Day. +You can disable the startup from a computer with "set shell.allow_startup false". +You can disable the startup from a disk with "set shell.allow_disk_startup false". +Programs that are placed in the "startup" folder in the root of a computer are started on boot. +Use a modem to connect with other computers. +With the "gps" program you can get the position of a computer. +Use "monitor" to run a program on a attached monitor. +View all attached peripherals with "peripherals". +Use "time" to see the in-game time. +You can set the label of a computer with "label set". +A computer needs a label to keep its files if it got destroyed. +You can disable auto completion in the shell with "set shell.autocomplete false". +You can disable auto completion in edit with "set edit.autocomplete false". +Feeling creative? Use a printer to print a book! From 4d18234714b7bb61e20aef48c37f2ee2351b7b23 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 23 Dec 2019 17:17:32 +0000 Subject: [PATCH 112/711] Use a fake network handler too It appears that WB opens containers manually, and thus all of our stubs network stubs are entirely ignored. Thus the only solution here is to stub out the whole network handler code. Thankfully this is simple enough - we do the same for Plethora and 1.14. Fixes #328 --- .../shared/turtle/core/TurtlePlayer.java | 3 + .../shared/util/FakeNetHandler.java | 234 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 6bd90717e..50284741e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared.turtle.core; import com.mojang.authlib.GameProfile; import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.shared.util.FakeNetHandler; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.entity.Entity; @@ -46,11 +47,13 @@ public class TurtlePlayer extends FakePlayer public TurtlePlayer( World world ) { super( (WorldServer) world, DEFAULT_PROFILE ); + connection = new FakeNetHandler( this ); } private TurtlePlayer( ITurtleAccess turtle ) { super( (WorldServer) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); + connection = new FakeNetHandler( this ); setState( turtle ); } diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java new file mode 100644 index 000000000..a99e53e09 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -0,0 +1,234 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.network.*; +import net.minecraft.network.play.client.*; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.common.util.FakePlayer; + +import javax.annotation.Nonnull; +import javax.crypto.SecretKey; + +public class FakeNetHandler extends NetHandlerPlayServer +{ + public static class FakeNetworkManager extends NetworkManager + { + private INetHandler handler; + + public FakeNetworkManager() + { + super( EnumPacketDirection.CLIENTBOUND ); + } + + @Override + public void channelActive( ChannelHandlerContext context ) + { + } + + @Override + public void setConnectionState( @Nonnull EnumConnectionState state ) + { + } + + @Override + public void channelInactive( ChannelHandlerContext context ) + { + } + + @Override + public void exceptionCaught( ChannelHandlerContext context, @Nonnull Throwable e ) + { + } + + @Override + public void setNetHandler( INetHandler handler ) + { + this.handler = handler; + } + + @Override + public void processReceivedPackets() + { + } + + @Override + public void closeChannel( @Nonnull ITextComponent channel ) + { + } + + @Override + public boolean isLocalChannel() + { + return false; + } + + + @Override + public void enableEncryption( SecretKey key ) + { + } + + @Override + public boolean isChannelOpen() + { + return false; + } + + @Nonnull + @Override + public INetHandler getNetHandler() + { + return handler; + } + + @Nonnull + @Override + public ITextComponent getExitMessage() + { + return null; + } + + @Override + public void disableAutoRead() + { + } + + @Nonnull + @Override + public Channel channel() + { + return null; + } + } + + + public FakeNetHandler( FakePlayer player ) + { + this( player.server, player ); + } + + public FakeNetHandler( MinecraftServer server, FakePlayer player ) + { + super( server, new FakeNetworkManager(), player ); + } + + @Override + public void processInput( CPacketInput packet ) + { + } + + @Override + public void processPlayer( CPacketPlayer packet ) + { + } + + @Override + public void setPlayerLocation( double x, double y, double z, float yaw, float pitch ) + { + } + + @Override + public void processPlayerDigging( CPacketPlayerDigging packet ) + { + } + + @Override + public void onDisconnect( @Nonnull ITextComponent chat ) + { + } + + @Override + @SuppressWarnings( "rawtypes" ) + public void sendPacket( @Nonnull final Packet packet ) + { + + } + + @Override + public void processHeldItemChange( CPacketHeldItemChange packet ) + { + } + + @Override + public void processChatMessage( @Nonnull CPacketChatMessage packet ) + { + } + + @Override + public void processEntityAction( CPacketEntityAction packet ) + { + } + + @Override + public void processUseEntity( CPacketUseEntity packet ) + { + } + + @Override + public void processClientStatus( CPacketClientStatus packet ) + { + } + + @Override + public void processCloseWindow( @Nonnull CPacketCloseWindow packet ) + { + } + + @Override + public void processClickWindow( CPacketClickWindow packet ) + { + } + + @Override + public void processEnchantItem( CPacketEnchantItem packet ) + { + } + + @Override + public void processCreativeInventoryAction( @Nonnull CPacketCreativeInventoryAction packet ) + { + } + + @Override + public void processConfirmTransaction( @Nonnull CPacketConfirmTransaction packet ) + { + } + + @Override + public void processUpdateSign( CPacketUpdateSign packet ) + { + } + + @Override + public void processKeepAlive( @Nonnull CPacketKeepAlive packet ) + { + } + + @Override + public void processPlayerAbilities( CPacketPlayerAbilities packet ) + { + } + + @Override + public void processTabComplete( CPacketTabComplete packet ) + { + } + + @Override + public void processClientSettings( @Nonnull CPacketClientSettings packet ) + { + } + + @Override + public void processCustomPayload( CPacketCustomPayload packetIn ) + { + } +} From da41c651281da30ede3a4efa76ad41fd74eb4c23 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 23 Dec 2019 18:54:19 +0000 Subject: [PATCH 113/711] Update proguard configuration - Remove redundant preservation of cobalt lib constructors. We use lambdas now, so this is no longer needed. - Fix Java crypto lib not being included. --- build.gradle | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index a10121df1..3ada5933e 100644 --- a/build.gradle +++ b/build.gradle @@ -137,6 +137,7 @@ task proguard(type: ProGuardTask, dependsOn: jar) { // Add the main runtime jar and all non-shadowed dependencies libraryjars "${System.getProperty('java.home')}/lib/rt.jar" + libraryjars "${System.getProperty('java.home')}/lib/jce.jar" doFirst { sourceSets.main.compileClasspath .filter { !it.name.contains("Cobalt") } @@ -151,9 +152,6 @@ task proguard(type: ProGuardTask, dependsOn: jar) { // Preserve ComputerCraft classes - we only want to strip shadowed files. keep 'class dan200.computercraft.** { *; }' - - // Preserve the constructors in Cobalt library class, as we init them via reflection - keepclassmembers 'class org.squiddev.cobalt.lib.** { (...); }' } task proguardMove(dependsOn: proguard) { From ae928c4397b055cbdb0dc78a0877b01336b3b9a2 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 23 Dec 2019 18:59:36 +0000 Subject: [PATCH 114/711] Make http domain configuration a little clearer --- .../dan200/computercraft/shared/Config.java | 24 ++++++++++--------- .../assets/computercraft/lang/de_de.lang | 4 ++-- .../assets/computercraft/lang/en_us.lang | 4 ++-- .../assets/computercraft/lang/es_es.lang | 4 ++-- .../assets/computercraft/lang/fr_fr.lang | 4 ++-- .../assets/computercraft/lang/it_it.lang | 4 ++-- .../assets/computercraft/lang/pt_br.lang | 4 ++-- .../assets/computercraft/lang/sv_se.lang | 4 ++-- .../assets/computercraft/lang/zh_cn.lang | 4 ++-- 9 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index ffb176c72..cd5840100 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -54,8 +54,8 @@ public final class Config private static Property httpEnable; private static Property httpWebsocketEnable; - private static Property httpWhitelist; - private static Property httpBlacklist; + private static Property httpAllowedDomains; + private static Property httpBlockedDomains; private static Property httpTimeout; private static Property httpMaxRequests; @@ -163,8 +163,10 @@ public final class Config { // HTTP renameProperty( CATEGORY_GENERAL, "http_enable", CATEGORY_HTTP, "enabled" ); renameProperty( CATEGORY_GENERAL, "http_websocket_enable", CATEGORY_HTTP, "websocket_enabled" ); - renameProperty( CATEGORY_GENERAL, "http_whitelist", CATEGORY_HTTP, "whitelist" ); - renameProperty( CATEGORY_GENERAL, "http_blacklist", CATEGORY_HTTP, "blacklist" ); + renameProperty( CATEGORY_GENERAL, "http_whitelist", CATEGORY_HTTP, "allowed_domains" ); + renameProperty( CATEGORY_GENERAL, "http_blacklist", CATEGORY_HTTP, "blocked_domains" ); + renameProperty( CATEGORY_HTTP, "whitelist", CATEGORY_HTTP, "allowed_domains" ); + renameProperty( CATEGORY_HTTP, "blacklist", CATEGORY_HTTP, "blocked_domains" ); config.getCategory( CATEGORY_HTTP ) .setComment( "Controls the HTTP API" ); @@ -176,15 +178,15 @@ public final class Config httpWebsocketEnable = config.get( CATEGORY_HTTP, "websocket_enabled", ComputerCraft.http_websocket_enable ); httpWebsocketEnable.setComment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ); - httpWhitelist = config.get( CATEGORY_HTTP, "whitelist", DEFAULT_HTTP_WHITELIST ); - httpWhitelist.setComment( "A list of wildcards for domains or IP ranges that can be accessed through the " + + httpAllowedDomains = config.get( CATEGORY_HTTP, "allowed_domains", DEFAULT_HTTP_WHITELIST ); + httpAllowedDomains.setComment( "A list of wildcards for domains or IP ranges that can be accessed through the " + "\"http\" API on Computers.\n" + "Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to " + "just subdomains of pastebin.com.\n" + "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); - httpBlacklist = config.get( CATEGORY_HTTP, "blacklist", DEFAULT_HTTP_BLACKLIST ); - httpBlacklist.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the " + + httpBlockedDomains = config.get( CATEGORY_HTTP, "blocked_domains", DEFAULT_HTTP_BLACKLIST ); + httpBlockedDomains.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the " + "\"http\" API on Computers.\n" + "If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block " + "access to all subdomains of github.com.\n" + @@ -220,7 +222,7 @@ public final class Config setOrder( CATEGORY_HTTP, - httpEnable, httpWebsocketEnable, httpWhitelist, httpBlacklist, + httpEnable, httpWebsocketEnable, httpAllowedDomains, httpBlockedDomains, httpTimeout, httpMaxRequests, httpMaxDownload, httpMaxUpload, httpMaxWebsockets, httpMaxWebsocketMessage ); } @@ -441,8 +443,8 @@ public final class Config // HTTP ComputerCraft.http_enable = httpEnable.getBoolean(); ComputerCraft.http_websocket_enable = httpWebsocketEnable.getBoolean(); - ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.getStringList() ); - ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.getStringList() ); + ComputerCraft.http_whitelist = new AddressPredicate( httpAllowedDomains.getStringList() ); + ComputerCraft.http_blacklist = new AddressPredicate( httpBlockedDomains.getStringList() ); ComputerCraft.httpTimeout = Math.max( 0, httpTimeout.getInt() ); ComputerCraft.httpMaxRequests = Math.max( 1, httpMaxRequests.getInt() ); diff --git a/src/main/resources/assets/computercraft/lang/de_de.lang b/src/main/resources/assets/computercraft/lang/de_de.lang index 7460a071c..6fabe4002 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.lang +++ b/src/main/resources/assets/computercraft/lang/de_de.lang @@ -168,8 +168,8 @@ gui.computercraft:config.execution.max_main_computer_time=Computer Servertick Ze gui.computercraft:config.http=HTTP gui.computercraft:config.http.enabled=HTTP-API aktivieren gui.computercraft:config.http.websocket_enabled=Websockets aktivieren -gui.computercraft:config.http.whitelist=HTTP-Whitelist -gui.computercraft:config.http.blacklist=HTTP-Blacklist +gui.computercraft:config.http.allowed_domains=HTTP-Whitelist +gui.computercraft:config.http.blocked_domains=HTTP-Blacklist gui.computercraft:config.http.timeout=Zeitüberschreitung gui.computercraft:config.http.max_requests=Maximale Anzahl gleichzeitiger Anfragen diff --git a/src/main/resources/assets/computercraft/lang/en_us.lang b/src/main/resources/assets/computercraft/lang/en_us.lang index d00875c37..99cadd868 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.lang +++ b/src/main/resources/assets/computercraft/lang/en_us.lang @@ -168,8 +168,8 @@ gui.computercraft:config.execution.max_main_computer_time=Server tick computer t gui.computercraft:config.http=HTTP gui.computercraft:config.http.enabled=Enable the HTTP API gui.computercraft:config.http.websocket_enabled=Enable websockets -gui.computercraft:config.http.whitelist=HTTP whitelist -gui.computercraft:config.http.blacklist=HTTP blacklist +gui.computercraft:config.http.allowed_domains=Allowed domains +gui.computercraft:config.http.blocked_domains=Blocked domains gui.computercraft:config.http.timeout=Timeout gui.computercraft:config.http.max_requests=Maximum concurrent requests diff --git a/src/main/resources/assets/computercraft/lang/es_es.lang b/src/main/resources/assets/computercraft/lang/es_es.lang index fa2129634..b8c352bb1 100644 --- a/src/main/resources/assets/computercraft/lang/es_es.lang +++ b/src/main/resources/assets/computercraft/lang/es_es.lang @@ -57,8 +57,8 @@ gui.computercraft:config.default_computer_settings=Configuración de Ordenador p gui.computercraft:config.log_computer_errors=Grabar errores periféricos gui.computercraft:config.http.enabled=Habilitar API de HTTP -gui.computercraft:config.http.whitelist=Lista blanca de HTTP -gui.computercraft:config.http.blacklist=Lista negra de HTTP +gui.computercraft:config.http.allowed_domains=Lista blanca de HTTP +gui.computercraft:config.http.blocked_domains=Lista negra de HTTP gui.computercraft:config.peripheral.command_block_enabled=Habilitar bloque de comandos periférico gui.computercraft:config.peripheral.modem_range=Rango del módem (Por defecto) diff --git a/src/main/resources/assets/computercraft/lang/fr_fr.lang b/src/main/resources/assets/computercraft/lang/fr_fr.lang index e1f151235..b21567e47 100644 --- a/src/main/resources/assets/computercraft/lang/fr_fr.lang +++ b/src/main/resources/assets/computercraft/lang/fr_fr.lang @@ -57,8 +57,8 @@ gui.computercraft:config.default_computer_settings=Configuration d'Ordinateur pa gui.computercraft:config.log_computer_errors=Journal d'erreur périphériques gui.computercraft:config.http.enabled=Permettre l'API HTTP -gui.computercraft:config.http.whitelist=HTTP liste blanche -gui.computercraft:config.http.blacklist=HTTP liste noire +gui.computercraft:config.http.allowed_domains=HTTP liste blanche +gui.computercraft:config.http.blocked_domains=HTTP liste noire gui.computercraft:config.peripheral.command_block_enabled=Permettre l'accès d'un Bloc de Commande par périphérique gui.computercraft:config.peripheral.modem_range=Portée d'un Modem (par défaut) diff --git a/src/main/resources/assets/computercraft/lang/it_it.lang b/src/main/resources/assets/computercraft/lang/it_it.lang index 6be7df879..931118f9c 100644 --- a/src/main/resources/assets/computercraft/lang/it_it.lang +++ b/src/main/resources/assets/computercraft/lang/it_it.lang @@ -63,8 +63,8 @@ gui.computercraft:config.execution.computer_threads=Threads computer gui.computercraft:config.http=HTTP gui.computercraft:config.http.enabled=Attiva l'API HTTP gui.computercraft:config.http.websocket_enabled=Attiva websocket -gui.computercraft:config.http.whitelist=Lista bianca HTTP -gui.computercraft:config.http.blacklist=Lista nera HTTP +gui.computercraft:config.http.allowed_domains=Lista bianca HTTP +gui.computercraft:config.http.blocked_domains=Lista nera HTTP gui.computercraft:config.http.timeout=Tempo di scadenza gui.computercraft:config.http.max_requests=Richieste correnti massime diff --git a/src/main/resources/assets/computercraft/lang/pt_br.lang b/src/main/resources/assets/computercraft/lang/pt_br.lang index d9706ffa5..2cf77ebf5 100644 --- a/src/main/resources/assets/computercraft/lang/pt_br.lang +++ b/src/main/resources/assets/computercraft/lang/pt_br.lang @@ -63,8 +63,8 @@ gui.computercraft:config.execution.computer_threads=Threads por computador gui.computercraft:config.http=HTTP gui.computercraft:config.http.enabled=Habilitar a biblioteca de HTTP gui.computercraft:config.http.websocket_enabled=Habilitar websockets -gui.computercraft:config.http.whitelist=Lista de endereços autorizados -gui.computercraft:config.http.blacklist=Lista de endereços proíbidos +gui.computercraft:config.http.allowed_domains=Lista de endereços autorizados +gui.computercraft:config.http.blocked_domains=Lista de endereços proíbidos gui.computercraft:config.http.timeout=Tempo limite para conexões gui.computercraft:config.http.max_requests=Limite de conexões paralelas diff --git a/src/main/resources/assets/computercraft/lang/sv_se.lang b/src/main/resources/assets/computercraft/lang/sv_se.lang index ad4dc0ceb..b90379225 100644 --- a/src/main/resources/assets/computercraft/lang/sv_se.lang +++ b/src/main/resources/assets/computercraft/lang/sv_se.lang @@ -63,8 +63,8 @@ gui.computercraft:config.execution.computer_threads=Dator trÃ¥dar gui.computercraft:config.http=HTTP gui.computercraft:config.http.enabled=Aktivera HTTP API gui.computercraft:config.http.websocket_enabled=Aktivera websockets -gui.computercraft:config.http.whitelist=HTTP vitlista -gui.computercraft:config.http.blacklist=HTTP svartlista +gui.computercraft:config.http.allowed_domains=HTTP vitlista +gui.computercraft:config.http.blocked_domains=HTTP svartlista gui.computercraft:config.http.timeout=Timeout gui.computercraft:config.http.max_requests=Maximalt antal samgÃ¥ende förfrÃ¥gningar diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.lang b/src/main/resources/assets/computercraft/lang/zh_cn.lang index 56b9aa106..86c43c33f 100644 --- a/src/main/resources/assets/computercraft/lang/zh_cn.lang +++ b/src/main/resources/assets/computercraft/lang/zh_cn.lang @@ -168,8 +168,8 @@ gui.computercraft:config.execution.max_main_computer_time=æœåŠ¡å™¨è®¡ç®—æœºtick gui.computercraft:config.http=HTTP gui.computercraft:config.http.enabled=å¯ç”¨HTTP API gui.computercraft:config.http.websocket_enabled=å¯ç”¨websockets -gui.computercraft:config.http.whitelist=HTTP白åå• -gui.computercraft:config.http.blacklist=HTTP黑åå• +gui.computercraft:config.http.allowed_domains=HTTP白åå• +gui.computercraft:config.http.blocked_domains=HTTP黑åå• gui.computercraft:config.http.timeout=Timeout gui.computercraft:config.http.max_requests=最大并å‘请求数 From e59c043fb68da1c0e993f55b5e57901a5be3b4ce Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 23 Dec 2019 21:34:03 +0000 Subject: [PATCH 115/711] Fix a couple of comments to use the new config names --- src/main/java/dan200/computercraft/shared/Config.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index cd5840100..8c80af4ba 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -172,8 +172,8 @@ public final class Config .setComment( "Controls the HTTP API" ); httpEnable = config.get( CATEGORY_HTTP, "enabled", ComputerCraft.http_enable ); - httpEnable.setComment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for " + - "more fine grained control than this)" ); + httpEnable.setComment( "Enable the \"http\" API on Computers (see \"allowed_domains\" and \"blocked_domains\" " + + "for more fine grained control than this)" ); httpWebsocketEnable = config.get( CATEGORY_HTTP, "websocket_enabled", ComputerCraft.http_websocket_enable ); httpWebsocketEnable.setComment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ); @@ -188,7 +188,7 @@ public final class Config httpBlockedDomains = config.get( CATEGORY_HTTP, "blocked_domains", DEFAULT_HTTP_BLACKLIST ); httpBlockedDomains.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the " + "\"http\" API on Computers.\n" + - "If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block " + + "If this is empty then all explicitly allowed domains will be accessible. Example: \"*.github.com\" will block " + "access to all subdomains of github.com.\n" + "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); From 0dde859582ede3ac4a77148f4604709fb2ded1c6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 23 Dec 2019 22:10:32 +0000 Subject: [PATCH 116/711] Bump version --- gradle.properties | 2 +- .../assets/computercraft/lua/rom/help/changelog.txt | 9 +++++++++ .../assets/computercraft/lua/rom/help/whatsnew.txt | 9 +++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index d3002e82e..c23effa6f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.85.2 +mod_version=1.86.0 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 99140820e..dec1fec52 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,12 @@ +# New features in CC: Tweaked 1.86.0 + +* Add PATCH and TRACE HTTP methods. (jaredallard) +* Add more MOTD messages. (JakobDev) +* Allow removing and adding turtle upgrades via CraftTweaker. + +And several bug fixes: +* Fix crash when interacting with Wearable Backpacks. + # New features in CC: Tweaked 1.85.2 * Fix crashes when using the mouse with advanced computers. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index b1a6d0cff..3d8051511 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,5 +1,10 @@ -New features in CC: Tweaked 1.85.2 +New features in CC: Tweaked 1.86.0 -* Fix crashes when using the mouse with advanced computers. +* Add PATCH and TRACE HTTP methods. (jaredallard) +* Add more MOTD messages. (JakobDev) +* Allow removing and adding turtle upgrades via CraftTweaker. + +And several bug fixes: +* Fix crash when interacting with Wearable Backpacks. Type "help changelog" to see the full version history. From 4320a4f851dff915bb3a4356b6b0caafc82f133e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 24 Dec 2019 19:16:06 +0000 Subject: [PATCH 117/711] Update CT integration Sadly we have to disable -Werror, as the annotation class files are not available on maven, so this produces a warning. --- build.gradle | 2 +- .../computercraft/shared/TurtleUpgrades.java | 73 ++++++++++++++----- .../crafttweaker/TrackingLogger.java | 40 ++++++++++ .../crafttweaker/TurtleTweaker.java | 56 +++++++------- .../crafttweaker/actions/AddTurtleTool.java | 65 ++++++++++++----- .../crafttweaker/actions/IAction.java | 32 -------- .../actions/RemoveTurtleUpgradeByItem.java | 35 +++++++-- .../actions/RemoveTurtleUpgradeByName.java | 35 +++++++-- .../integration/jei/JEIComputerCraft.java | 10 +-- .../integration/jei/RecipeResolver.java | 7 +- .../shared/turtle/items/ItemTurtle.java | 10 +-- .../shared/turtle/upgrades/TurtleTool.java | 2 +- 12 files changed, 240 insertions(+), 127 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java delete mode 100644 src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java diff --git a/build.gradle b/build.gradle index d9129bd8d..10b5f77f8 100644 --- a/build.gradle +++ b/build.gradle @@ -139,7 +139,7 @@ jar { [compileJava, compileTestJava].forEach { it.configure { - options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror" + options.compilerArgs << "-Xlint" << "-Xlint:-processing" } } diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 221c7980a..01f507e63 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -11,7 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.item.ItemStack; -import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; import javax.annotation.Nonnull; @@ -21,21 +20,18 @@ import java.util.stream.Stream; public final class TurtleUpgrades { - public static class Wrapper + private static class Wrapper { final ITurtleUpgrade upgrade; - final int legacyId; final String id; final String modId; boolean enabled; public Wrapper( ITurtleUpgrade upgrade ) { - ModContainer mc = ModLoadingContext.get().getActiveContainer(); - this.upgrade = upgrade; this.id = upgrade.getUpgradeID().toString(); - this.modId = mc != null && mc.getModId() != null ? mc.getModId() : null; + this.modId = ModLoadingContext.get().getActiveNamespace(); this.enabled = true; } } @@ -44,19 +40,21 @@ public final class TurtleUpgrades private static final Map upgrades = new HashMap<>(); private static final IdentityHashMap wrappers = new IdentityHashMap<>(); + private static boolean needsRebuild; private TurtleUpgrades() {} public static void register( @Nonnull ITurtleUpgrade upgrade ) { Objects.requireNonNull( upgrade, "upgrade cannot be null" ); + rebuild(); Wrapper wrapper = new Wrapper( upgrade ); String id = wrapper.id; ITurtleUpgrade existing = upgrades.get( id ); if( existing != null ) { - throw new IllegalStateException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turle'. UpgradeID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); + throw new IllegalStateException( "Error registering '" + upgrade.getUnlocalisedAdjective() + " Turtle'. Upgrade ID '" + id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); } upgrades.put( id, upgrade ); @@ -66,15 +64,10 @@ public final class TurtleUpgrades @Nullable public static ITurtleUpgrade get( String id ) { + rebuild(); return upgrades.get( id ); } - @Nullable - public static ITurtleUpgrade get( int id ) - { - return legacyUpgrades.get( id ); - } - @Nullable public static String getOwner( @Nonnull ITurtleUpgrade upgrade ) { @@ -86,12 +79,14 @@ public final class TurtleUpgrades { if( stack.isEmpty() ) return null; - for( ITurtleUpgrade upgrade : upgrades.values() ) + for( Wrapper wrapper : wrappers.values() ) { - ItemStack craftingStack = upgrade.getCraftingItem(); + if( !wrapper.enabled ) continue; + + ItemStack craftingStack = wrapper.upgrade.getCraftingItem(); if( !craftingStack.isEmpty() && InventoryUtil.areItemsSimilar( stack, craftingStack ) ) { - return upgrade; + return wrapper.upgrade; } } @@ -121,9 +116,9 @@ public final class TurtleUpgrades return Arrays.stream( vanilla ).filter( x -> x != null && wrappers.get( x ).enabled ); } - public static Iterable getUpgrades() + public static Stream getUpgrades() { - return Collections.unmodifiableCollection( upgrades.values() ); + return wrappers.values().stream().filter( x -> x.enabled ).map( x -> x.upgrade ); } public static boolean suitableForFamily( ComputerFamily family, ITurtleUpgrade upgrade ) @@ -131,6 +126,41 @@ public final class TurtleUpgrades return true; } + /** + * Rebuild the cache of turtle upgrades. This is done before querying the cache or registering new upgrades. + */ + private static void rebuild() + { + if( !needsRebuild ) return; + + upgrades.clear(); + for( Wrapper wrapper : wrappers.values() ) + { + if( !wrapper.enabled ) continue; + + ITurtleUpgrade existing = upgrades.get( wrapper.id ); + if( existing != null ) + { + ComputerCraft.log.error( "Error registering '" + wrapper.upgrade.getUnlocalisedAdjective() + " Turtle'." + + " Upgrade ID '" + wrapper.id + "' is already registered by '" + existing.getUnlocalisedAdjective() + " Turtle'" ); + continue; + } + + upgrades.put( wrapper.id, wrapper.upgrade ); + } + + needsRebuild = false; + } + + public static void enable( ITurtleUpgrade upgrade ) + { + Wrapper wrapper = wrappers.get( upgrade ); + if( wrapper.enabled ) return; + + wrapper.enabled = true; + needsRebuild = true; + } + public static void disable( ITurtleUpgrade upgrade ) { Wrapper wrapper = wrappers.get( upgrade ); @@ -138,6 +168,11 @@ public final class TurtleUpgrades wrapper.enabled = false; upgrades.remove( wrapper.id ); - if( wrapper.legacyId >= 0 ) legacyUpgrades.remove( wrapper.legacyId ); + } + + public static void remove( ITurtleUpgrade upgrade ) + { + wrappers.remove( upgrade ); + needsRebuild = true; } } diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java new file mode 100644 index 000000000..9635e0410 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java @@ -0,0 +1,40 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.integration.crafttweaker; + +import com.blamejared.crafttweaker.api.logger.ILogger; + +/** + * Logger which tracks if it has any messages. + */ +public final class TrackingLogger +{ + private final ILogger logger; + private boolean ok = true; + + public TrackingLogger( ILogger logger ) + { + this.logger = logger; + } + + public boolean isOk() + { + return ok; + } + + public void warning( String message ) + { + ok = false; + logger.warning( message ); + } + + public void error( String message ) + { + ok = false; + logger.error( message ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java index 8f1439233..ecefb37b8 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java @@ -6,65 +6,67 @@ package dan200.computercraft.shared.integration.crafttweaker; -import crafttweaker.CraftTweakerAPI; -import crafttweaker.annotations.ModOnly; -import crafttweaker.annotations.ZenDoc; -import crafttweaker.annotations.ZenRegister; -import crafttweaker.api.item.IItemStack; -import crafttweaker.api.minecraft.CraftTweakerMC; -import dan200.computercraft.ComputerCraft; +import com.blamejared.crafttweaker.api.CraftTweakerAPI; +import com.blamejared.crafttweaker.api.annotations.ZenRegister; +import com.blamejared.crafttweaker.api.item.IItemStack; import dan200.computercraft.shared.integration.crafttweaker.actions.AddTurtleTool; import dan200.computercraft.shared.integration.crafttweaker.actions.RemoveTurtleUpgradeByItem; import dan200.computercraft.shared.integration.crafttweaker.actions.RemoveTurtleUpgradeByName; -import stanhebben.zenscript.annotations.ZenClass; -import stanhebben.zenscript.annotations.ZenMethod; +import org.openzen.zencode.java.ZenCodeType; @ZenRegister -@ZenClass( "dan200.computercraft.turtle" ) -@ModOnly( ComputerCraft.MOD_ID ) +@ZenCodeType.Name( "dan200.computercraft.turtle" ) public class TurtleTweaker { - @ZenMethod - @ZenDoc( "Remove a turtle upgrade with the given id" ) + /** + * Remove a turtle upgrade with the given id + * + * @param upgrade The ID of the to remove + */ + @ZenCodeType.Method public static void removeUpgrade( String upgrade ) { CraftTweakerAPI.apply( new RemoveTurtleUpgradeByName( upgrade ) ); } - @ZenMethod - @ZenDoc( "Remove a turtle upgrade crafted with the given item stack" ) + /** + * Remove a turtle upgrade crafted with the given item stack" + * + * @param stack The stack with which the upgrade is crafted. + */ + @ZenCodeType.Method public static void removeUpgrade( IItemStack stack ) { - CraftTweakerAPI.apply( new RemoveTurtleUpgradeByItem( CraftTweakerMC.getItemStack( stack ) ) ); + CraftTweakerAPI.apply( new RemoveTurtleUpgradeByItem( stack.getInternal() ) ); } - @ZenMethod - @ZenDoc( "Add a new turtle tool with the given id, which crafts and acts using the given stack." ) + /** + * Add a new turtle tool with the given id, which crafts and acts using the given stack. + * + * @param id The new upgrade's ID + * @param stack The stack used for crafting the upgrade and used by the turtle as a tool. + */ + @ZenCodeType.Method public static void addTool( String id, IItemStack stack ) { addTool( id, stack, stack, "tool" ); } - @ZenMethod - @ZenDoc( "Add a new turtle tool with the given id, which is crafted with one item, and uses another." ) + @ZenCodeType.Method public static void addTool( String id, IItemStack craftingStack, IItemStack toolStack ) { addTool( id, craftingStack, toolStack, "tool" ); } - @ZenMethod - @ZenDoc( "Add a new turtle tool with the given id, which crafts and acts using the given stack. You may also" + - "specify a 'kind' of tool, which limits what blocks the turtle can break (for instance, an 'axe' may only break wood)." ) + @ZenCodeType.Method public static void addTool( String id, IItemStack stack, String kind ) { addTool( id, stack, stack, kind ); } - @ZenMethod - @ZenDoc( "Add a new turtle tool with the given id, which is crafted with one item, and uses another. You may also" + - "specify a 'kind' of tool, which limits what blocks the turtle can break (for instance, an 'axe' may only break wood)." ) + @ZenCodeType.Method public static void addTool( String id, IItemStack craftingStack, IItemStack toolStack, String kind ) { - CraftTweakerAPI.apply( new AddTurtleTool( id, CraftTweakerMC.getItemStack( craftingStack ), CraftTweakerMC.getItemStack( toolStack ), kind ) ); + CraftTweakerAPI.apply( new AddTurtleTool( id, craftingStack.getInternal(), toolStack.getInternal(), kind ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java index 3b34cf5d7..47ab16f42 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java @@ -6,20 +6,24 @@ package dan200.computercraft.shared.integration.crafttweaker.actions; +import com.blamejared.crafttweaker.api.actions.IUndoableAction; +import com.blamejared.crafttweaker.api.logger.ILogger; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.TurtleUpgrades; +import dan200.computercraft.shared.integration.crafttweaker.TrackingLogger; import dan200.computercraft.shared.turtle.upgrades.*; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.LogicalSide; import java.util.HashMap; import java.util.Map; -import java.util.Optional; /** * Register a new turtle tool. */ -public class AddTurtleTool implements IAction +public class AddTurtleTool implements IUndoableAction { private interface Factory { @@ -42,6 +46,8 @@ public class AddTurtleTool implements IAction private final ItemStack toolItem; private final String kind; + private ITurtleUpgrade upgrade; + public AddTurtleTool( String id, ItemStack craftItem, ItemStack toolItem, String kind ) { this.id = id; @@ -53,16 +59,22 @@ public class AddTurtleTool implements IAction @Override public void apply() { - Factory factory = kinds.get( kind ); - if( factory == null ) + ITurtleUpgrade upgrade = this.upgrade; + if( upgrade == null ) { - ComputerCraft.log.error( "Unknown turtle upgrade kind '{}' (this should have been rejected by verify!)", kind ); - return; + Factory factory = kinds.get( kind ); + if( factory == null ) + { + ComputerCraft.log.error( "Unknown turtle upgrade kind '{}' (this should have been rejected by verify!)", kind ); + return; + } + + upgrade = this.upgrade = factory.create( new ResourceLocation( id ), craftItem, toolItem ); } try { - TurtleUpgrades.register( factory.create( new ResourceLocation( id ), craftItem, toolItem ) ); + TurtleUpgrades.register( upgrade ); } catch( RuntimeException e ) { @@ -76,21 +88,40 @@ public class AddTurtleTool implements IAction return String.format( "Add new turtle %s '%s' (crafted with '%s', uses a '%s')", kind, id, craftItem, toolItem ); } - public Optional getValidationProblem() + @Override + public void undo() { - if( craftItem.isEmpty() ) return Optional.of( "Crafting item stack is empty." ); - if( craftItem.hasTagCompound() && !craftItem.getTagCompound().isEmpty() ) - { - return Optional.of( "Crafting item has NBT." ); - } - if( toolItem.isEmpty() ) return Optional.of( "Tool item stack is empty." ); - if( !kinds.containsKey( kind ) ) return Optional.of( String.format( "Unknown kind '%s'.", kind ) ); + if( upgrade != null ) TurtleUpgrades.remove( upgrade ); + } + + @Override + public String describeUndo() + { + return String.format( "Removing turtle upgrade %s.", id ); + } + + public boolean validate( ILogger logger ) + { + TrackingLogger trackLog = new TrackingLogger( logger ); + + if( craftItem.isEmpty() ) trackLog.warning( "Crafting item stack is empty." ); + + if( craftItem.hasTag() && !craftItem.getTag().isEmpty() ) trackLog.warning( "Crafting item has NBT." ); + if( toolItem.isEmpty() ) trackLog.error( "Tool item stack is empty." ); + + if( !kinds.containsKey( kind ) ) trackLog.error( String.format( "Unknown kind '%s'.", kind ) ); if( TurtleUpgrades.get( id ) != null ) { - return Optional.of( String.format( "An upgrade with the same name ('%s') has already been registered.", id ) ); + trackLog.error( String.format( "An upgrade with the same name ('%s') has already been registered.", id ) ); } - return Optional.empty(); + return trackLog.isOk(); + } + + @Override + public boolean shouldApplyOn( LogicalSide side ) + { + return true; } } diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java deleted file mode 100644 index d726c7090..000000000 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.shared.integration.crafttweaker.actions; - -import java.util.Optional; - -/** - * An extension of {@link IAction} with a single validation function, rather than two. - */ -public interface IAction extends crafttweaker.IAction -{ - default Optional getValidationProblem() - { - return Optional.empty(); - } - - @Override - default boolean validate() - { - return !getValidationProblem().isPresent(); - } - - @Override - default String describeInvalid() - { - return getValidationProblem().orElse( "No problems found." ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java index 939e72592..822db3309 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java @@ -6,18 +6,20 @@ package dan200.computercraft.shared.integration.crafttweaker.actions; +import com.blamejared.crafttweaker.api.actions.IUndoableAction; +import com.blamejared.crafttweaker.api.logger.ILogger; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.TurtleUpgrades; import net.minecraft.item.ItemStack; - -import java.util.Optional; +import net.minecraftforge.fml.LogicalSide; /** * Removes a turtle upgrade crafted with the given stack. */ -public class RemoveTurtleUpgradeByItem implements IAction +public class RemoveTurtleUpgradeByItem implements IUndoableAction { private final ItemStack stack; + private ITurtleUpgrade upgrade; public RemoveTurtleUpgradeByItem( ItemStack stack ) { @@ -27,7 +29,7 @@ public class RemoveTurtleUpgradeByItem implements IAction @Override public void apply() { - ITurtleUpgrade upgrade = TurtleUpgrades.get( stack ); + ITurtleUpgrade upgrade = this.upgrade = TurtleUpgrades.get( stack ); if( upgrade != null ) TurtleUpgrades.disable( upgrade ); } @@ -38,13 +40,32 @@ public class RemoveTurtleUpgradeByItem implements IAction } @Override - public Optional getValidationProblem() + public void undo() + { + if( this.upgrade != null ) TurtleUpgrades.enable( upgrade ); + } + + @Override + public String describeUndo() + { + return String.format( "Adding back turtle upgrades crafted with '%s'", stack ); + } + + @Override + public boolean validate( ILogger logger ) { if( TurtleUpgrades.get( stack ) == null ) { - return Optional.of( String.format( "Unknown turtle upgrade crafted with '%s'.", stack ) ); + logger.error( String.format( "Unknown turtle upgrade crafted with '%s'.", stack ) ); + return false; } - return Optional.empty(); + return true; + } + + @Override + public boolean shouldApplyOn( LogicalSide side ) + { + return true; } } diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java index ce41a17d9..9f1f8a1bd 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java @@ -6,17 +6,19 @@ package dan200.computercraft.shared.integration.crafttweaker.actions; +import com.blamejared.crafttweaker.api.actions.IUndoableAction; +import com.blamejared.crafttweaker.api.logger.ILogger; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.TurtleUpgrades; - -import java.util.Optional; +import net.minecraftforge.fml.LogicalSide; /** * Removes a turtle upgrade with the given id. */ -public class RemoveTurtleUpgradeByName implements IAction +public class RemoveTurtleUpgradeByName implements IUndoableAction { private final String id; + private ITurtleUpgrade upgrade; public RemoveTurtleUpgradeByName( String id ) { @@ -26,7 +28,7 @@ public class RemoveTurtleUpgradeByName implements IAction @Override public void apply() { - ITurtleUpgrade upgrade = TurtleUpgrades.get( id ); + ITurtleUpgrade upgrade = this.upgrade = TurtleUpgrades.get( id ); if( upgrade != null ) TurtleUpgrades.disable( upgrade ); } @@ -37,13 +39,32 @@ public class RemoveTurtleUpgradeByName implements IAction } @Override - public Optional getValidationProblem() + public void undo() + { + if( this.upgrade != null ) TurtleUpgrades.enable( upgrade ); + } + + @Override + public String describeUndo() + { + return String.format( "Adding back turtle upgrade '%s'", id ); + } + + @Override + public boolean validate( ILogger logger ) { if( TurtleUpgrades.get( id ) == null ) { - return Optional.of( String.format( "Unknown turtle upgrade '%s'.", id ) ); + logger.error( String.format( "Unknown turtle upgrade '%s'.", id ) ); + return false; } - return Optional.empty(); + return true; + } + + @Override + public boolean shouldApplyOn( LogicalSide side ) + { + return true; } } diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index b44035afa..93ccb2a9e 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -76,12 +76,10 @@ public class JEIComputerCraft implements IModPlugin List upgradeItems = new ArrayList<>(); for( ComputerFamily family : MAIN_FAMILIES ) { - for( ITurtleUpgrade upgrade : TurtleUpgrades.getUpgrades() ) - { - if( !TurtleUpgrades.suitableForFamily( family, upgrade ) ) continue; - - upgradeItems.add( TurtleItemFactory.create( -1, null, -1, family, null, upgrade, 0, null ) ); - } + TurtleUpgrades.getUpgrades() + .filter( x -> TurtleUpgrades.suitableForFamily( family, x ) ) + .map( x -> TurtleItemFactory.create( -1, null, -1, family, null, x, 0, null ) ) + .forEach( upgradeItems::add ); for( IPocketUpgrade upgrade : PocketUpgrades.getUpgrades() ) { diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java index e30417122..818e9e936 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java @@ -53,15 +53,14 @@ class RecipeResolver implements IRecipeManagerPlugin if( initialised ) return; initialised = true; - for( ITurtleUpgrade upgrade : TurtleUpgrades.getUpgrades() ) - { + TurtleUpgrades.getUpgrades().forEach( upgrade -> { ItemStack stack = upgrade.getCraftingItem(); - if( stack.isEmpty() ) continue; + if( stack.isEmpty() ) return; UpgradeInfo info = new UpgradeInfo( stack, upgrade ); upgradeItemLookup.computeIfAbsent( stack.getItem(), k -> new ArrayList<>( 1 ) ).add( info ); turtleUpgrades.add( info ); - } + } ); for( IPocketUpgrade upgrade : PocketUpgrades.getUpgrades() ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index 889cf1a20..6e5f2e8f5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -66,12 +66,10 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem ComputerFamily family = getFamily(); list.add( create( -1, null, -1, null, null, 0, null ) ); - for( ITurtleUpgrade upgrade : TurtleUpgrades.getVanillaUpgrades() ) - { - if( !TurtleUpgrades.suitableForFamily( family, upgrade ) ) continue; - - list.add( create( -1, null, -1, null, upgrade, 0, null ) ); - } + TurtleUpgrades.getVanillaUpgrades() + .filter( x -> TurtleUpgrades.suitableForFamily( family, x ) ) + .map( x -> create( -1, null, -1, null, x, 0, null ) ) + .forEach( list::add ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 71a2ecbac..0e3c479e3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -65,7 +65,7 @@ public class TurtleTool extends AbstractTurtleUpgrade public TurtleTool( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { - super( id, -1, TurtleUpgradeType.Tool, craftItem ); + super( id, TurtleUpgradeType.Tool, craftItem ); this.item = toolItem; } From 0f82a4589b631506c58928214c692ff27fce48d5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 24 Dec 2019 19:31:14 +0000 Subject: [PATCH 118/711] Fix complaints --- src/main/java/dan200/computercraft/shared/TurtleUpgrades.java | 2 +- .../shared/integration/crafttweaker/TurtleTweaker.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 01f507e63..655849238 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -27,7 +27,7 @@ public final class TurtleUpgrades final String modId; boolean enabled; - public Wrapper( ITurtleUpgrade upgrade ) + Wrapper( ITurtleUpgrade upgrade ) { this.upgrade = upgrade; this.id = upgrade.getUpgradeID().toString(); diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java index ecefb37b8..4d8cf8991 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java @@ -19,7 +19,7 @@ import org.openzen.zencode.java.ZenCodeType; public class TurtleTweaker { /** - * Remove a turtle upgrade with the given id + * Remove a turtle upgrade with the given id. * * @param upgrade The ID of the to remove */ @@ -30,7 +30,7 @@ public class TurtleTweaker } /** - * Remove a turtle upgrade crafted with the given item stack" + * Remove a turtle upgrade crafted with the given item stack". * * @param stack The stack with which the upgrade is crafted. */ From 041cfe91b4f53ec2fe4c85a0849cdbcfc40eb53e Mon Sep 17 00:00:00 2001 From: Jacob <32282272+jakedacatman@users.noreply.github.com> Date: Sun, 29 Dec 2019 01:12:55 -0500 Subject: [PATCH 119/711] wilcards > wildcards (#331) --- src/main/java/dan200/computercraft/shared/Config.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 8c80af4ba..3bb116666 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -183,14 +183,14 @@ public final class Config "\"http\" API on Computers.\n" + "Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to " + "just subdomains of pastebin.com.\n" + - "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); + "You can use domain names (\"pastebin.com\"), wildcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); httpBlockedDomains = config.get( CATEGORY_HTTP, "blocked_domains", DEFAULT_HTTP_BLACKLIST ); httpBlockedDomains.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the " + "\"http\" API on Computers.\n" + "If this is empty then all explicitly allowed domains will be accessible. Example: \"*.github.com\" will block " + "access to all subdomains of github.com.\n" + - "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); + "You can use domain names (\"pastebin.com\"), wildcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ); httpTimeout = config.get( CATEGORY_HTTP, "timeout", ComputerCraft.httpTimeout ); httpTimeout.setComment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ); From 42f5389fb8dbbb60afcd99cb1cf6676e94f5715d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 29 Dec 2019 18:49:35 +0000 Subject: [PATCH 120/711] Make Lua's "exit" function a little prettier "exit" now has a custom __tostring method, which prints an explanation message. This is very similar to how Python achives the same functionality: lua> exit Call exit() to exit lua> exit() > Actually leaves the REPL --- .../assets/computercraft/lua/rom/programs/lua.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 3535b19df..63d4c6add 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -9,9 +9,10 @@ end local bRunning = true local tCommandHistory = {} local tEnv = { - ["exit"] = function() - bRunning = false - end, + ["exit"] = setmetatable({}, { + __tostring = function() return "Call exit() to exit" end, + __call = function() bRunning = false end, + }), ["_echo"] = function( ... ) return ... end, From 0bcd28e58c8cffc92af75e7bc58da2de681222bb Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 29 Dec 2019 19:47:52 +0000 Subject: [PATCH 121/711] Fix incorrect module names --- .../computercraft/lua/rom/modules/main/cc/completion.lua | 2 +- .../assets/computercraft/lua/rom/modules/main/cc/expect.lua | 4 ++-- .../lua/rom/modules/main/cc/shell/completion.lua | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua index 4634bcc98..2ae2e4966 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/completion.lua @@ -1,7 +1,7 @@ --- A collection of helper methods for working with input completion, such -- as that require by @{read}. -- --- @module craftos.completion +-- @module cc.completion -- @see cc.shell.completion For additional helpers to use with -- @{shell.setCompletionFunction}. diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua index 14db7231c..7b1a53e8c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua @@ -1,7 +1,7 @@ ---- The @{craftos.expect} library provides helper functions for verifying that +--- The @{cc.expect} library provides helper functions for verifying that -- function arguments are well-formed and of the correct type. -- --- @module craftos.expect +-- @module cc.expect local native_select, native_type = select, type diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua index 023e500fc..865e54dcb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -7,7 +7,7 @@ -- and so are not directly usable with the @{shell.setCompletionFunction}. Instead, -- wrap them using @{build}, or your own custom function. -- --- @module craftos.shell.completion +-- @module cc.shell.completion -- @see cc.completion For more general helpers, suitable for use with @{read}. -- @see shell.setCompletionFunction From 393e6287212a338ad668c7ff3bbb2b7c6efac39b Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Mon, 30 Dec 2019 16:26:57 +0000 Subject: [PATCH 122/711] More MOTDs (#333) --- .../resources/assets/computercraft/lua/rom/motd.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/motd.txt b/src/main/resources/assets/computercraft/lua/rom/motd.txt index d82c3a995..87f3f0503 100644 --- a/src/main/resources/assets/computercraft/lua/rom/motd.txt +++ b/src/main/resources/assets/computercraft/lua/rom/motd.txt @@ -28,7 +28,16 @@ Use "monitor" to run a program on a attached monitor. View all attached peripherals with "peripherals". Use "time" to see the in-game time. You can set the label of a computer with "label set". -A computer needs a label to keep its files if it got destroyed. +A computer needs a label to keep its files if it is destroyed. You can disable auto completion in the shell with "set shell.autocomplete false". You can disable auto completion in edit with "set edit.autocomplete false". Feeling creative? Use a printer to print a book! +Files beginning with a "." character are hidden from "list" by default. +Running "set" lists the current values of all settings. +Some programs are only available on advanced computers, turtles, pocket computers, or command computers. +The "equip" and "unequip" programs let you add or remove supported upgrades from a turtle or pocket computer without crafting. +You can change the color of a disk by crafting it with dye. +Right-clicking a turtle with a dye changes its color. +You can print on a printed page again to get multiple colors. +Holding the Control and T keys terminates the running program. +Holding Control and S or R shuts down or reboots the computer you are using. From 7cc2bd43c64b35bd02951c3479a1746889b30884 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Wed, 1 Jan 2020 01:08:31 +0100 Subject: [PATCH 123/711] Make builded Jar downloadable (#332) --- .github/workflows/main-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 649c36da6..d0caedbf2 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -18,6 +18,12 @@ jobs: - name: Build with Gradle run: ./gradlew build --no-daemon + - name: Upload Jar + uses: actions/upload-artifact@v1 + with: + name: CC-Tweaked + path: build/libs + lint-lua: name: Lint Lua runs-on: ubuntu-latest From 93a9ebc4f6b8c7c59151feffa1b5ab3996c016f5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 1 Jan 2020 00:09:18 +0000 Subject: [PATCH 124/711] Happy new year --- src/main/java/dan200/computercraft/CCTweaked.java | 3 +-- src/main/java/dan200/computercraft/ComputerCraft.java | 3 +-- .../java/dan200/computercraft/api/AbstractTurtleUpgrade.java | 2 +- src/main/java/dan200/computercraft/api/ComputerCraftAPI.java | 3 +-- .../computercraft/api/filesystem/FileOperationException.java | 2 +- .../java/dan200/computercraft/api/filesystem/IFileSystem.java | 3 +-- src/main/java/dan200/computercraft/api/filesystem/IMount.java | 3 +-- .../dan200/computercraft/api/filesystem/IWritableMount.java | 3 +-- .../java/dan200/computercraft/api/filesystem/package-info.java | 3 +-- src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java | 3 +-- .../java/dan200/computercraft/api/lua/IComputerSystem.java | 3 +-- src/main/java/dan200/computercraft/api/lua/ILuaAPI.java | 3 +-- src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java | 3 +-- src/main/java/dan200/computercraft/api/lua/ILuaContext.java | 3 +-- src/main/java/dan200/computercraft/api/lua/ILuaObject.java | 3 +-- src/main/java/dan200/computercraft/api/lua/ILuaTask.java | 3 +-- src/main/java/dan200/computercraft/api/lua/LuaException.java | 3 +-- src/main/java/dan200/computercraft/api/lua/package-info.java | 3 +-- src/main/java/dan200/computercraft/api/media/IMedia.java | 3 +-- .../java/dan200/computercraft/api/media/IMediaProvider.java | 3 +-- src/main/java/dan200/computercraft/api/media/package-info.java | 3 +-- .../java/dan200/computercraft/api/network/IPacketNetwork.java | 2 +- .../java/dan200/computercraft/api/network/IPacketReceiver.java | 2 +- .../java/dan200/computercraft/api/network/IPacketSender.java | 2 +- src/main/java/dan200/computercraft/api/network/Packet.java | 2 +- .../java/dan200/computercraft/api/network/package-info.java | 3 +-- .../dan200/computercraft/api/network/wired/IWiredElement.java | 3 +-- .../dan200/computercraft/api/network/wired/IWiredNetwork.java | 3 +-- .../computercraft/api/network/wired/IWiredNetworkChange.java | 3 +-- .../dan200/computercraft/api/network/wired/IWiredNode.java | 3 +-- .../dan200/computercraft/api/network/wired/IWiredSender.java | 3 +-- .../dan200/computercraft/api/network/wired/package-info.java | 3 +-- src/main/java/dan200/computercraft/api/package-info.java | 3 +-- .../dan200/computercraft/api/peripheral/IComputerAccess.java | 3 +-- .../java/dan200/computercraft/api/peripheral/IPeripheral.java | 3 +-- .../computercraft/api/peripheral/IPeripheralProvider.java | 3 +-- .../dan200/computercraft/api/peripheral/IPeripheralTile.java | 2 +- .../java/dan200/computercraft/api/peripheral/IWorkMonitor.java | 2 +- .../java/dan200/computercraft/api/peripheral/package-info.java | 3 +-- .../api/permissions/ITurtlePermissionProvider.java | 3 +-- .../dan200/computercraft/api/permissions/package-info.java | 3 +-- .../dan200/computercraft/api/pocket/AbstractPocketUpgrade.java | 2 +- .../java/dan200/computercraft/api/pocket/IPocketAccess.java | 3 +-- .../java/dan200/computercraft/api/pocket/IPocketUpgrade.java | 3 +-- .../computercraft/api/redstone/IBundledRedstoneProvider.java | 3 +-- .../java/dan200/computercraft/api/redstone/package-info.java | 3 +-- .../java/dan200/computercraft/api/turtle/ITurtleAccess.java | 3 +-- .../java/dan200/computercraft/api/turtle/ITurtleCommand.java | 3 +-- .../java/dan200/computercraft/api/turtle/ITurtleUpgrade.java | 3 +-- .../java/dan200/computercraft/api/turtle/TurtleAnimation.java | 3 +-- .../dan200/computercraft/api/turtle/TurtleCommandResult.java | 3 +-- src/main/java/dan200/computercraft/api/turtle/TurtleSide.java | 3 +-- .../dan200/computercraft/api/turtle/TurtleUpgradeType.java | 3 +-- src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java | 3 +-- .../dan200/computercraft/api/turtle/event/TurtleAction.java | 3 +-- .../computercraft/api/turtle/event/TurtleActionEvent.java | 3 +-- .../computercraft/api/turtle/event/TurtleAttackEvent.java | 3 +-- .../computercraft/api/turtle/event/TurtleBlockEvent.java | 3 +-- .../dan200/computercraft/api/turtle/event/TurtleEvent.java | 3 +-- .../computercraft/api/turtle/event/TurtleInspectItemEvent.java | 2 +- .../computercraft/api/turtle/event/TurtleInventoryEvent.java | 3 +-- .../computercraft/api/turtle/event/TurtlePlayerEvent.java | 3 +-- .../computercraft/api/turtle/event/TurtleRefuelEvent.java | 2 +- .../dan200/computercraft/api/turtle/event/package-info.java | 3 +-- .../java/dan200/computercraft/api/turtle/package-info.java | 3 +-- src/main/java/dan200/computercraft/client/ClientRegistry.java | 3 +-- .../java/dan200/computercraft/client/ClientTableFormatter.java | 3 +-- src/main/java/dan200/computercraft/client/FrameInfo.java | 3 +-- .../computercraft/client/gui/FixedWidthFontRenderer.java | 3 +-- src/main/java/dan200/computercraft/client/gui/GuiComputer.java | 3 +-- src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java | 3 +-- .../java/dan200/computercraft/client/gui/GuiDiskDrive.java | 3 +-- .../dan200/computercraft/client/gui/GuiPocketComputer.java | 3 +-- src/main/java/dan200/computercraft/client/gui/GuiPrinter.java | 3 +-- src/main/java/dan200/computercraft/client/gui/GuiPrintout.java | 3 +-- src/main/java/dan200/computercraft/client/gui/GuiTurtle.java | 3 +-- .../java/dan200/computercraft/client/gui/widgets/Widget.java | 3 +-- .../computercraft/client/gui/widgets/WidgetTerminal.java | 3 +-- .../computercraft/client/proxy/ComputerCraftProxyClient.java | 3 +-- .../computercraft/client/render/CableHighlightRenderer.java | 3 +-- .../computercraft/client/render/ItemMapLikeRenderer.java | 3 +-- .../dan200/computercraft/client/render/ItemPocketRenderer.java | 3 +-- .../computercraft/client/render/ItemPrintoutRenderer.java | 3 +-- .../dan200/computercraft/client/render/ModelTransformer.java | 3 +-- .../computercraft/client/render/MonitorHighlightRenderer.java | 3 +-- .../dan200/computercraft/client/render/PrintoutRenderer.java | 3 +-- .../computercraft/client/render/TileEntityCableRenderer.java | 3 +-- .../computercraft/client/render/TileEntityMonitorRenderer.java | 3 +-- .../computercraft/client/render/TileEntityTurtleRenderer.java | 3 +-- .../dan200/computercraft/client/render/TurtleModelLoader.java | 3 +-- .../dan200/computercraft/client/render/TurtleMultiModel.java | 3 +-- .../computercraft/client/render/TurtleSmartItemModel.java | 3 +-- .../java/dan200/computercraft/core/apis/AddressPredicate.java | 3 +-- src/main/java/dan200/computercraft/core/apis/ApiFactories.java | 3 +-- .../java/dan200/computercraft/core/apis/ArgumentHelper.java | 3 +-- .../java/dan200/computercraft/core/apis/ComputerAccess.java | 3 +-- src/main/java/dan200/computercraft/core/apis/FSAPI.java | 3 +-- src/main/java/dan200/computercraft/core/apis/HTTPAPI.java | 3 +-- .../java/dan200/computercraft/core/apis/IAPIEnvironment.java | 3 +-- src/main/java/dan200/computercraft/core/apis/ILuaAPI.java | 3 +-- src/main/java/dan200/computercraft/core/apis/LuaDateTime.java | 3 +-- src/main/java/dan200/computercraft/core/apis/OSAPI.java | 3 +-- .../java/dan200/computercraft/core/apis/PeripheralAPI.java | 3 +-- src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java | 3 +-- src/main/java/dan200/computercraft/core/apis/TableHelper.java | 3 +-- src/main/java/dan200/computercraft/core/apis/TermAPI.java | 3 +-- .../computercraft/core/apis/handles/ArrayByteChannel.java | 3 +-- .../computercraft/core/apis/handles/BinaryReadableHandle.java | 3 +-- .../computercraft/core/apis/handles/BinaryWritableHandle.java | 3 +-- .../computercraft/core/apis/handles/EncodedReadableHandle.java | 3 +-- .../computercraft/core/apis/handles/EncodedWritableHandle.java | 3 +-- .../dan200/computercraft/core/apis/handles/HandleGeneric.java | 3 +-- .../java/dan200/computercraft/core/apis/http/CheckUrl.java | 3 +-- .../computercraft/core/apis/http/HTTPRequestException.java | 3 +-- .../java/dan200/computercraft/core/apis/http/NetworkUtils.java | 3 +-- .../java/dan200/computercraft/core/apis/http/Resource.java | 3 +-- .../dan200/computercraft/core/apis/http/ResourceGroup.java | 3 +-- .../dan200/computercraft/core/apis/http/ResourceQueue.java | 3 +-- .../computercraft/core/apis/http/request/HttpRequest.java | 3 +-- .../core/apis/http/request/HttpRequestHandler.java | 3 +-- .../core/apis/http/request/HttpResponseHandle.java | 3 +-- .../computercraft/core/apis/http/websocket/Websocket.java | 3 +-- .../core/apis/http/websocket/WebsocketHandle.java | 3 +-- .../core/apis/http/websocket/WebsocketHandler.java | 3 +-- .../java/dan200/computercraft/core/computer/ApiWrapper.java | 3 +-- src/main/java/dan200/computercraft/core/computer/Computer.java | 3 +-- .../dan200/computercraft/core/computer/ComputerExecutor.java | 3 +-- .../java/dan200/computercraft/core/computer/ComputerSide.java | 3 +-- .../dan200/computercraft/core/computer/ComputerSystem.java | 3 +-- .../dan200/computercraft/core/computer/ComputerThread.java | 3 +-- .../java/dan200/computercraft/core/computer/Environment.java | 3 +-- .../computercraft/core/computer/IComputerEnvironment.java | 3 +-- .../java/dan200/computercraft/core/computer/MainThread.java | 3 +-- .../dan200/computercraft/core/computer/MainThreadExecutor.java | 3 +-- .../java/dan200/computercraft/core/computer/TimeoutState.java | 3 +-- .../dan200/computercraft/core/filesystem/ChannelWrapper.java | 3 +-- .../java/dan200/computercraft/core/filesystem/ComboMount.java | 3 +-- .../java/dan200/computercraft/core/filesystem/EmptyMount.java | 3 +-- .../java/dan200/computercraft/core/filesystem/FileMount.java | 3 +-- .../java/dan200/computercraft/core/filesystem/FileSystem.java | 3 +-- .../computercraft/core/filesystem/FileSystemException.java | 3 +-- .../computercraft/core/filesystem/FileSystemWrapper.java | 3 +-- .../computercraft/core/filesystem/FileSystemWrapperMount.java | 3 +-- .../java/dan200/computercraft/core/filesystem/JarMount.java | 3 +-- .../java/dan200/computercraft/core/filesystem/SubMount.java | 3 +-- .../java/dan200/computercraft/core/lua/CobaltLuaMachine.java | 3 +-- src/main/java/dan200/computercraft/core/lua/ILuaMachine.java | 3 +-- src/main/java/dan200/computercraft/core/lua/MachineResult.java | 3 +-- src/main/java/dan200/computercraft/core/terminal/Terminal.java | 3 +-- .../java/dan200/computercraft/core/terminal/TextBuffer.java | 3 +-- .../dan200/computercraft/core/tracking/ComputerTracker.java | 3 +-- src/main/java/dan200/computercraft/core/tracking/Tracker.java | 3 +-- src/main/java/dan200/computercraft/core/tracking/Tracking.java | 3 +-- .../dan200/computercraft/core/tracking/TrackingContext.java | 3 +-- .../java/dan200/computercraft/core/tracking/TrackingField.java | 3 +-- src/main/java/dan200/computercraft/shared/BundledRedstone.java | 3 +-- src/main/java/dan200/computercraft/shared/Config.java | 3 +-- src/main/java/dan200/computercraft/shared/MediaProviders.java | 3 +-- src/main/java/dan200/computercraft/shared/Peripherals.java | 3 +-- src/main/java/dan200/computercraft/shared/PocketUpgrades.java | 3 +-- src/main/java/dan200/computercraft/shared/Registry.java | 3 +-- .../java/dan200/computercraft/shared/TurtlePermissions.java | 3 +-- src/main/java/dan200/computercraft/shared/TurtleUpgrades.java | 3 +-- .../computercraft/shared/command/CommandComputerCraft.java | 3 +-- .../java/dan200/computercraft/shared/command/CommandCopy.java | 3 +-- .../java/dan200/computercraft/shared/command/CommandUtils.java | 3 +-- .../dan200/computercraft/shared/command/ComputerSelector.java | 3 +-- .../java/dan200/computercraft/shared/command/UserLevel.java | 3 +-- .../computercraft/shared/command/framework/CommandContext.java | 3 +-- .../shared/command/framework/CommandDelegate.java | 3 +-- .../computercraft/shared/command/framework/CommandRoot.java | 3 +-- .../computercraft/shared/command/framework/ISubCommand.java | 3 +-- .../computercraft/shared/command/framework/SubCommandBase.java | 3 +-- .../computercraft/shared/command/framework/SubCommandHelp.java | 3 +-- .../dan200/computercraft/shared/command/text/ChatHelpers.java | 3 +-- .../shared/command/text/ServerTableFormatter.java | 3 +-- .../dan200/computercraft/shared/command/text/TableBuilder.java | 3 +-- .../computercraft/shared/command/text/TableFormatter.java | 3 +-- .../dan200/computercraft/shared/common/BlockDirectional.java | 3 +-- .../java/dan200/computercraft/shared/common/BlockGeneric.java | 3 +-- .../dan200/computercraft/shared/common/ClientTerminal.java | 3 +-- .../dan200/computercraft/shared/common/ColourableRecipe.java | 3 +-- .../shared/common/DefaultBundledRedstoneProvider.java | 3 +-- .../java/dan200/computercraft/shared/common/IColouredItem.java | 3 +-- .../dan200/computercraft/shared/common/IDirectionalTile.java | 3 +-- .../java/dan200/computercraft/shared/common/ITerminal.java | 3 +-- .../dan200/computercraft/shared/common/ServerTerminal.java | 3 +-- .../java/dan200/computercraft/shared/common/TileGeneric.java | 3 +-- .../dan200/computercraft/shared/computer/apis/CommandAPI.java | 3 +-- .../shared/computer/blocks/BlockCommandComputer.java | 3 +-- .../computercraft/shared/computer/blocks/BlockComputer.java | 3 +-- .../shared/computer/blocks/BlockComputerBase.java | 3 +-- .../shared/computer/blocks/ComputerPeripheral.java | 3 +-- .../computercraft/shared/computer/blocks/ComputerProxy.java | 3 +-- .../computercraft/shared/computer/blocks/ComputerState.java | 3 +-- .../computercraft/shared/computer/blocks/IComputerTile.java | 3 +-- .../shared/computer/blocks/TileCommandComputer.java | 3 +-- .../computercraft/shared/computer/blocks/TileComputer.java | 3 +-- .../computercraft/shared/computer/blocks/TileComputerBase.java | 3 +-- .../computercraft/shared/computer/core/ClientComputer.java | 3 +-- .../shared/computer/core/ClientComputerRegistry.java | 3 +-- .../computercraft/shared/computer/core/ComputerFamily.java | 3 +-- .../computercraft/shared/computer/core/ComputerRegistry.java | 3 +-- .../dan200/computercraft/shared/computer/core/IComputer.java | 3 +-- .../computercraft/shared/computer/core/IComputerContainer.java | 3 +-- .../computercraft/shared/computer/core/IContainerComputer.java | 3 +-- .../computercraft/shared/computer/core/InputHandler.java | 3 +-- .../dan200/computercraft/shared/computer/core/InputState.java | 3 +-- .../computercraft/shared/computer/core/ServerComputer.java | 3 +-- .../shared/computer/core/ServerComputerRegistry.java | 3 +-- .../shared/computer/inventory/ContainerComputer.java | 3 +-- .../shared/computer/inventory/ContainerViewComputer.java | 3 +-- .../shared/computer/items/ComputerItemFactory.java | 3 +-- .../computercraft/shared/computer/items/IComputerItem.java | 3 +-- .../shared/computer/items/ItemCommandComputer.java | 3 +-- .../computercraft/shared/computer/items/ItemComputer.java | 3 +-- .../computercraft/shared/computer/items/ItemComputerBase.java | 3 +-- .../shared/computer/recipe/ComputerConvertRecipe.java | 3 +-- .../shared/computer/recipe/ComputerFamilyRecipe.java | 3 +-- .../shared/computer/recipe/ComputerIngredient.java | 3 +-- src/main/java/dan200/computercraft/shared/datafix/Fixes.java | 3 +-- .../computercraft/shared/datafix/TileEntityDataFixer.java | 3 +-- .../shared/integration/charset/BundledCapabilityProvider.java | 2 +- .../shared/integration/charset/BundledRedstoneProvider.java | 2 +- .../shared/integration/charset/IntegrationCharset.java | 2 +- .../shared/integration/crafttweaker/TurtleTweaker.java | 3 +-- .../shared/integration/crafttweaker/actions/AddTurtleTool.java | 3 +-- .../shared/integration/crafttweaker/actions/IAction.java | 3 +-- .../crafttweaker/actions/RemoveTurtleUpgradeByItem.java | 3 +-- .../crafttweaker/actions/RemoveTurtleUpgradeByName.java | 3 +-- .../computercraft/shared/integration/jei/JEIComputerCraft.java | 3 +-- .../computercraft/shared/integration/jei/RecipeResolver.java | 3 +-- .../computercraft/shared/integration/mcmp/MCMPHooks.java | 3 +-- .../computercraft/shared/integration/mcmp/MCMPIntegration.java | 3 +-- .../shared/integration/mcmp/PartAdvancedModem.java | 3 +-- .../computercraft/shared/integration/mcmp/PartPeripheral.java | 3 +-- .../shared/media/inventory/ContainerHeldItem.java | 3 +-- .../computercraft/shared/media/items/ItemDiskExpanded.java | 3 +-- .../computercraft/shared/media/items/ItemDiskLegacy.java | 3 +-- .../dan200/computercraft/shared/media/items/ItemPrintout.java | 3 +-- .../computercraft/shared/media/items/ItemTreasureDisk.java | 3 +-- .../dan200/computercraft/shared/media/items/RecordMedia.java | 3 +-- .../dan200/computercraft/shared/media/recipes/DiskRecipe.java | 3 +-- .../computercraft/shared/media/recipes/PrintoutRecipe.java | 3 +-- .../java/dan200/computercraft/shared/network/Containers.java | 3 +-- .../dan200/computercraft/shared/network/NetworkHandler.java | 3 +-- .../dan200/computercraft/shared/network/NetworkMessage.java | 3 +-- .../shared/network/client/ChatTableClientMessage.java | 3 +-- .../shared/network/client/ComputerClientMessage.java | 3 +-- .../shared/network/client/ComputerDataClientMessage.java | 3 +-- .../shared/network/client/ComputerDeletedClientMessage.java | 3 +-- .../shared/network/client/ComputerTerminalClientMessage.java | 3 +-- .../shared/network/client/PlayRecordClientMessage.java | 3 +-- .../shared/network/server/ComputerActionServerMessage.java | 3 +-- .../shared/network/server/ComputerServerMessage.java | 3 +-- .../shared/network/server/KeyEventServerMessage.java | 3 +-- .../shared/network/server/MouseEventServerMessage.java | 3 +-- .../shared/network/server/QueueEventServerMessage.java | 3 +-- .../shared/network/server/RequestComputerMessage.java | 3 +-- .../dan200/computercraft/shared/peripheral/PeripheralType.java | 3 +-- .../shared/peripheral/commandblock/CommandBlockPeripheral.java | 3 +-- .../shared/peripheral/common/BlockPeripheral.java | 3 +-- .../shared/peripheral/common/BlockPeripheralVariant.java | 3 +-- .../shared/peripheral/common/IPeripheralItem.java | 3 +-- .../shared/peripheral/common/IPeripheralTile.java | 3 +-- .../shared/peripheral/common/ITilePeripheral.java | 3 +-- .../computercraft/shared/peripheral/common/ItemPeripheral.java | 3 +-- .../shared/peripheral/common/ItemPeripheralBase.java | 3 +-- .../shared/peripheral/common/PeripheralItemFactory.java | 3 +-- .../shared/peripheral/common/TilePeripheralBase.java | 3 +-- .../shared/peripheral/diskdrive/ContainerDiskDrive.java | 3 +-- .../shared/peripheral/diskdrive/DiskDrivePeripheral.java | 3 +-- .../shared/peripheral/diskdrive/TileDiskDrive.java | 3 +-- .../computercraft/shared/peripheral/modem/ModemBounds.java | 3 +-- .../computercraft/shared/peripheral/modem/ModemPeripheral.java | 3 +-- .../computercraft/shared/peripheral/modem/ModemState.java | 3 +-- .../shared/peripheral/modem/WirelessModemPeripheral.java | 3 +-- .../shared/peripheral/modem/wired/BlockCable.java | 3 +-- .../shared/peripheral/modem/wired/BlockCableModemVariant.java | 3 +-- .../shared/peripheral/modem/wired/BlockWiredModemFull.java | 3 +-- .../shared/peripheral/modem/wired/CableBounds.java | 3 +-- .../computercraft/shared/peripheral/modem/wired/ItemCable.java | 3 +-- .../shared/peripheral/modem/wired/ItemWiredModemFull.java | 3 +-- .../computercraft/shared/peripheral/modem/wired/TileCable.java | 3 +-- .../shared/peripheral/modem/wired/TileWiredModemFull.java | 3 +-- .../shared/peripheral/modem/wired/WiredModemElement.java | 3 +-- .../peripheral/modem/wired/WiredModemLocalPeripheral.java | 3 +-- .../shared/peripheral/modem/wired/WiredModemPeripheral.java | 3 +-- .../shared/peripheral/modem/wireless/BlockAdvancedModem.java | 3 +-- .../shared/peripheral/modem/wireless/ItemAdvancedModem.java | 3 +-- .../shared/peripheral/modem/wireless/TileAdvancedModem.java | 3 +-- .../shared/peripheral/modem/wireless/TileWirelessModem.java | 3 +-- .../peripheral/modem/wireless/TileWirelessModemBase.java | 3 +-- .../peripheral/modem/wireless/WirelessModemPeripheral.java | 3 +-- .../shared/peripheral/modem/wireless/WirelessNetwork.java | 3 +-- .../computercraft/shared/peripheral/monitor/ClientMonitor.java | 3 +-- .../shared/peripheral/monitor/MonitorPeripheral.java | 3 +-- .../computercraft/shared/peripheral/monitor/ServerMonitor.java | 3 +-- .../computercraft/shared/peripheral/monitor/TileMonitor.java | 3 +-- .../dan200/computercraft/shared/peripheral/monitor/XYPair.java | 3 +-- .../shared/peripheral/printer/ContainerPrinter.java | 3 +-- .../shared/peripheral/printer/PrinterPeripheral.java | 3 +-- .../computercraft/shared/peripheral/printer/TilePrinter.java | 3 +-- .../shared/peripheral/speaker/SpeakerPeripheral.java | 3 +-- .../computercraft/shared/peripheral/speaker/TileSpeaker.java | 3 +-- .../dan200/computercraft/shared/pocket/apis/PocketAPI.java | 3 +-- .../computercraft/shared/pocket/core/PocketServerComputer.java | 3 +-- .../shared/pocket/inventory/ContainerPocketComputer.java | 3 +-- .../computercraft/shared/pocket/items/ItemPocketComputer.java | 3 +-- .../shared/pocket/items/PocketComputerItemFactory.java | 3 +-- .../computercraft/shared/pocket/peripherals/PocketModem.java | 3 +-- .../shared/pocket/peripherals/PocketModemPeripheral.java | 2 +- .../computercraft/shared/pocket/peripherals/PocketSpeaker.java | 3 +-- .../shared/pocket/peripherals/PocketSpeakerPeripheral.java | 3 +-- .../shared/pocket/recipes/PocketComputerUpgradeRecipe.java | 3 +-- .../computercraft/shared/proxy/ComputerCraftProxyCommon.java | 3 +-- .../computercraft/shared/turtle/FurnaceRefuelHandler.java | 3 +-- .../dan200/computercraft/shared/turtle/apis/TurtleAPI.java | 3 +-- .../dan200/computercraft/shared/turtle/blocks/BlockTurtle.java | 3 +-- .../dan200/computercraft/shared/turtle/blocks/ITurtleTile.java | 3 +-- .../dan200/computercraft/shared/turtle/blocks/TileTurtle.java | 3 +-- .../computercraft/shared/turtle/blocks/TileTurtleAdvanced.java | 3 +-- .../computercraft/shared/turtle/blocks/TileTurtleExpanded.java | 3 +-- .../computercraft/shared/turtle/core/InteractDirection.java | 3 +-- .../dan200/computercraft/shared/turtle/core/MoveDirection.java | 3 +-- .../dan200/computercraft/shared/turtle/core/TurnDirection.java | 3 +-- .../dan200/computercraft/shared/turtle/core/TurtleBrain.java | 3 +-- .../shared/turtle/core/TurtleCommandQueueEntry.java | 3 +-- .../computercraft/shared/turtle/core/TurtleCompareCommand.java | 3 +-- .../shared/turtle/core/TurtleCompareToCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleCraftCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleDetectCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleDropCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleEquipCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleInspectCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleMoveCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtlePlaceCommand.java | 3 +-- .../dan200/computercraft/shared/turtle/core/TurtlePlayer.java | 3 +-- .../computercraft/shared/turtle/core/TurtleRefuelCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleSuckCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleToolCommand.java | 3 +-- .../shared/turtle/core/TurtleTransferToCommand.java | 3 +-- .../computercraft/shared/turtle/core/TurtleTurnCommand.java | 3 +-- .../computercraft/shared/turtle/inventory/ContainerTurtle.java | 3 +-- .../dan200/computercraft/shared/turtle/items/ITurtleItem.java | 3 +-- .../computercraft/shared/turtle/items/ItemTurtleAdvanced.java | 3 +-- .../computercraft/shared/turtle/items/ItemTurtleBase.java | 3 +-- .../computercraft/shared/turtle/items/ItemTurtleLegacy.java | 3 +-- .../computercraft/shared/turtle/items/ItemTurtleNormal.java | 3 +-- .../computercraft/shared/turtle/items/TurtleItemFactory.java | 3 +-- .../computercraft/shared/turtle/recipes/TurtleRecipe.java | 3 +-- .../shared/turtle/recipes/TurtleUpgradeRecipe.java | 3 +-- .../shared/turtle/upgrades/CraftingTablePeripheral.java | 3 +-- .../dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java | 3 +-- .../shared/turtle/upgrades/TurtleCraftingTable.java | 3 +-- .../dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java | 3 +-- .../shared/turtle/upgrades/TurtleInventoryCrafting.java | 3 +-- .../computercraft/shared/turtle/upgrades/TurtleModem.java | 3 +-- .../computercraft/shared/turtle/upgrades/TurtleShovel.java | 3 +-- .../computercraft/shared/turtle/upgrades/TurtleSpeaker.java | 3 +-- .../computercraft/shared/turtle/upgrades/TurtleSword.java | 3 +-- .../computercraft/shared/turtle/upgrades/TurtleTool.java | 3 +-- src/main/java/dan200/computercraft/shared/util/Colour.java | 3 +-- .../java/dan200/computercraft/shared/util/ColourTracker.java | 3 +-- .../java/dan200/computercraft/shared/util/ColourUtils.java | 3 +-- .../java/dan200/computercraft/shared/util/CreativeTabMain.java | 3 +-- .../dan200/computercraft/shared/util/DefaultInventory.java | 3 +-- .../computercraft/shared/util/DefaultSidedInventory.java | 3 +-- .../java/dan200/computercraft/shared/util/DirectionUtil.java | 3 +-- .../java/dan200/computercraft/shared/util/DropConsumer.java | 3 +-- .../java/dan200/computercraft/shared/util/FakeNetHandler.java | 3 +-- src/main/java/dan200/computercraft/shared/util/Holiday.java | 3 +-- .../java/dan200/computercraft/shared/util/HolidayUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/IDAssigner.java | 3 +-- .../java/dan200/computercraft/shared/util/ImpostorRecipe.java | 3 +-- .../computercraft/shared/util/ImpostorShapelessRecipe.java | 3 +-- .../dan200/computercraft/shared/util/InventoryDelegate.java | 3 +-- .../java/dan200/computercraft/shared/util/InventoryUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/IoUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/NBTUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/Palette.java | 3 +-- src/main/java/dan200/computercraft/shared/util/RecipeUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/RecordUtil.java | 3 +-- .../java/dan200/computercraft/shared/util/RedstoneUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/StringUtil.java | 3 +-- .../java/dan200/computercraft/shared/util/ThreadUtils.java | 3 +-- .../java/dan200/computercraft/shared/util/TickScheduler.java | 3 +-- .../java/dan200/computercraft/shared/util/ValidatingSlot.java | 3 +-- src/main/java/dan200/computercraft/shared/util/WorldUtil.java | 3 +-- .../computercraft/shared/wired/CapabilityWiredElement.java | 3 +-- .../dan200/computercraft/shared/wired/InvariantChecker.java | 3 +-- .../java/dan200/computercraft/shared/wired/WiredNetwork.java | 3 +-- .../dan200/computercraft/shared/wired/WiredNetworkChange.java | 3 +-- src/main/java/dan200/computercraft/shared/wired/WiredNode.java | 3 +-- .../java/dan200/computercraft/core/ComputerTestDelegate.java | 3 +-- .../java/dan200/computercraft/core/apis/ObjectWrapper.java | 3 +-- .../core/apis/handles/BinaryReadableHandleTest.java | 3 +-- .../core/apis/handles/EncodedReadableHandleTest.java | 3 +-- .../dan200/computercraft/core/computer/BasicEnvironment.java | 3 +-- .../dan200/computercraft/core/computer/ComputerBootstrap.java | 3 +-- .../java/dan200/computercraft/core/computer/ComputerTest.java | 3 +-- .../dan200/computercraft/core/filesystem/FileSystemTest.java | 3 +-- .../dan200/computercraft/core/filesystem/JarMountTest.java | 3 +-- .../java/dan200/computercraft/core/filesystem/MemoryMount.java | 3 +-- .../java/dan200/computercraft/shared/wired/NetworkTest.java | 3 +-- 405 files changed, 405 insertions(+), 795 deletions(-) diff --git a/src/main/java/dan200/computercraft/CCTweaked.java b/src/main/java/dan200/computercraft/CCTweaked.java index 1ee227a4d..c4e4d91c9 100644 --- a/src/main/java/dan200/computercraft/CCTweaked.java +++ b/src/main/java/dan200/computercraft/CCTweaked.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft; import net.minecraftforge.fml.common.Mod; diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index c0240599a..626d387f0 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java index 3cbbfb339..af0ab2d3a 100644 --- a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api; diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 165301587..3ba615080 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index eef6cf4f3..703a95911 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java index cc2aac128..7ef4a1c12 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import java.io.IOException; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index d2e5e030e..41fb51b78 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index 38ae27da0..a778f423d 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.filesystem; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/filesystem/package-info.java b/src/main/java/dan200/computercraft/api/filesystem/package-info.java index 8b1cf52cb..fc6490a20 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/package-info.java +++ b/src/main/java/dan200/computercraft/api/filesystem/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|FileSystem", apiVersion = "${version}" ) package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java b/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java index 7bc8c79e3..97500fa97 100644 --- a/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java +++ b/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.peripheral.IComputerAccess; diff --git a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java index 9c5c6837e..c0717bcb2 100644 --- a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java +++ b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.filesystem.IFileSystem; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java index 8e02b740d..a37f0404a 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java index 90a147832..763a8bdaf 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java index e1fc07b89..623f19a74 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaObject.java b/src/main/java/dan200/computercraft/api/lua/ILuaObject.java index 2f09434c8..4d0f37f89 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaObject.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaObject.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import dan200.computercraft.api.peripheral.IComputerAccess; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java index 76636f335..f99ce283b 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/api/lua/LuaException.java b/src/main/java/dan200/computercraft/api/lua/LuaException.java index 2f9d2687c..65d8d0284 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaException.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaException.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.lua; import javax.annotation.Nullable; diff --git a/src/main/java/dan200/computercraft/api/lua/package-info.java b/src/main/java/dan200/computercraft/api/lua/package-info.java index 2a9020719..85ea9f6b2 100644 --- a/src/main/java/dan200/computercraft/api/lua/package-info.java +++ b/src/main/java/dan200/computercraft/api/lua/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Lua", apiVersion = "${version}" ) package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index efc752d7f..b841a6500 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.media; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java index 13784cd20..a3605f024 100644 --- a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.media; import net.minecraft.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/api/media/package-info.java b/src/main/java/dan200/computercraft/api/media/package-info.java index 6381b11c9..47d2c93da 100644 --- a/src/main/java/dan200/computercraft/api/media/package-info.java +++ b/src/main/java/dan200/computercraft/api/media/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Media", apiVersion = "${version}" ) package dan200.computercraft.api.media; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java index d6b2f529c..b85ac6e38 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index 8be74f30e..49b37d889 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index c28f06dee..bb9dc63d1 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/Packet.java b/src/main/java/dan200/computercraft/api/network/Packet.java index df7408682..baaaeefa4 100644 --- a/src/main/java/dan200/computercraft/api/network/Packet.java +++ b/src/main/java/dan200/computercraft/api/network/Packet.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/package-info.java b/src/main/java/dan200/computercraft/api/network/package-info.java index 35b8cc5a9..799b5d69b 100644 --- a/src/main/java/dan200/computercraft/api/network/package-info.java +++ b/src/main/java/dan200/computercraft/api/network/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Network", apiVersion = "${version}" ) package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java index a7a76d7b0..b60f1800c 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java index bd1431a44..d2e046e77 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java index 9769bbf9b..df90f279f 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java index a67d06bba..061f950f7 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.network.IPacketNetwork; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java index ccc182b93..ee456f538 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.network.wired; import dan200.computercraft.api.network.IPacketSender; diff --git a/src/main/java/dan200/computercraft/api/network/wired/package-info.java b/src/main/java/dan200/computercraft/api/network/wired/package-info.java index c45eef432..571195a82 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/package-info.java +++ b/src/main/java/dan200/computercraft/api/network/wired/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Network|Wired", apiVersion = "${version}" ) package dan200.computercraft.api.network.wired; diff --git a/src/main/java/dan200/computercraft/api/package-info.java b/src/main/java/dan200/computercraft/api/package-info.java index e23d7219a..da427a2e1 100644 --- a/src/main/java/dan200/computercraft/api/package-info.java +++ b/src/main/java/dan200/computercraft/api/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API", apiVersion = "${version}" ) package dan200.computercraft.api; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 26f8cf154..263f4d86b 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 481499138..310ff24c5 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import dan200.computercraft.api.lua.ArgumentHelper; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index 0c39e83cf..ec317481a 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.peripheral; import net.minecraft.tileentity.TileEntity; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java index 55e5a5c3f..e3d9a2efb 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java index 68da2d1d9..a68fd58e0 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/package-info.java b/src/main/java/dan200/computercraft/api/peripheral/package-info.java index b2456ea1a..980026b62 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/package-info.java +++ b/src/main/java/dan200/computercraft/api/peripheral/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Peripheral", apiVersion = "${version}" ) package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java b/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java index 355f86720..e3a5d1adc 100644 --- a/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java +++ b/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.permissions; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/dan200/computercraft/api/permissions/package-info.java b/src/main/java/dan200/computercraft/api/permissions/package-info.java index 3516bad1b..0e551de92 100755 --- a/src/main/java/dan200/computercraft/api/permissions/package-info.java +++ b/src/main/java/dan200/computercraft/api/permissions/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Permissions", apiVersion = "${version}" ) package dan200.computercraft.api.permissions; diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index 7965a7c3e..5b369cb5d 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.pocket; diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index feebe9d0b..609f73a1d 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.pocket; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index 9c75b5517..638f95cc7 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.pocket; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index ee98f9958..d9199b246 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.redstone; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/api/redstone/package-info.java b/src/main/java/dan200/computercraft/api/redstone/package-info.java index 06526b70c..232545135 100644 --- a/src/main/java/dan200/computercraft/api/redstone/package-info.java +++ b/src/main/java/dan200/computercraft/api/redstone/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Redstone", apiVersion = "${version}" ) package dan200.computercraft.api.redstone; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index b693de3a7..3f3970b9a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import com.mojang.authlib.GameProfile; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java index 20dfd0808..88b4b7ab5 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 08d89f177..76a0671ac 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java index 58d36719f..96e25074e 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java index 795513cc9..3da0a7fc0 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java index 912fa6d30..d0a15fae1 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java index 447adf289..5ba83f754 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index 050775081..07c3bc2fe 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java index b7e87ad3a..f5e347d5a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; /** diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java index a26a12a0f..7fff81ac2 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java index de95a7d8f..8211fa74f 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index 1c464b83e..7c80e0426 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java index 8b67a4455..135c15505 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index 26abb36bb..12a1b751b 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java index 18441ec33..f01436f6b 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java index 2ab9e8b3e..476221171 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - package dan200.computercraft.api.turtle.event; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java index 773de6ff0..e9fc0c92e 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/package-info.java b/src/main/java/dan200/computercraft/api/turtle/event/package-info.java index 58ae3f05c..9019d8829 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/package-info.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Turtle|Event", apiVersion = "${version}" ) package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/package-info.java b/src/main/java/dan200/computercraft/api/turtle/package-info.java index b278aa1a3..ed132345f 100644 --- a/src/main/java/dan200/computercraft/api/turtle/package-info.java +++ b/src/main/java/dan200/computercraft/api/turtle/package-info.java @@ -1,9 +1,8 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ - @API( owner = "ComputerCraft", provides = "ComputerCraft|API|Turtle", apiVersion = "${version}" ) package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index da81a77bb..ce31867f5 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 6e2e159dd..86c3e0f19 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client; import dan200.computercraft.shared.command.text.ChatHelpers; diff --git a/src/main/java/dan200/computercraft/client/FrameInfo.java b/src/main/java/dan200/computercraft/client/FrameInfo.java index 3a9123ab1..e40bcbf1d 100644 --- a/src/main/java/dan200/computercraft/client/FrameInfo.java +++ b/src/main/java/dan200/computercraft/client/FrameInfo.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 97c83afc7..57760da3f 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.core.terminal.TextBuffer; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index d79459e76..f81177995 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java b/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java index 2eb6d4107..535af33c3 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiConfigCC.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index 5aa49544e..de7ae4278 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java index 8f11c287c..f1091f63e 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPocketComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index f4723ac0c..17a92ad48 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 5c2ec49ea..d9ece49a7 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.core.terminal.TextBuffer; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 79798ec89..9bf3b07e4 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java b/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java index f556a0043..d56c0a041 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/Widget.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui.widgets; import net.minecraft.client.Minecraft; diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index d0a72a42a..87d5e2f80 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui.widgets; import dan200.computercraft.client.FrameInfo; diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index b71d0e3c0..d4d24cd0a 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.proxy; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index 225e177bf..6c2b7e49b 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index 2a2a22e1e..55109f2a5 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import net.minecraft.client.Minecraft; diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 1abf89489..300c65b6a 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index 7e9432ed8..f2a31947d 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java index 01cfd8e22..3a93a23cb 100644 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import net.minecraft.client.renderer.block.model.BakedQuad; diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index fea1d335a..4b8b1964e 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index d49aeec0c..be07d5039 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.client.gui.FixedWidthFontRenderer; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java index e0222e821..209990335 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index f5b7a498d..96646ff4c 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.client.FrameInfo; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 32a24606b..28cc26fc2 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import dan200.computercraft.api.turtle.ITurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index cfd1e60ce..e29b82deb 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 183e47f4b..74a02957a 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import net.minecraft.block.state.IBlockState; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 9ef6144fc..15ff9e945 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java b/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java index 61068d5f3..3d40ea24c 100644 --- a/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java +++ b/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import com.google.common.net.InetAddresses; diff --git a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java index 6db2eecc8..1bf5e9ab6 100644 --- a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java +++ b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPIFactory; diff --git a/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java b/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java index 0123d9de4..f4f9d0033 100644 --- a/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java +++ b/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.LuaException; diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index 52341b92b..ad3c24da1 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 5fece4a7c..4b63ee3a1 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index f89853cc2..8c29d9237 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 92ef98d32..00b5ebf8d 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java b/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java index a4a34fa11..e623feb82 100644 --- a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; /** diff --git a/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java b/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java index 516f89f36..dc5c4fa1f 100644 --- a/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java +++ b/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.LuaException; diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 3f6e36ee5..e1bc5c1ab 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index c5470a475..3788c48ee 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 2da52759c..0f8f622d6 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/core/apis/TableHelper.java b/src/main/java/dan200/computercraft/core/apis/TableHelper.java index db546a089..4ceae1659 100644 --- a/src/main/java/dan200/computercraft/core/apis/TableHelper.java +++ b/src/main/java/dan200/computercraft/core/apis/TableHelper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ArgumentHelper; diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index ce57adc49..6bb290f67 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java b/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java index 9e7b9a6bf..adcc75ff6 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import java.nio.ByteBuffer; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index 2ad90ddb1..df0ff48d5 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import com.google.common.collect.ObjectArrays; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index 558fbfe2e..2ab94bd4b 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import com.google.common.collect.ObjectArrays; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index 7244c914b..af714dbdc 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java index 9d81c1b21..c9cfb5ba7 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index fd69ff5df..2ebad4202 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import dan200.computercraft.api.lua.ILuaObject; diff --git a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java index 0f4d3e9c0..ab4b56de2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java +++ b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http; import dan200.computercraft.core.apis.IAPIEnvironment; diff --git a/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java b/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java index 248cbc4c1..72655a05c 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java +++ b/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http; public class HTTPRequestException extends Exception diff --git a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java index 490c601cb..aedf7e419 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/apis/http/Resource.java b/src/main/java/dan200/computercraft/core/apis/http/Resource.java index 77a7485ec..6587fb19d 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/Resource.java +++ b/src/main/java/dan200/computercraft/core/apis/http/Resource.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http; import dan200.computercraft.shared.util.IoUtil; diff --git a/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java b/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java index 8686a3682..cfce1f3ce 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java +++ b/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http; import java.util.Collections; diff --git a/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java b/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java index c465d6316..4159097b0 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java +++ b/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http; import java.util.ArrayDeque; diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index 3f9c34ff7..2f03a1b7e 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.request; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index 114c24e80..866d0d138 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.request; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java index 49add574c..bfface4eb 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.request; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index 7698c3d18..67a15e963 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.websocket; import com.google.common.base.Strings; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index fd2d79527..976b526c2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.websocket; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java index 0569cfffa..70a2e77a6 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.websocket; import dan200.computercraft.core.apis.http.HTTPRequestException; diff --git a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java index 02812ce72..96be03c3e 100644 --- a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java +++ b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index 101707ca6..cacb755d1 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index aa621f803..0da3b2d65 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java index 1cbbfa294..7581a91fb 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java index 94eead340..c5cb4f529 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.api.filesystem.IFileSystem; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java index f1439e6f9..91ac8161e 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index b23ad377e..35a79ee4d 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java b/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java index 7c9797585..a4229bd05 100644 --- a/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java +++ b/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/core/computer/MainThread.java b/src/main/java/dan200/computercraft/core/computer/MainThread.java index 9bddaee4e..e2874dadc 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThread.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThread.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java index 955b48c65..baedd3b53 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/computer/TimeoutState.java b/src/main/java/dan200/computercraft/core/computer/TimeoutState.java index 5939ac2bd..6bfe804e4 100644 --- a/src/main/java/dan200/computercraft/core/computer/TimeoutState.java +++ b/src/main/java/dan200/computercraft/core/computer/TimeoutState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.core.lua.ILuaMachine; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java index ee4457032..94cd47b19 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import java.io.Closeable; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index 58bc62047..53e119954 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import dan200.computercraft.api.filesystem.FileOperationException; diff --git a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java index 5ad38de9b..15d6df7f1 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import dan200.computercraft.api.filesystem.FileOperationException; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index 58c66228f..eb0f39ff8 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import com.google.common.collect.Sets; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index c02d6def3..4f6f84cd3 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import com.google.common.io.ByteStreams; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java index d4702e278..2ff07ae5d 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; public class FileSystemException extends Exception diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java index a51377f7e..28841f295 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java index 01b110dc3..3b270fe1b 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import dan200.computercraft.api.filesystem.IFileSystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 24e350330..336d4ddcc 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import com.google.common.cache.Cache; diff --git a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java index 5b4c9c482..1cdac4a6a 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 64a34df5c..577486d36 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.lua; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java index 700eb34aa..4ca5d4b07 100644 --- a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.lua; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/core/lua/MachineResult.java b/src/main/java/dan200/computercraft/core/lua/MachineResult.java index 0b3cf8c0a..adff1058f 100644 --- a/src/main/java/dan200/computercraft/core/lua/MachineResult.java +++ b/src/main/java/dan200/computercraft/core/lua/MachineResult.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.lua; import dan200.computercraft.core.computer.TimeoutState; diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 4bd0921de..e053e41b4 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.terminal; import dan200.computercraft.shared.util.Palette; diff --git a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java index fa24e9d51..6a8e55355 100644 --- a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java +++ b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.terminal; public class TextBuffer diff --git a/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java b/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java index 9ee52cb38..3cc9886c9 100644 --- a/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java +++ b/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.tracking; import dan200.computercraft.core.computer.Computer; diff --git a/src/main/java/dan200/computercraft/core/tracking/Tracker.java b/src/main/java/dan200/computercraft/core/tracking/Tracker.java index f0eb0144b..c64731f76 100644 --- a/src/main/java/dan200/computercraft/core/tracking/Tracker.java +++ b/src/main/java/dan200/computercraft/core/tracking/Tracker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.tracking; import dan200.computercraft.core.computer.Computer; diff --git a/src/main/java/dan200/computercraft/core/tracking/Tracking.java b/src/main/java/dan200/computercraft/core/tracking/Tracking.java index 6df9de33e..587b242cc 100644 --- a/src/main/java/dan200/computercraft/core/tracking/Tracking.java +++ b/src/main/java/dan200/computercraft/core/tracking/Tracking.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.tracking; import dan200.computercraft.core.computer.Computer; diff --git a/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java b/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java index d9d6d2c05..d1205c2e2 100644 --- a/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java +++ b/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.tracking; import com.google.common.collect.MapMaker; diff --git a/src/main/java/dan200/computercraft/core/tracking/TrackingField.java b/src/main/java/dan200/computercraft/core/tracking/TrackingField.java index 9618dd171..da9a5e1a6 100644 --- a/src/main/java/dan200/computercraft/core/tracking/TrackingField.java +++ b/src/main/java/dan200/computercraft/core/tracking/TrackingField.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.tracking; import dan200.computercraft.shared.util.StringUtil; diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index ea390a6f6..aa6413b0e 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 3bb116666..a58cd1962 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import com.google.common.base.CaseFormat; diff --git a/src/main/java/dan200/computercraft/shared/MediaProviders.java b/src/main/java/dan200/computercraft/shared/MediaProviders.java index 42c272975..fd4cd6b8b 100644 --- a/src/main/java/dan200/computercraft/shared/MediaProviders.java +++ b/src/main/java/dan200/computercraft/shared/MediaProviders.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 4e499b8c1..50e1c49fa 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index fbd9eeb22..5068ceab6 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index d9d78db4f..845e2c660 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index ec9cf4f0e..d83fecfc1 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index ad62ff310..c05996e30 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 7a6be3151..610da2440 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command; import com.google.common.collect.Sets; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java index 5e598d8d3..4837b152a 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command; import net.minecraft.client.gui.GuiScreen; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index 73061cb97..d9d7b2eb3 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command; import net.minecraft.command.ICommandSender; diff --git a/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java b/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java index 444fa6596..5eafc09a7 100644 --- a/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java +++ b/src/main/java/dan200/computercraft/shared/command/ComputerSelector.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command; import com.google.common.collect.Lists; diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java index 52eddde4b..6ca10907e 100644 --- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java +++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command; import dan200.computercraft.shared.command.framework.CommandContext; diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java index c6c6e4d4a..5d7b95342 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/CommandContext.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.framework; import com.google.common.collect.Lists; diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java index ef26a5e2f..74c6d2882 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/CommandDelegate.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.framework; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java b/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java index e4dfe3624..0b37fa263 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/CommandRoot.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.framework; import com.google.common.collect.Lists; diff --git a/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java b/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java index 051fe3e75..e7bd6d8ce 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/ISubCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.framework; import net.minecraft.command.CommandException; diff --git a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java b/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java index b741ee0e4..3be781dd3 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/SubCommandBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.framework; import dan200.computercraft.shared.command.UserLevel; diff --git a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java b/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java index 532849754..61c9b4dbc 100644 --- a/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java +++ b/src/main/java/dan200/computercraft/shared/command/framework/SubCommandHelp.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.framework; import com.google.common.collect.Lists; diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index 9e942d2fd..58f65e18d 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.text; import dan200.computercraft.shared.command.framework.CommandContext; diff --git a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java index 53c79e888..77068c07d 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.text; import net.minecraft.command.ICommandSender; diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java index 155306f32..c48ddffd1 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.text; import dan200.computercraft.shared.command.CommandUtils; diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index 2b6b361d4..97448af4e 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.text; import net.minecraft.util.text.ITextComponent; diff --git a/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java b/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java index beecc70b4..8b8c4f7e7 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockDirectional.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.block.material.Material; diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index fa039875e..2147f421b 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.block.Block; diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 56f86c18b..f823724d0 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index c975b259a..79e4836fe 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java index 8d5667173..946db3834 100644 --- a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import dan200.computercraft.api.redstone.IBundledRedstoneProvider; diff --git a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java index e0988ad12..b3720f46b 100644 --- a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java +++ b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java b/src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java index 781784eea..0e166f885 100644 --- a/src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java +++ b/src/main/java/dan200/computercraft/shared/common/IDirectionalTile.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/shared/common/ITerminal.java b/src/main/java/dan200/computercraft/shared/common/ITerminal.java index 1d46fa271..2e91b85b4 100644 --- a/src/main/java/dan200/computercraft/shared/common/ITerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ITerminal.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index b007ef86c..7c72b11c5 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 0634f0497..5ca31e4c6 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.block.Block; diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 1be33cf02..b8a3ecd64 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.apis; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java index 1067ec711..954d4df29 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockCommandComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index 9306cee1c..d987b0e2e 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index f0aee2848..c54387691 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.common.BlockDirectional; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java index 0149ba0b3..a536a9e29 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java index 7990f24ca..810d72c57 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.IComputer; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java index f719b0919..b0fea8a42 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import net.minecraft.util.IStringSerializable; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java index 8c341df33..ce5fa71ed 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index b538d5971..a822dad84 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.apis.CommandAPI; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 7769f174d..3ae1c4725 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 6e709d3eb..03d8f59c3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index b3f2fdfc7..24611e7e8 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java index 8d6b510ba..89a3aafda 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; public class ClientComputerRegistry extends ComputerRegistry diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java index c8ed459af..85aac4244 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; public enum ComputerFamily diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java index 9c795878c..10ad45731 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import java.util.Collection; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java index 3d8a21b01..9fd848f77 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import dan200.computercraft.shared.common.ITerminal; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java b/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java index 7654eaa25..8639fef10 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IComputerContainer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; @FunctionalInterface diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java index 85acfbae0..123d3d004 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java index c2b800eab..efc401070 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; /** diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputState.java b/src/main/java/dan200/computercraft/shared/computer/core/InputState.java index 4ee3420ec..832bc91f2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/InputState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import it.unimi.dsi.fastutil.ints.IntIterator; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index e75b55fa3..f5938d62c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java index 591597d9d..ab605420c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.core; import java.util.Iterator; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java index deb1f596f..a5c8bfc32 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.shared.computer.blocks.TileComputer; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 60d995e5d..18f5d37bb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index 847355e60..e742ec317 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java index 8c85b704c..0dc072847 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.items; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java index 2ebe4f9e5..09dd473bb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemCommandComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java index e20a660a2..bacdfdea3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 7171e741e..e00ec444a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index dee45d203..43bfd5660 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.items.IComputerItem; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index 0b3cd7475..9a7cf9235 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.recipe; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java index 4ce036e1b..9bf0309b7 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerIngredient.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.recipe; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/datafix/Fixes.java b/src/main/java/dan200/computercraft/shared/datafix/Fixes.java index 9b1d284da..138badb55 100644 --- a/src/main/java/dan200/computercraft/shared/datafix/Fixes.java +++ b/src/main/java/dan200/computercraft/shared/datafix/Fixes.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.datafix; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java b/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java index 9e343f070..c67eb1937 100644 --- a/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java +++ b/src/main/java/dan200/computercraft/shared/datafix/TileEntityDataFixer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.datafix; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java index fe478f7c2..7d9a58bf2 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/BundledCapabilityProvider.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.charset; diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java index e7ac4768a..4d9329360 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/BundledRedstoneProvider.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.charset; diff --git a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java index 32055fc92..5e69b4e36 100644 --- a/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java +++ b/src/main/java/dan200/computercraft/shared/integration/charset/IntegrationCharset.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.charset; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java index 8f1439233..c8340f094 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.crafttweaker; import crafttweaker.CraftTweakerAPI; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java index 3b34cf5d7..4d9255d4d 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.crafttweaker.actions; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java index d726c7090..d94f9e061 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/IAction.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.crafttweaker.actions; import java.util.Optional; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java index 939e72592..1cd486269 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.crafttweaker.actions; import dan200.computercraft.api.turtle.ITurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java index ce41a17d9..325513302 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.crafttweaker.actions; import dan200.computercraft.api.turtle.ITurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 43f002368..3adc0cbb8 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.jei; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java index 59ecf9c64..c6899c097 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.jei; import dan200.computercraft.api.pocket.IPocketUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java index 35c0b47fe..170ed5125 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPHooks.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.mcmp; import mcmultipart.MCMultiPart; diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java index 358fcda92..fb4e40244 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/MCMPIntegration.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.mcmp; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java index 603ab9575..8996b92c3 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartAdvancedModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.mcmp; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java index daf25450b..21d694524 100644 --- a/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/integration/mcmp/PartPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.mcmp; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java index cc059646b..26c3464e7 100644 --- a/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/media/inventory/ContainerHeldItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.inventory; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java index fbca52659..1d6687d56 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskExpanded.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java index 97b8d1355..73f574dfd 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index 6f9629d82..0e3d5332d 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index d475ec54e..bf0791872 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 39b0980c5..f825dc0d0 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.items; import dan200.computercraft.api.media.IMedia; diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index c7775080e..84cf071dc 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.recipes; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index c0cdfb587..f0bb79376 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.recipes; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/network/Containers.java b/src/main/java/dan200/computercraft/shared/network/Containers.java index 579f3d7bf..010e5840a 100644 --- a/src/main/java/dan200/computercraft/shared/network/Containers.java +++ b/src/main/java/dan200/computercraft/shared/network/Containers.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index d644e6ffe..b83aa81ca 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java index d8680ec2d..bff94e7b6 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network; import io.netty.buffer.ByteBuf; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index 9fb3f35a4..55bf17a1d 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.client.ClientTableFormatter; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java index ac97c51f1..684f9a8f2 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java index 1a0999f0b..b2d36e355 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.computer.blocks.ComputerState; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java index daa9d4398..f1219eac7 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index 5c7adf562..7c82c4dec 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.util.NBTUtil; diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 4458b5e7e..93ba4cc5c 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.network.NetworkMessage; diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java index f761bc044..9ec56f044 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.core.IContainerComputer; diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index 2d4c6e07b..b5aae0381 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.server; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java index 7472c4f32..8b56efeda 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.core.IContainerComputer; diff --git a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java index 385a80116..9ecc612a5 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.core.IContainerComputer; diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index c1467f3f9..fbf6d0124 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.server; import dan200.computercraft.shared.computer.core.IContainerComputer; diff --git a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java index 77b4aecb2..46fb9d328 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.server; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java b/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java index 5fc318e28..014c8d46e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/PeripheralType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral; import net.minecraft.util.IStringSerializable; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index b4638041c..f5f46b52d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.commandblock; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java index b7d5c46f1..18b64907f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java index a14c39bb4..e419ef029 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/BlockPeripheralVariant.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.shared.peripheral.PeripheralType; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java b/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java index 9e53c865a..225576cff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.shared.peripheral.PeripheralType; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java b/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java index 119dd171a..efa07722d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/IPeripheralTile.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; @Deprecated diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java index e256eb06c..84d12e484 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/ITilePeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.shared.peripheral.PeripheralType; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java index 753c09ca3..59a803399 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java index 35b0fe8b0..f3e5e6e4b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/ItemPeripheralBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.shared.peripheral.PeripheralType; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java b/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java index aff6de8a4..75ef98b45 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/PeripheralItemFactory.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java b/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java index 35a6e1b2b..8b50fae8b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/common/TilePeripheralBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.common; import dan200.computercraft.api.peripheral.IPeripheralTile; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index 06930188a..1d08012b3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.diskdrive; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 8dc7b9008..fcb4b7b70 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 8d46edd44..ea8cad7e2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.api.filesystem.IMount; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java index 4770d2f69..61045dbd6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemBounds.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; import net.minecraft.block.Block; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 3222367d6..084e318a6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java index ba4cfd790..d206c1d4b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; import dan200.computercraft.api.lua.LuaException; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java index a7718656c..4f246f976 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/WirelessModemPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 8c4ad3fd4..459fb6cc9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java index 711492f4c..08cebeeda 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCableModemVariant.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index 157094455..f52f5a3c5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java index 4af2cff12..6a6baae46 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableBounds.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java index bb928190a..85c438605 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemCable.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java index e437f2dbb..6662bc170 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemWiredModemFull.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.shared.peripheral.PeripheralType; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 0cd0d4da4..18a835f09 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 02f63caff..d8eb036b5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java index 545c7bda2..510e5e342 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.api.network.wired.IWiredElement; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index 83aa8590f..9518cf411 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index daf3820df..5030b9c21 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java index 1300869a4..8c75dbbf4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockAdvancedModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java index 5e494257e..9756f828d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/ItemAdvancedModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java index 374f939b9..16ee63250 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileAdvancedModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import net.minecraft.util.EnumFacing; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index f3595013c..142930e37 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.shared.common.IDirectionalTile; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java index 108401705..7d79afc63 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModemBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index 2ff323829..a6db98161 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java index 1f6ee792c..2300d4e3c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.api.network.IPacketNetwork; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 0d64cbf58..c3ccc3dae 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.shared.common.ClientTerminal; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java index 13bce9955..17246c424 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java index a6ace0f71..11e404dcf 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 66307dd98..46e6999a2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.api.peripheral.IComputerAccess; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java index 30096d5ad..641467f74 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; public class XYPair diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index a1a7af401..d578afd91 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.printer; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index 7dfeeb96d..b699b8eb5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 6542e3adb..a7b469eb2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 6ecee51d2..23deb5f5e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index caaeeccbe..ec78a945c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index f5ef6f79e..66d35fe48 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.apis; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index b6e727381..19ebafb50 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.core; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java index fa79ec289..84615fef9 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.inventory; import dan200.computercraft.shared.computer.core.IComputer; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 38c92fd82..6cfe430f5 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.items; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index edc432189..be87fcf3c 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index d8c10327f..7cbea33b5 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index f34f31bc8..12e98c000 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.peripherals; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index e025d6d02..da01800ca 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java index 7202cd862..66182ff4d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index 78186299c..1ef96bd5d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.pocket.recipes; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 92703eb2c..3a83fa239 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.proxy; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index feccb9543..c9859b757 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 7dc83ce55..08e22d805 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.apis; import dan200.computercraft.api.lua.ILuaAPI; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 0e5871515..4142d018d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.blocks; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java index 4eba4378e..b7a4836f9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.blocks; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index e4b23311c..3b9e0e178 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.blocks; import com.mojang.authlib.GameProfile; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java index 02db45df9..ac2036862 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleAdvanced.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java index beb8ebe7d..c9e61c76d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtleExpanded.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java index 1e8a5175f..0ca5a45f8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java index 26c6d9681..d2d333212 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java index caa1ad4ed..5e4085443 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; public enum TurnDirection diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index bf68e2b3f..35f8c2aad 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import com.google.common.base.Objects; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java index d3f20ac59..64a2aa655 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleCommand; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index b71c8e901..7f0c4fbb3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java index d00b0b24e..d1f87c912 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java index ad1f08ac9..98191656b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index ab89ae6b0..5a7491144 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index 21de8bab1..7789d6ae8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index 795e3bd98..0df332ff7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.*; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index 1778af0a7..a72d8c280 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 839fe0ae6..1bd9ee7ff 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 34ad51413..18b37d97b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 50284741e..b3132cba9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import com.mojang.authlib.GameProfile; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index 8e4ebce11..4669f89a1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index 4eab4550b..c8dcdbc9e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java index 592233b06..5f8f9f13e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.*; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index 574a0e05b..803365202 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java index f129efc4b..95cb681c2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 26a00a3a0..13b3b19c0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.inventory; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java index 3fa25bda9..a6cc3de5a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.api.turtle.ITurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java index ba4a61f38..789cc8aaa 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleAdvanced.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java index 3fdf3a01a..8d29f6d94 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java index 2d5b36ab0..b0bcfd577 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java index 4d21726cd..464f2bf10 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleNormal.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index b335d2b62..28811f00c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java index 6757d6239..ca3059bbf 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.recipes; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index 11c394855..4230a2b5a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.recipes; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index bb3049588..f33762694 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java index 02342eb8a..65f20e5af 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import net.minecraft.item.Item; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 6dd6f3aaf..5c1570516 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.AbstractTurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index e29a17d46..a14c56e71 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 40fc88fb2..715c6816e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 039b632eb..a3f95b524 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.AbstractTurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index face19e6d..bca0d6c5e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.turtle.ITurtleAccess; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 712bfb531..618af0d11 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -1,10 +1,9 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.AbstractTurtleUpgrade; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 853def832..4f744e2ff 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.shared.turtle.core.TurtlePlayer; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index cf6b09ac7..c32a15d8a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/util/Colour.java b/src/main/java/dan200/computercraft/shared/util/Colour.java index ac383a58f..010d1152b 100644 --- a/src/main/java/dan200/computercraft/shared/util/Colour.java +++ b/src/main/java/dan200/computercraft/shared/util/Colour.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; public enum Colour diff --git a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java index 41152fb4c..6611108f9 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; /** diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index d4dccc176..9c8908f33 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java index 10023b740..4167de5e0 100644 --- a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java +++ b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index 7c4aeb6e3..7ef5da375 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index b1ca2333c..6fd46f380 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.inventory.ISidedInventory; diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java index 582507730..ecd4e15f0 100644 --- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.core.computer.ComputerSide; diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index ec11947aa..47a6915e9 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index a99e53e09..3386e635c 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import io.netty.channel.Channel; diff --git a/src/main/java/dan200/computercraft/shared/util/Holiday.java b/src/main/java/dan200/computercraft/shared/util/Holiday.java index a59674a01..d50d8422b 100644 --- a/src/main/java/dan200/computercraft/shared/util/Holiday.java +++ b/src/main/java/dan200/computercraft/shared/util/Holiday.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; public enum Holiday diff --git a/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java b/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java index 4212a8af0..7abc26976 100644 --- a/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import java.util.Calendar; diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index d989b4f84..fd0f222ab 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index 5227cd2d2..e4d0a8a65 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index 12c56caf0..8401de2e4 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java index 7f94d0460..96ca6325f 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.entity.player.EntityPlayer; diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index ae0434c9f..d5c180519 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.entity.Entity; diff --git a/src/main/java/dan200/computercraft/shared/util/IoUtil.java b/src/main/java/dan200/computercraft/shared/util/IoUtil.java index a4fc13638..a2afde286 100644 --- a/src/main/java/dan200/computercraft/shared/util/IoUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/IoUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import java.io.Closeable; diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index f83dbf1e9..c783ce475 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.nbt.*; diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index 8d4a0649c..18c8040c2 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.nbt.NBTTagCompound; diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index d2fd270c3..650773140 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import com.google.common.collect.Maps; diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index 0977775dc..d5382f595 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.shared.network.NetworkHandler; diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java index 7f30c8db1..2767cef85 100644 --- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.shared.BundledRedstone; diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index f91c8f96d..7b764fa67 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.util.text.TextComponentTranslation; diff --git a/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java b/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java index 0751dbe1b..f03bb4d8e 100644 --- a/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import com.google.common.util.concurrent.ThreadFactoryBuilder; diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 62ac366cc..34368e61c 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import com.google.common.collect.MapMaker; diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index eaed69114..42a662e37 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.inventory.IInventory; diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index d6a76dbfa..f4c8a437d 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import com.google.common.base.Predicate; diff --git a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java index 12b626aaa..ccacab2b9 100644 --- a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java +++ b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import dan200.computercraft.api.network.wired.IWiredElement; diff --git a/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java b/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java index 128a5ca25..40084252f 100644 --- a/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java +++ b/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index 8653f0ccd..c66c7e19b 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java index ed287222f..144fe6a76 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import dan200.computercraft.api.network.wired.IWiredNetworkChange; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java index 6169c2058..4ccd80ebc 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import dan200.computercraft.api.network.IPacketReceiver; diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index db75d0472..c5d9e02ef 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core; import dan200.computercraft.ComputerCraft; diff --git a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java index 878bb7a71..cd7684270 100644 --- a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java +++ b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaContext; diff --git a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java index 37f3f4905..3def2ce9f 100644 --- a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import dan200.computercraft.api.lua.LuaException; diff --git a/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java index 78d8e1d06..5c3e57da0 100644 --- a/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.handles; import dan200.computercraft.api.lua.LuaException; diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index a66ba69d0..cc6cebd3f 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 8425657bc..f44567b80 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java index da04d058b..d2d6d744c 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.computer; import org.junit.jupiter.api.Assertions; diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java index 3711afa16..eca098f6e 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import com.google.common.io.Files; diff --git a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java index 4a13b825f..31031c96c 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import com.google.common.io.ByteStreams; diff --git a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java index b68ba4340..dcdc40b5e 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java +++ b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import dan200.computercraft.api.filesystem.IWritableMount; diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 614b3b6b7..69736fea8 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import com.google.common.collect.Maps; From a48c3d0ba8a86ea62308c7c556582c380b0f1228 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 1 Jan 2020 09:01:00 +0000 Subject: [PATCH 125/711] A couple of io fixes - Use expect within io.write before calling the handle's write function. Closes #338 - Coerce to string in write before doing any writing. Fixes #339 --- .../resources/assets/computercraft/lua/bios.lua | 1 + .../assets/computercraft/lua/rom/apis/io.lua | 6 +++++- src/test/resources/test-rom/spec/base_spec.lua | 12 ++++++++++++ .../resources/test-rom/spec/test_helpers.lua | 16 ++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 0cceccf99..2913da090 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -207,6 +207,7 @@ function write( sText ) end -- Print the line with proper word wrapping + sText = tostring(sText) while #sText > 0 do local whitespace = string.match( sText, "^[ \t]+" ) if whitespace then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index 779d7e26d..0011ab73c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -122,7 +122,11 @@ handleMetatable = { if not handle.write then return nil, "file is not writable" end local n = select("#", ...) - for i = 1, n do handle.write(select(i, ...)) end + for i = 1, n do + local arg = select(i, ...) + expect(1, arg, "string", "number") + handle.write(arg) + end return self end, }, diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua index 8ce2213bf..2e557e132 100644 --- a/src/test/resources/test-rom/spec/base_spec.lua +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -1,3 +1,5 @@ +local with_window = require "test_helpers".with_window + describe("The Lua base library", function() describe("sleep", function() it("validates arguments", function() @@ -13,6 +15,16 @@ describe("The Lua base library", function() write("") expect.error(write, nil):eq("bad argument #1 (expected string or number, got nil)") end) + + it("writes numbers", function() + local w = with_window(5, 5, function() write(123) end) + expect(w.getLine(1)):eq("123 ") + end) + + it("writes strings", function() + local w = with_window(5, 5, function() write("abc") end) + expect(w.getLine(1)):eq("abc ") + end) end) describe("loadfile", function() diff --git a/src/test/resources/test-rom/spec/test_helpers.lua b/src/test/resources/test-rom/spec/test_helpers.lua index 74b94b7e2..5d1ba9f1c 100644 --- a/src/test/resources/test-rom/spec/test_helpers.lua +++ b/src/test/resources/test-rom/spec/test_helpers.lua @@ -41,6 +41,22 @@ local function capture_program(stub, program, ...) } end +--- Run a function redirecting to a new window with the given dimensions +-- +-- @tparam number width The window's width +-- @tparam number height The window's height +-- @tparam function() fn The action to run +-- @treturn window.Window The window, whose content can be queried. +local function with_window(width, height, fn) + local current = term.current() + local redirect = window.create(current, 1, 1, width, height, false) + term.redirect(redirect) + fn() + term.redirect(current) + return redirect +end + return { capture_program = capture_program, + with_window = with_window, } From c1c01bef7cb13d4382b928380df31205c6b86bb0 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 1 Jan 2020 09:55:44 +0000 Subject: [PATCH 126/711] Fix argument index in expect call --- src/main/resources/assets/computercraft/lua/rom/apis/io.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index 0011ab73c..3cf28c80b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -121,10 +121,9 @@ handleMetatable = { local handle = self._handle if not handle.write then return nil, "file is not writable" end - local n = select("#", ...) - for i = 1, n do + for i = 1, select("#", ...) do local arg = select(i, ...) - expect(1, arg, "string", "number") + expect(i, arg, "string", "number") handle.write(arg) end return self From 35c1b1022477bf4afc4748d3680c6f878eb952e2 Mon Sep 17 00:00:00 2001 From: Oliver Marks Date: Wed, 8 Jan 2020 17:07:01 +0000 Subject: [PATCH 127/711] Anonymized GPS (#341) GPS requests are now sent and received on CHANNEL_GPS by default instead. This means it should not be possible to distinguish computers (and thus locate them) via their GPS requests. --- .../assets/computercraft/lua/rom/apis/gps.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index 5b556eb09..79b192494 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -84,16 +84,16 @@ function locate( _nTimeout, _bDebug ) print( "Finding position..." ) end - -- Open a channel + -- Open GPS channel to listen for ping responses local modem = peripheral.wrap( sModemSide ) local bCloseChannel = false - if not modem.isOpen( os.getComputerID() ) then - modem.open( os.getComputerID() ) + if not modem.isOpen( CHANNEL_GPS ) then + modem.open( CHANNEL_GPS ) bCloseChannel = true end -- Send a ping to listening GPS hosts - modem.transmit( CHANNEL_GPS, os.getComputerID(), "PING" ) + modem.transmit( CHANNEL_GPS, CHANNEL_GPS, "PING" ) -- Wait for the responses local tFixes = {} @@ -104,7 +104,7 @@ function locate( _nTimeout, _bDebug ) if e == "modem_message" then -- We received a reply from a modem local sSide, sChannel, sReplyChannel, tMessage, nDistance = p1, p2, p3, p4, p5 - if sSide == sModemSide and sChannel == os.getComputerID() and sReplyChannel == CHANNEL_GPS and nDistance then + if sSide == sModemSide and sChannel == CHANNEL_GPS and sReplyChannel == CHANNEL_GPS and nDistance then -- Received the correct message from the correct modem: use it to determine position if type(tMessage) == "table" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance } @@ -141,7 +141,7 @@ function locate( _nTimeout, _bDebug ) -- Close the channel, if we opened one if bCloseChannel then - modem.close( os.getComputerID() ) + modem.close( CHANNEL_GPS ) end -- Return the response From 4c8fd4fc358d034b8346d0a5325039076c1d641b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Jan 2020 13:20:15 +0000 Subject: [PATCH 128/711] Allow returning collections and arrays from Java Closes #344 --- .../dan200/computercraft/core/apis/FSAPI.java | 18 +--- .../core/apis/PeripheralAPI.java | 11 +-- .../computercraft/core/apis/RedstoneAPI.java | 14 +-- .../core/lua/CobaltLuaMachine.java | 95 +++++++++---------- .../shared/computer/apis/CommandAPI.java | 25 +++-- .../turtle/core/TurtlePlaceCommand.java | 5 +- 6 files changed, 67 insertions(+), 101 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 4b63ee3a1..c99273763 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -22,8 +22,6 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; -import java.util.HashMap; -import java.util.Map; import java.util.function.Function; import static dan200.computercraft.api.lua.ArgumentHelper.getString; @@ -93,13 +91,7 @@ public class FSAPI implements ILuaAPI m_env.addTrackingChange( TrackingField.FS_OPS ); try { - String[] results = m_fileSystem.list( path ); - Map table = new HashMap<>(); - for( int i = 0; i < results.length; i++ ) - { - table.put( i + 1, results[i] ); - } - return new Object[] { table }; + return new Object[] { m_fileSystem.list( path ) }; } catch( FileSystemException e ) { @@ -330,13 +322,7 @@ public class FSAPI implements ILuaAPI try { m_env.addTrackingChange( TrackingField.FS_OPS ); - String[] results = m_fileSystem.find( path ); - Map table = new HashMap<>(); - for( int i = 0; i < results.length; i++ ) - { - table.put( i + 1, results[i] ); - } - return new Object[] { table }; + return new Object[] { m_fileSystem.find( path ) }; } catch( FileSystemException e ) { diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 3788c48ee..c957af8b2 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -377,16 +377,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange } } } - if( methods != null ) - { - Map table = new HashMap<>(); - for( int i = 0; i < methods.length; i++ ) - { - table.put( i + 1, methods[i] ); - } - return new Object[] { table }; - } - return null; + return methods != null ? new Object[] { new HashMap<>() } : null; } case 3: { diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 0f8f622d6..1a987d519 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -11,8 +11,6 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.core.computer.ComputerSide; import javax.annotation.Nonnull; -import java.util.HashMap; -import java.util.Map; import static dan200.computercraft.api.lua.ArgumentHelper.*; @@ -58,16 +56,8 @@ public class RedstoneAPI implements ILuaAPI { switch( method ) { - case 0: - { - // getSides - Map table = new HashMap<>(); - for( int i = 0; i < ComputerSide.NAMES.length; i++ ) - { - table.put( i + 1, ComputerSide.NAMES[i] ); - } - return new Object[] { table }; - } + case 0: // getSides + return new Object[] { ComputerSide.NAMES }; case 1: { // setOutput diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 577486d36..08c3231f0 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -25,11 +25,9 @@ import org.squiddev.cobalt.lib.*; import org.squiddev.cobalt.lib.platform.VoidResourceManipulator; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.InputStream; -import java.util.Arrays; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; +import java.util.*; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -263,80 +261,79 @@ public class CobaltLuaMachine implements ILuaMachine return table; } - private LuaValue toValue( Object object, Map values ) + @Nonnull + private LuaValue toValue( @Nullable Object object, @Nonnull Map values ) { - if( object == null ) - { - return Constants.NIL; - } - else if( object instanceof Number ) - { - double d = ((Number) object).doubleValue(); - return valueOf( d ); - } - else if( object instanceof Boolean ) - { - return valueOf( (Boolean) object ); - } - else if( object instanceof String ) - { - String s = object.toString(); - return valueOf( s ); - } - else if( object instanceof byte[] ) + if( object == null ) return Constants.NIL; + if( object instanceof Number ) return valueOf( ((Number) object).doubleValue() ); + if( object instanceof Boolean ) return valueOf( (Boolean) object ); + if( object instanceof String ) return valueOf( object.toString() ); + if( object instanceof byte[] ) { byte[] b = (byte[]) object; return valueOf( Arrays.copyOf( b, b.length ) ); } - else if( object instanceof Map ) + + LuaValue result = values.get( object ); + if( result != null ) return result; + + if( object instanceof ILuaObject ) + { + LuaValue wrapped = wrapLuaObject( (ILuaObject) object ); + values.put( object, wrapped ); + return wrapped; + } + + if( object instanceof Map ) { - // Table: - // Start remembering stuff - if( values == null ) - { - values = new IdentityHashMap<>(); - } - else if( values.containsKey( object ) ) - { - return values.get( object ); - } LuaTable table = new LuaTable(); values.put( object, table ); - // Convert all keys for( Map.Entry pair : ((Map) object).entrySet() ) { LuaValue key = toValue( pair.getKey(), values ); LuaValue value = toValue( pair.getValue(), values ); - if( !key.isNil() && !value.isNil() ) - { - table.rawset( key, value ); - } + if( !key.isNil() && !value.isNil() ) table.rawset( key, value ); } return table; } - else if( object instanceof ILuaObject ) + + if( object instanceof Collection ) { - return wrapLuaObject( (ILuaObject) object ); + Collection objects = (Collection) object; + LuaTable table = new LuaTable( objects.size(), 0 ); + values.put( object, table ); + int i = 0; + for( Object child : objects ) table.rawset( ++i, toValue( child, values ) ); + return table; } - else + + if( object instanceof Object[] ) { - return Constants.NIL; + Object[] objects = (Object[]) object; + LuaTable table = new LuaTable( objects.length, 0 ); + values.put( object, table ); + for( int i = 0; i < objects.length; i++ ) table.rawset( i + 1, toValue( objects[i], values ) ); + return table; } + + if( ComputerCraft.logPeripheralErrors ) + { + ComputerCraft.log.warn( "Received unknown type '{}', returning nil.", object.getClass().getName() ); + } + return Constants.NIL; } private Varargs toValues( Object[] objects ) { - if( objects == null || objects.length == 0 ) - { - return Constants.NONE; - } + if( objects == null || objects.length == 0 ) return Constants.NONE; + Map result = new IdentityHashMap<>( 0 ); LuaValue[] values = new LuaValue[objects.length]; for( int i = 0; i < values.length; i++ ) { Object object = objects[i]; - values[i] = toValue( object, null ); + values[i] = toValue( object, result ); } return varargsOf( values ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index b8a3ecd64..8706cc077 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -25,8 +25,9 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import javax.annotation.Nonnull; -import java.util.Collections; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import static dan200.computercraft.api.lua.ArgumentHelper.getInt; @@ -63,9 +64,9 @@ public class CommandAPI implements ILuaAPI }; } - private static Map createOutput( String output ) + private static Object createOutput( String output ) { - return Collections.singletonMap( 1, output ); + return new Object[] { output }; } private Object[] doCommand( String command ) @@ -141,8 +142,7 @@ public class CommandAPI implements ILuaAPI case 2: // list return context.executeMainThreadTask( () -> { - int i = 1; - Map result = new HashMap<>(); + List result = new ArrayList<>(); MinecraftServer server = m_computer.getWorld().getMinecraftServer(); if( server != null ) { @@ -157,7 +157,7 @@ public class CommandAPI implements ILuaAPI { if( command.checkPermission( server, commandSender ) ) { - result.put( i++, name ); + result.add( name ); } } catch( Throwable t ) @@ -205,12 +205,11 @@ public class CommandAPI implements ILuaAPI { throw new LuaException( "Co-ordinates out of range" ); } - if( (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1) > 4096 ) - { - throw new LuaException( "Too many blocks" ); - } - int i = 1; - Map results = new HashMap<>(); + + int blocks = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1); + if( blocks > 4096 ) throw new LuaException( "Too many blocks" ); + + List results = new ArrayList<>( blocks ); for( int y = min.getY(); y <= max.getY(); y++ ) { for( int z = min.getZ(); z <= max.getZ(); z++ ) @@ -218,7 +217,7 @@ public class CommandAPI implements ILuaAPI for( int x = min.getX(); x <= max.getX(); x++ ) { BlockPos pos = new BlockPos( x, y, z ); - results.put( i++, getBlockInfo( world, pos ) ); + results.add( getBlockInfo( world, pos ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 18b37d97b..dc5720fa5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -369,7 +369,10 @@ public class TurtlePlaceCommand implements ITurtleCommand if( !placed && (item instanceof ItemBucket || item instanceof ItemBoat || item instanceof ItemLilyPad || item instanceof ItemGlassBottle) ) { - EnumActionResult actionResult = ForgeHooks.onItemRightClick( turtlePlayer, EnumHand.MAIN_HAND ); + PlayerInteractEvent.RightClickItem evt = new PlayerInteractEvent.RightClickItem( turtlePlayer, EnumHand.MAIN_HAND ); + MinecraftForge.EVENT_BUS.post( evt ); + EnumActionResult actionResult = evt.isCanceled() ? evt.getCancellationResult() : null; + // EnumActionResult actionResult = ForgeHooks.onItemRightClick( turtlePlayer, EnumHand.MAIN_HAND ); if( actionResult == EnumActionResult.SUCCESS ) { placed = true; From 018ecfbaa0fe5ee93ddca33b32f2d33202d7034e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Jan 2020 13:43:38 +0000 Subject: [PATCH 129/711] =?UTF-8?q?=E2=96=B2=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../assets/computercraft/lua/rom/help/changelog.txt | 11 +++++++++++ .../assets/computercraft/lua/rom/help/whatsnew.txt | 12 +++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index c23effa6f..0b7c88e52 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.86.0 +mod_version=1.86.1 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index dec1fec52..351e3784c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,14 @@ +# New features in CC: Tweaked 1.86.1 + +* Add a help message to the Lua REPL's exit function +* Add more MOTD messages. (osmarks) +* GPS requests are now made anonymously (osmarks) +* Minor memory usage improvements to Cobalt VM. + +And several bug fixes: +* Fix error when calling `write` with a number. +* Add missing assertion to `io.write`. + # New features in CC: Tweaked 1.86.0 * Add PATCH and TRACE HTTP methods. (jaredallard) diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 3d8051511..04137ac9f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,10 +1,12 @@ -New features in CC: Tweaked 1.86.0 +New features in CC: Tweaked 1.86.1 -* Add PATCH and TRACE HTTP methods. (jaredallard) -* Add more MOTD messages. (JakobDev) -* Allow removing and adding turtle upgrades via CraftTweaker. +* Add a help message to the Lua REPL's exit function +* Add more MOTD messages. (osmarks) +* GPS requests are now made anonymously (osmarks) +* Minor memory usage improvements to Cobalt VM. And several bug fixes: -* Fix crash when interacting with Wearable Backpacks. +* Fix error when calling `write` with a number. +* Add missing assertion to `io.write`. Type "help changelog" to see the full version history. From 1862a439e28a6d7fc9810717f96d7689a0ce0b32 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Jan 2020 14:59:56 +0000 Subject: [PATCH 130/711] Correctly offset scroll cursor positions Fixes #330 --- .../dan200/computercraft/client/gui/widgets/WidgetWrapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java index df5c46f6b..4eeeaf8ee 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java @@ -55,7 +55,8 @@ public class WidgetWrapper implements IGuiEventListener @Override public boolean mouseScrolled( double x, double y, double delta ) { - return listener.mouseScrolled( x, y, delta ); + double dx = x - this.x, dy = y - this.y; + return dx >= 0 && dx < width && dy >= 0 && dy < height && listener.mouseScrolled( dx, dy, delta ); } @Override From 2541c3c5e650aece9003cf75aded5ef382954aa1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Jan 2020 15:08:09 +0000 Subject: [PATCH 131/711] Licenses, again --- src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java | 3 +-- .../dan200/computercraft/client/gui/widgets/WidgetWrapper.java | 3 +-- .../dan200/computercraft/core/filesystem/ResourceMount.java | 3 +-- src/main/java/dan200/computercraft/shared/Config.java | 3 +-- .../java/dan200/computercraft/shared/command/Exceptions.java | 3 +-- .../shared/command/arguments/ArgumentSerializers.java | 3 +-- .../shared/command/arguments/ChoiceArgumentType.java | 3 +-- .../shared/command/arguments/ComputerArgumentType.java | 3 +-- .../shared/command/arguments/ComputersArgumentType.java | 3 +-- .../shared/command/arguments/RepeatArgumentType.java | 3 +-- .../shared/command/arguments/TrackingFieldArgumentType.java | 3 +-- .../computercraft/shared/command/builder/ArgCommand.java | 3 +-- .../computercraft/shared/command/builder/CommandBuilder.java | 3 +-- .../shared/command/builder/CommandNodeBuilder.java | 3 +-- .../shared/command/builder/HelpingArgumentBuilder.java | 3 +-- .../dan200/computercraft/shared/common/ContainerHeldItem.java | 3 +-- .../computercraft/shared/common/IBundledRedstoneBlock.java | 3 +-- .../shared/computer/inventory/ContainerComputerBase.java | 3 +-- .../shared/computer/recipe/ComputerUpgradeRecipe.java | 3 +-- .../shared/data/BlockNamedEntityLootCondition.java | 3 +-- .../shared/data/ConstantLootConditionSerializer.java | 3 +-- .../computercraft/shared/data/PlayerCreativeLootCondition.java | 3 +-- .../shared/integration/crafttweaker/TrackingLogger.java | 3 +-- .../java/dan200/computercraft/shared/media/items/ItemDisk.java | 3 +-- .../shared/network/container/ComputerContainerData.java | 3 +-- .../computercraft/shared/network/container/ContainerData.java | 3 +-- .../shared/network/container/HeldItemContainerData.java | 3 +-- .../shared/network/container/ViewComputerContainerData.java | 3 +-- .../shared/peripheral/diskdrive/BlockDiskDrive.java | 3 +-- .../shared/peripheral/diskdrive/DiskDriveState.java | 3 +-- .../computercraft/shared/peripheral/modem/ModemShapes.java | 3 +-- .../shared/peripheral/modem/wired/CableModemVariant.java | 3 +-- .../shared/peripheral/modem/wired/CableShapes.java | 3 +-- .../shared/peripheral/modem/wired/ItemBlockCable.java | 3 +-- .../shared/peripheral/modem/wireless/BlockWirelessModem.java | 3 +-- .../computercraft/shared/peripheral/monitor/BlockMonitor.java | 3 +-- .../shared/peripheral/monitor/MonitorEdgeState.java | 3 +-- .../computercraft/shared/peripheral/printer/BlockPrinter.java | 3 +-- .../computercraft/shared/peripheral/speaker/BlockSpeaker.java | 3 +-- .../dan200/computercraft/shared/turtle/items/ItemTurtle.java | 3 +-- .../computercraft/shared/util/BasicRecipeSerializer.java | 3 +-- .../dan200/computercraft/shared/util/NamedTileEntityType.java | 3 +-- .../java/dan200/computercraft/shared/util/SingleIntArray.java | 3 +-- .../dan200/computercraft/shared/util/WaterloggableHelpers.java | 3 +-- .../computercraft/core/filesystem/ResourceMountTest.java | 2 +- 45 files changed, 45 insertions(+), 89 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 5a9f89df4..f8bf288d8 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft; import com.google.common.collect.MapMaker; diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java index 4eeeaf8ee..84317f8a3 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.gui.widgets; import net.minecraft.client.gui.IGuiEventListener; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index a7837bef4..e6116c144 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.filesystem; import com.google.common.cache.Cache; diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index c5a93c2a5..60e0e454a 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import com.electronwill.nightconfig.core.CommentedConfig; diff --git a/src/main/java/dan200/computercraft/shared/command/Exceptions.java b/src/main/java/dan200/computercraft/shared/command/Exceptions.java index e4a6b0a44..46289a773 100644 --- a/src/main/java/dan200/computercraft/shared/command/Exceptions.java +++ b/src/main/java/dan200/computercraft/shared/command/Exceptions.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java index 85e99bdfa..b52cb26cb 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.arguments; import com.mojang.brigadier.arguments.ArgumentType; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java index 16d8f8f26..797db6f85 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.arguments; import com.mojang.brigadier.Message; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java index cd07d381b..25bfe6256 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.arguments; import com.mojang.brigadier.StringReader; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java index a89f7a74c..9784556a8 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.arguments; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java index a7c957865..8c91be401 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.arguments; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java index 209a8d343..6391fd3ef 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.arguments; import dan200.computercraft.core.tracking.TrackingField; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java index c5fcd1990..f2dcc4efa 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.Command; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java index bbfe9eb0a..21998e71f 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.Command; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java index b3aad55d3..638a42806 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.tree.CommandNode; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index ca3c3db79..a90713133 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.command.builder; import com.mojang.brigadier.Command; diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index 292551360..6300cc0d7 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import dan200.computercraft.shared.network.container.ContainerData; diff --git a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java index 4d4b2d28c..27d45b4bb 100644 --- a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java +++ b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.common; import net.minecraft.util.Direction; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index e88b15b09..52e532550 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java index 6799bc784..afd91c89c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.computer.recipe; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index b8edf002c..c2842ff28 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import net.minecraft.tileentity.TileEntity; diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java index 4649b4c08..07ac6a830 100644 --- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import com.google.gson.JsonDeserializationContext; diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 5c8d45c3b..9055f3c17 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.data; import net.minecraft.entity.Entity; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java index 9635e0410..07733df89 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.integration.crafttweaker; import com.blamejared.crafttweaker.api.logger.ILogger; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 9dce5d77d..0b5a203c7 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.media.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java index fadf0189d..0a2b5c643 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.computer.core.ComputerFamily; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index 842f97957..370f6c139 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.container; import net.minecraft.entity.player.PlayerEntity; diff --git a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index ba3cab271..2088cd240 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.common.ContainerHeldItem; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index 1fa3edcea..e1805a517 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.container; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java index f018313a4..c87d1ba50 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.diskdrive; import dan200.computercraft.shared.common.BlockGeneric; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java index d15dd010d..17faae369 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.diskdrive; import net.minecraft.util.IStringSerializable; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java index 4aab12684..77d241b6a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; import net.minecraft.util.Direction; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index a22148fe2..be3630a05 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import net.minecraft.util.Direction; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java index 013f7f0ff..1b96f50ac 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java index 32efb50a5..c8c985e96 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wired; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index c5ae80392..33d0619ac 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.shared.common.BlockGeneric; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 2ea865c2c..6bf60083a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.shared.common.BlockGeneric; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java index 00b60f65c..0ada54c82 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import net.minecraft.util.IStringSerializable; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java index ef53a5f72..ce6f7fd92 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.shared.common.BlockGeneric; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java index 60ef1f9df..902e4de47 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.shared.common.BlockGeneric; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index 6e5f2e8f5..557234ed1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java b/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java index 6c54dff49..7558549b2 100644 --- a/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java +++ b/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.item.crafting.IRecipe; diff --git a/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java index b6d08624d..fed7ca91a 100644 --- a/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java +++ b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.block.Block; diff --git a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java index 11151ff72..3d2297f2b 100644 --- a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java +++ b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.util.IIntArray; diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java index 9364911f1..978b78eff 100644 --- a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java +++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.block.BlockState; diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java index f46e50fdb..5c61f24fb 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; From a706300598ceed6948f438a8cd9c49d1243ce6e8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Jan 2020 15:10:32 +0000 Subject: [PATCH 132/711] Update changelog/version --- src/main/resources/data/computercraft/lua/rom/help/changelog.txt | 1 + src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 57a0f63c9..44a72c70c 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -8,6 +8,7 @@ And several bug fixes: * Fix error when calling `write` with a number. * Add missing assertion to `io.write`. +* Fix incorrect coordinates in `mouse_scroll` events. # New features in CC: Tweaked 1.86.0 diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 04137ac9f..ca6899729 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -8,5 +8,6 @@ New features in CC: Tweaked 1.86.1 And several bug fixes: * Fix error when calling `write` with a number. * Add missing assertion to `io.write`. +* Fix incorrect coordinates in `mouse_scroll` events. Type "help changelog" to see the full version history. From 8b1773dd6019eb9ec5e7dfff44f1568518c2c930 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 14 Jan 2020 08:45:08 +0000 Subject: [PATCH 133/711] Fix peripheral.getMethods returning {} I don't even know how this snuck past. Closes #346 --- gradle.properties | 2 +- .../dan200/computercraft/core/apis/PeripheralAPI.java | 9 +++------ .../assets/computercraft/lua/rom/help/changelog.txt | 4 ++++ .../assets/computercraft/lua/rom/help/whatsnew.txt | 11 ++--------- 4 files changed, 10 insertions(+), 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0b7c88e52..0f6aa539a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.86.1 +mod_version=1.86.2 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index c957af8b2..c289c85a2 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -364,20 +364,17 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange case 2: { // getMethods - String[] methods = null; ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); if( side != null ) { synchronized( m_peripherals ) { PeripheralWrapper p = m_peripherals[side.ordinal()]; - if( p != null ) - { - methods = p.getMethods(); - } + if( p != null ) return new Object[] { p.getMethods() }; } } - return methods != null ? new Object[] { new HashMap<>() } : null; + + return null; } case 3: { diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 351e3784c..ae073d005 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.86.2 + +* Fix peripheral.getMethods returning an empty table + # New features in CC: Tweaked 1.86.1 * Add a help message to the Lua REPL's exit function diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 04137ac9f..0ded4f8d3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,12 +1,5 @@ -New features in CC: Tweaked 1.86.1 +New features in CC: Tweaked 1.86.2 -* Add a help message to the Lua REPL's exit function -* Add more MOTD messages. (osmarks) -* GPS requests are now made anonymously (osmarks) -* Minor memory usage improvements to Cobalt VM. - -And several bug fixes: -* Fix error when calling `write` with a number. -* Add missing assertion to `io.write`. +* Fix peripheral.getMethods returning an empty table Type "help changelog" to see the full version history. From 1db3a14c5426abce0e1e06b7b5dfbe8a0cb20533 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 15 Jan 2020 09:29:11 +0000 Subject: [PATCH 134/711] Eta-reduce several calls to pcall --- .../assets/computercraft/lua/bios.lua | 29 +++++++++---------- .../computercraft/lua/rom/programs/lua.lua | 2 +- .../lua/rom/programs/rednet/chat.lua | 16 +++++----- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 2913da090..500276da4 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -991,22 +991,19 @@ if fs.exists( ".settings" ) then end -- Run the shell -local ok, err = pcall( function() - parallel.waitForAny( - function() - local sShell - if term.isColour() and settings.get( "bios.use_multishell" ) then - sShell = "rom/programs/advanced/multishell.lua" - else - sShell = "rom/programs/shell.lua" - end - os.run( {}, sShell ) - os.run( {}, "rom/programs/shutdown.lua" ) - end, - function() - rednet.run() - end ) -end ) +local ok, err = pcall(parallel.waitForAny, + function() + local sShell + if term.isColour() and settings.get( "bios.use_multishell" ) then + sShell = "rom/programs/advanced/multishell.lua" + else + sShell = "rom/programs/shell.lua" + end + os.run( {}, sShell ) + os.run( {}, "rom/programs/shutdown.lua" ) + end, + rednet.run +) -- If the shell errored, let the user read it. term.redirect( term.native() ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 63d4c6add..0a6a664fe 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -10,7 +10,7 @@ local bRunning = true local tCommandHistory = {} local tEnv = { ["exit"] = setmetatable({}, { - __tostring = function() return "Call exit() to exit" end, + __tostring = function() return "Call exit() to exit." end, __call = function() bRunning = false end, }), ["_echo"] = function( ... ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index 58a513f36..4c4ae75c0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -105,8 +105,8 @@ if sCommand == "host" then end -- Handle messages - local ok, error = pcall( function() - parallel.waitForAny( function() + local ok, error = pcall(parallel.waitForAny, + function() while true do local _, timer = os.pullEvent( "timer" ) local nUserID = tPingPongTimer[ timer ] @@ -223,8 +223,8 @@ if sCommand == "host" then end end end - end ) - end ) + end + ) if not ok then printError( error ) end @@ -332,8 +332,8 @@ elseif sCommand == "join" then drawTitle() - local ok, error = pcall( function() - parallel.waitForAny( function() + local ok, error = pcall(parallel.waitForAny, + function() while true do local sEvent, timer = os.pullEvent() if sEvent == "timer" then @@ -402,8 +402,8 @@ elseif sCommand == "join" then table.insert( tSendHistory, sChat ) end end - end ) - end ) + end + ) -- Close the windows term.redirect( parentTerm ) From c79f643ba71cb9a6e63e21aa6457949f7cf47d4d Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 17 Jan 2020 10:18:46 +0000 Subject: [PATCH 135/711] Remove redundant illuaminate options --- illuaminate.sexp | 3 --- 1 file changed, 3 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index b37f34928..d6865618c 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -23,6 +23,3 @@ (linters -var:unused-global) (lint (allow-toplevel-global true))) - -;; These warnings are broken right now -(at (bios.lua worm.lua) (linters -control:unreachable)) From 798868427e8e03edf67976d7ff0cbfe67a8be856 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 17 Jan 2020 22:51:36 +0000 Subject: [PATCH 136/711] Use a Wadler style pretty printer in the Lua REPL (#334) - Add a cc.pretty module, which provides a Wadler style pretty printer [1]. - The cc.pretty.pretty function converts an arbitrary object into a pretty-printed document. This can then be printed to the screen with cc.pretty.{write, print} or converted to a string with cc.pretty.render. - Convert the Lua REPL to use the pretty printer rather than textutils.serialise. [1]: http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf --- .../lua/rom/modules/main/cc/pretty.lua | 416 ++++++++++++++++++ .../computercraft/lua/rom/programs/lua.lua | 19 +- .../test-rom/spec/modules/cc/pretty_spec.lua | 208 +++++++++ 3 files changed, 630 insertions(+), 13 deletions(-) create mode 100644 src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua create mode 100644 src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua new file mode 100644 index 000000000..cf0007568 --- /dev/null +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -0,0 +1,416 @@ +--- Provides a "pretty printer", for rendering data structures in an +-- aesthetically pleasing manner. +-- +-- In order to display something using @{cc.pretty}, you build up a series of +-- @{documents|Doc}. These behave a little bit like strings; you can concatenate +-- them together and then print them to the screen. +-- +-- However, documents also allow you to control how they should be printed. There +-- are several functions (such as @{nest} and @{group}) which allow you to control +-- the "layout" of the document. When you come to display the document, the 'best' +-- (most compact) layout is used. +-- +-- @module cc.pretty +-- @usage Print a table to the terminal +-- local pretty = require "cc.pretty" +-- pretty.write(pretty.dump({ 1, 2, 3 })) +-- +-- @usage Build a custom document and display it +-- local pretty = require "cc.pretty" +-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world"))) + +local expect = require "cc.expect".expect +local type, getmetatable, setmetatable, colours, str_write = type, getmetatable, setmetatable, colours, write + +--- @{table.insert} alternative, but with the length stored inline. +local function append(out, value) + local n = out.n + 1 + out[n], out.n = value, n +end + +--- A document, which +-- +-- Documents effectively represent a sequence of strings in alternative layouts, +-- which we will try to print in the most compact form necessary. +-- +-- @type Doc +local Doc = { } + +--- An empty document. +local empty = setmetatable({ tag = "nil" }, Doc) + +--- A document with a single space in it. +local space = setmetatable({ tag = "text", text = " " }, Doc) + +--- A line break. When collapsed with @{group}, this will be replaced with @{empty}. +local line = setmetatable({ tag = "line", flat = empty }, Doc) + +--- A line break. When collapsed with @{group}, this will be replaced with @{space}. +local space_line = setmetatable({ tag = "line", flat = space }, Doc) + +local text_cache = { [""] = empty, [" "] = space, ["\n"] = space_line } + +local function mk_text(text, colour) + return text_cache[text] or setmetatable({ tag = "text", text = text, colour = colour }, Doc) +end + +--- Create a new document from a string. +-- +-- If your string contains multiple lines, @{group} will flatten the string +-- into a single line, with spaces between each line. +-- +-- @tparam string text The string to construct a new document with. +-- @tparam[opt] number colour The colour this text should be printed with. If not given, we default to the current +-- colour. +-- @treturn Doc The document with the provided text. +local function text(text, colour) + expect(1, text, "string") + expect(2, colour, "number", "nil") + + local cached = text_cache[text] + if cached then return cached end + + local new_line = text:find("\n", 1) + if not new_line then return mk_text(text, colour) end + + -- Split the string by "\n". With a micro-optimisation to skip empty strings. + local doc = setmetatable({ tag = "concat", n = 0 }, Doc) + if new_line ~= 1 then append(doc, mk_text(text:sub(1, new_line - 1), colour)) end + + new_line = new_line + 1 + while true do + local next_line = text:find("\n", new_line) + append(doc, space_line) + if not next_line then + if new_line <= #text then append(doc, mk_text(text:sub(new_line), colour)) end + return doc + else + if new_line <= next_line - 1 then + append(doc, mk_text(text:sub(new_line, next_line - 1), colour)) + end + new_line = next_line + 1 + end + end +end + +--- Concatenate several documents together. This behaves very similar to string concatenation. + +-- @tparam Doc|string ... The documents to concatenate. +-- @treturn Doc The concatenated documents. +-- @usage pretty.concat(doc1, " - ", doc2) +-- @usage doc1 .. " - " .. doc2 +local function concat(...) + local args = table.pack(...) + for i = 1, args.n do + if type(args[i]) == "string" then args[i] = text(args[i]) end + if getmetatable(args[i]) ~= Doc then expect(i, args[i], "document") end + end + + if args.n == 0 then return empty end + if args.n == 1 then return args[1] end + + args.tag = "concat" + return setmetatable(args, Doc) +end + +Doc.__concat = concat + +--- Indent later lines of the given document with the given number of spaces. +-- +-- For instance, nesting the document +-- ```txt +-- foo +-- bar +-- `` +-- by two spaces will produce +-- ```txt +-- foo +-- bar +-- ``` +-- +-- @tparam number depth The number of spaces with which the document should be indented. +-- @tparam Doc doc The document to indent. +-- @treturn Doc The nested document. +-- @usage pretty.nest(2, pretty.text("foo\nbar")) +local function nest(depth, doc) + expect(1, depth, "number") + if getmetatable(doc) ~= Doc then expect(2, doc, "document") end + if depth <= 0 then error("depth must be a positive number", 2) end + + return setmetatable({ tag = "nest", depth = depth, doc }, Doc) +end + +local function flatten(doc) + if doc.flat then return doc.flat end + + local kind = doc.tag + if kind == "nil" or kind == "text" then + return doc + elseif kind == "concat" then + local out = setmetatable({ tag = "concat", n = doc.n }, Doc) + for i = 1, doc.n do out[i] = flatten(doc[i]) end + doc.flat, out.flat = out, out -- cache the flattened node + return out + elseif kind == "nest" then + return flatten(doc[1]) + elseif kind == "group" then + return doc[1] + else + error("Unknown doc " .. kind) + end +end + +--- Builds a document which is displayed on a single line if there is enough +-- room, or as normal if not. +-- +-- @tparam Doc doc The document to group. +-- @treturn Doc The grouped document. +local function group(doc) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + + if doc.tag == "group" then return doc end -- Skip if already grouped. + + local flattened = flatten(doc) + if flattened == doc then return doc end -- Also skip if flattening does nothing. + return setmetatable({ tag = "group", flattened, doc }, Doc) +end + +local function get_remaining(doc, width) + local kind = doc.tag + if kind == "nil" or kind == "line" then + return width + elseif kind == "text" then + return width - #doc.text + elseif kind == "concat" then + for i = 1, doc.n do + width = get_remaining(doc[i], width) + if width < 0 then break end + end + return width + elseif kind == "group" or kind == "nest" then + return get_remaining(kind[1]) + else + error("Unknown doc " .. kind) + end +end + +--- Display a document on the terminal. +-- +-- @tparam Doc doc The document to render +-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +local function write(doc, ribbon_frac) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + expect(2, ribbon_frac, "number", "nil") + + local term = term + local width, height = term.getSize() + local ribbon_width = (ribbon_frac or 0.6) * width + if ribbon_width < 0 then ribbon_width = 0 end + if ribbon_width > width then ribbon_width = width end + + local def_colour = term.getTextColour() + local current_colour = def_colour + + local function go(doc, indent, col) + local kind = doc.tag + if kind == "nil" then + return col + elseif kind == "text" then + local doc_colour = doc.colour or def_colour + if doc_colour ~= current_colour then + term.setTextColour(doc_colour) + current_colour = doc_colour + end + + str_write(doc.text) + + return col + #doc.text + elseif kind == "line" then + local _, y = term.getCursorPos() + if y < height then + term.setCursorPos(indent + 1, y + 1) + else + term.scroll(1) + term.setCursorPos(indent + 1, height) + end + + return indent + elseif kind == "concat" then + for i = 1, doc.n do col = go(doc[i], indent, col) end + return col + elseif kind == "nest" then + return go(doc[1], indent + doc.depth, col) + elseif kind == "group" then + if get_remaining(doc[1], math.min(width, ribbon_width + indent) - col) >= 0 then + return go(doc[1], indent, col) + else + return go(doc[2], indent, col) + end + else + error("Unknown doc " .. kind) + end + end + + local col = math.max(term.getCursorPos() - 1, 0) + go(doc, 0, col) + if current_colour ~= def_colour then term.setTextColour(def_colour) end +end + +--- Display a document on the terminal with a trailing new line. +-- +-- @tparam Doc doc The document to render. +-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +local function print(doc, ribbon_frac) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + expect(2, ribbon_frac, "number", "nil") + write(doc, ribbon_frac) + str_write("\n") +end + +--- Render a document, converting it into a string. +-- +-- @tparam Doc doc The document to render. +-- @tparam[opt] number width The maximum width of this document. Note that long strings will not be wrapped to +-- fit this width - it is only used for finding the best layout. +-- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +local function render(doc, width, ribbon_frac) + if getmetatable(doc) ~= Doc then expect(1, doc, "document") end + expect(2, width, "number", "nil") + expect(3, ribbon_frac, "number", "nil") + + local ribbon_width + if width then + ribbon_width = (ribbon_frac or 0.6) * width + if ribbon_width < 0 then ribbon_width = 0 end + if ribbon_width > width then ribbon_width = width end + end + + local out = { n = 0 } + local function go(doc, indent, col) + local kind = doc.tag + if kind == "nil" then + return col + elseif kind == "text" then + append(out, doc.text) + return col + #doc.text + elseif kind == "line" then + append(out, "\n" .. (" "):rep(indent)) + return indent + elseif kind == "concat" then + for i = 1, doc.n do col = go(doc[i], indent, col) end + return col + elseif kind == "nest" then + return go(doc[1], indent + doc.depth, col) + elseif kind == "group" then + if not width or get_remaining(doc[1], math.min(width, ribbon_width + indent) - col) >= 0 then + return go(doc[1], indent, col) + else + return go(doc[2], indent, col) + end + else + error("Unknown doc " .. kind) + end + end + + go(doc, 0, 0) + return table.concat(out, "", 1, out.n) +end + +local keywords = { + [ "and" ] = true, [ "break" ] = true, [ "do" ] = true, [ "else" ] = true, + [ "elseif" ] = true, [ "end" ] = true, [ "false" ] = true, [ "for" ] = true, + [ "function" ] = true, [ "if" ] = true, [ "in" ] = true, [ "local" ] = true, + [ "nil" ] = true, [ "not" ] = true, [ "or" ] = true, [ "repeat" ] = true, [ "return" ] = true, + [ "then" ] = true, [ "true" ] = true, [ "until" ] = true, [ "while" ] = true, + } + +local comma = text(",") +local braces = text("{}") +local obrace, cbrace = text("{"), text("}") +local obracket, cbracket = text("["), text("] = ") + +local function key_compare(a, b) + local ta, tb = type(a), type(b) + + if ta == "string" then return tb ~= "string" or a < b + elseif tb == "string" then return false + end + + if ta == "number" then return tb ~= "number" or a < b end + return false +end + +local function pretty_impl(obj, tracking) + local obj_type = type(obj) + if obj_type == "string" then + local formatted = ("%q"):format(obj):gsub("\\\n", "\\n") + return text(formatted, colours.red) + elseif obj_type == "number" then + return text(tostring(obj), colours.magenta) + elseif obj_type ~= "table" or tracking[obj] then + return text(tostring(obj), colours.lightGrey) + elseif getmetatable(obj) ~= nil and getmetatable(obj).__tostring then + return text(tostring(obj)) + elseif next(obj) == nil then + return braces + else + tracking[obj] = true + local doc = setmetatable({ tag = "concat", n = 1, space_line }, Doc) + + local length, keys, keysn = #obj, {}, 1 + for k in pairs(obj) do keys[keysn], keysn = k, keysn + 1 end + table.sort(keys, key_compare) + + for i = 1, keysn - 1 do + if i > 1 then append(doc, comma) append(doc, space_line) end + + local k = keys[i] + local v = obj[k] + local ty = type(k) + if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then + append(doc, pretty_impl(v, tracking)) + elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then + append(doc, text(k .. " = ")) + append(doc, pretty_impl(v, tracking)) + else + append(doc, obracket) + append(doc, pretty_impl(k, tracking)) + append(doc, cbracket) + append(doc, pretty_impl(v, tracking)) + end + end + + tracking[obj] = nil + return group(concat(obrace, nest(2, concat(table.unpack(doc, 1, n))), space_line, cbrace)) + end +end + +--- Pretty-print an arbitrary object, converting it into a document. +-- +-- This can then be rendered with @{write} or @{print}. +-- +-- @param obj The object to pretty-print. +-- @treturn Doc The object formatted as a document. +-- @usage Display a table on the screen +-- local pretty = require "cc.pretty" +-- pretty.print(pretty.pretty({ 1, 2, 3 }) +local function pretty(obj) + return pretty_impl(obj, {}) +end + +return { + empty = empty, + space = space, + line = line, + space_line = space_line, + text = text, + concat = concat, + nest = nest, + group = group, + + write = write, + print = print, + render = render, + + pretty = pretty, +} diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 0a6a664fe..6514e6390 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -6,6 +6,8 @@ if #tArgs > 0 then return end +local pretty = require "cc.pretty" + local bRunning = true local tCommandHistory = {} local tEnv = { @@ -87,20 +89,11 @@ while bRunning do local n = 1 while n < tResults.n or n <= nForcePrint do local value = tResults[ n + 1 ] - if type( value ) == "table" then - local metatable = getmetatable( value ) - if type(metatable) == "table" and type(metatable.__tostring) == "function" then - print( tostring( value ) ) - else - local ok, serialised = pcall( textutils.serialise, value ) - if ok then - print( serialised ) - else - print( tostring( value ) ) - end - end + local ok, serialised = pcall(pretty.pretty, value) + if ok then + pretty.print(serialised) else - print( tostring( value ) ) + print(tostring(value)) end n = n + 1 end diff --git a/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua new file mode 100644 index 000000000..38b2ecc3c --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua @@ -0,0 +1,208 @@ +local with_window = require "test_helpers".with_window + +describe("cc.pretty", function() + local pp = require("cc.pretty") + + describe("text", function() + it("is constant for the empty string", function() + expect(pp.text("")):eq(pp.empty) + end) + + it("is constant for a space", function() + expect(pp.text(" ")):eq(pp.space) + end) + + it("is constant for a newline", function() + expect(pp.text("\n")):eq(pp.space_line) + end) + + it("validates arguments", function() + expect.error(pp.text, 123):eq("bad argument #1 (expected string, got number)") + expect.error(pp.text, "", ""):eq("bad argument #2 (expected number, got string)") + end) + + it("produces text documents", function() + expect(pp.text("a")):same({ tag = "text", text = "a" }) + expect(pp.text("a", colours.grey)):same({ tag = "text", text = "a", colour = colours.grey }) + end) + + it("splits lines", function() + expect(pp.text("a\nb")) + :same(pp.concat(pp.text("a"), pp.space_line, pp.text("b"))) + expect(pp.text("ab\ncd\nef")) + :same(pp.concat(pp.text("ab"), pp.space_line, pp.text("cd"), pp.space_line, pp.text("ef"))) + end) + + it("preserves empty lines", function() + expect(pp.text("a\n\nb")) + :same(pp.concat(pp.text("a"), pp.space_line, pp.space_line, pp.text("b"))) + expect(pp.text("\n\nb")) + :same(pp.concat(pp.space_line, pp.space_line, pp.text("b"))) + expect(pp.text("a\n\n")) + :same(pp.concat(pp.text("a"), pp.space_line, pp.space_line)) + end) + end) + + describe("concat", function() + it("returns empty with 0 arguments", function() + expect(pp.concat()):eq(pp.empty) + end) + + it("acts as the identity with 1 argument", function() + local x = pp.text("test") + expect(pp.concat(x)):eq(x) + end) + + it("coerces strings", function() + expect(pp.concat("a", "b")):same(pp.concat(pp.text("a"), pp.text("b"))) + end) + + it("validates arguments", function() + expect.error(pp.concat, 123):eq("bad argument #1 (expected document, got number)") + expect.error(pp.concat, "", {}):eq("bad argument #2 (expected document, got table)") + end) + + it("can be used as an operator", function() + local a, b = pp.text("a"), pp.text("b") + expect(pp.concat(a, b)):same(a .. b) + end) + end) + + describe("group", function() + it("is idempotent", function() + local x = pp.group(pp.text("a\nb")) + expect(pp.group(x)):eq(x) + end) + + it("does nothing for flat strings", function() + local x = pp.text("a") + expect(pp.group(x)):eq(x) + end) + end) + + -- Allows us to test + local function test_output(display) + it("displays the empty document", function() + expect(display(pp.empty)):same { "" } + end) + + it("displays a multiline string", function() + expect(display(pp.text("hello\nworld"))):same { + "hello", + "world", + } + end) + + it("displays a nested string", function() + expect(display(pp.nest(2, pp.concat("hello", pp.line, "world")))):same { + "hello", + " world", + } + end) + + it("displays a flattened group", function() + expect(display(pp.group(pp.concat("hello", pp.space_line, "world")))):same { + "hello world", + } + + expect(display(pp.group(pp.concat("hello", pp.line, "world")))):same { + "helloworld", + } + end) + + it("displays an expanded group", function() + expect(display(pp.group(pp.concat("hello darkness", pp.space_line, "my old friend")))):same { + "hello darkness", + "my old friend", + } + end) + + it("group removes nest", function() + expect(display(pp.group(pp.nest(2, pp.concat("hello", pp.space_line, "world"))))):same { + "hello world", + } + end) + end + + describe("write", function() + local function display(doc) + local w = with_window(20, 10, function() pp.write(doc) end) + local _, y = w.getCursorPos() + + local out = {} + for i = 1, y do out[i] = w.getLine(i):gsub("%s+$", "") end + return out + end + + test_output(display) + + it("wraps a long string", function() + expect(display(pp.text("hello world this is a long string which will wrap"))):same { + "hello world this is", + "a long string which", + "will wrap", + } + end) + end) + + describe("render", function() + local function display(doc) + local rendered = pp.render(doc, 20) + local n, lines = 1, {} + for line in (rendered .. "\n"):gmatch("([^\n]*)\n") do lines[n], n = line, n + 1 end + return lines + end + + test_output(display) + + it("does not wrap a long string", function() + expect(display(pp.text("hello world this is a long string which will wrap"))):same { + "hello world this is a long string which will wrap", + } + end) + end) + + describe("pretty", function() + --- We make use of "render" here, as it's considerably easier than checking against the actual structure. + -- However, it does also mean our tests are less unit-like. + local function pretty(x, width) return pp.render(pp.pretty(x), width) end + + describe("tables", function() + it("displays empty tables", function() + expect(pp.pretty({})):same(pp.text("{}")) + end) + + it("displays list-like tables", function() + expect(pretty({ 1, 2, 3 })):eq("{ 1, 2, 3 }") + end) + + it("displays mixed tables", function() + expect(pretty({ n = 3, 1, 2, 3 })):eq("{ n = 3, 1, 2, 3 }") + end) + + it("escapes keys", function() + expect(pretty({ ["and"] = 1, ["not that"] = 2 })):eq('{ ["and"] = 1, ["not that"] = 2 }') + end) + + it("sorts keys", function() + expect(pretty({ c = 1, b = 2, a = 3 })):eq('{ a = 3, b = 2, c = 1 }') + end) + + it("groups tables", function() + expect(pretty({ 1, 2, 3 }, 4)):eq("{\n 1,\n 2,\n 3\n}") + end) + end) + + it("shows numbers", function() + expect(pretty(123)):eq("123") + end) + + it("shows strings", function() + expect(pretty("hello\nworld")):eq('"hello\\nworld"') + end) + + it("shows functions", function() + expect(pretty(pretty)):eq(tostring(pretty)) + end) + end) +end) From 3f98b2785e893dc081f2a40212d1670e8149571c Mon Sep 17 00:00:00 2001 From: magiczocker10 <59317952+magiczocker10@users.noreply.github.com> Date: Thu, 23 Jan 2020 16:08:11 +0100 Subject: [PATCH 137/711] Fix turtle texture layout (#350) --- .../computercraft/models/block/modem.json | 2 +- .../models/block/turtle_base.json | 22 +++++----- .../block/turtle_upgrade_base_left.json | 4 +- .../block/turtle_upgrade_base_right.json | 4 +- .../models/block/turtle_white.json | 44 +++++++++---------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/main/resources/assets/computercraft/models/block/modem.json b/src/main/resources/assets/computercraft/models/block/modem.json index fd6ff916e..7ea4efaef 100644 --- a/src/main/resources/assets/computercraft/models/block/modem.json +++ b/src/main/resources/assets/computercraft/models/block/modem.json @@ -10,7 +10,7 @@ "faces": { "down": { "uv": [ 2, 13, 14, 16 ], "texture": "#front" }, "up": { "uv": [ 2, 0, 14, 3 ], "texture": "#front" }, - "north": { "uv": [ 2, 2, 14, 14 ], "texture": "#back" }, + "north": { "uv": [ 2, 2, 14, 14 ], "texture": "#back", "cullface": "north" }, "south": { "uv": [ 2, 2, 14, 14 ], "texture": "#front" }, "west": { "uv": [ 0, 2, 3, 14 ], "texture": "#front" }, "east": { "uv": [ 13, 2, 16, 14 ], "texture": "#front" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_base.json b/src/main/resources/assets/computercraft/models/block/turtle_base.json index a4788803d..aa3e71418 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_base.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_base.json @@ -8,23 +8,23 @@ "from": [ 2, 2, 2 ], "to": [ 14, 14, 13 ], "faces": { - "down": { "uv": [ 2.75, 0, 5.75, 2.75 ], "texture": "#texture" }, - "up": { "uv": [ 5.75, 0, 8.75, 2.75 ], "texture": "#texture" }, - "north": { "uv": [ 8.5, 5.75, 11.5, 2.75 ], "texture": "#texture" }, - "south": { "uv": [ 2.75, 5.75, 5.75, 2.75 ], "texture": "#texture" }, - "west": { "uv": [ 0, 5.75, 2.75, 2.75 ], "texture": "#texture" }, - "east": { "uv": [ 5.75, 5.75, 8.5, 2.75 ], "texture": "#texture" } + "down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" }, + "up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" }, + "north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" }, + "south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" }, + "west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" }, + "east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" } } }, { "from": [ 3, 6, 13 ], "to": [ 13, 13, 15 ], "faces": { - "down": { "uv": [ 9.25, 0, 11.75, 0.5 ], "texture": "#texture" }, - "up": { "uv": [ 11.75, 0, 14.25, 0.5 ], "texture": "#texture" }, - "south": { "uv": [ 9.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, - "west": { "uv": [ 8.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, - "east": { "uv": [ 11.75, 2.25, 12.25, 0.5 ], "texture": "#texture" } + "down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" }, + "up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" }, + "south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, + "west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, + "east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" } } } ] diff --git a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json index 1dcf2e72a..823c5e590 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_left.json @@ -8,8 +8,8 @@ "from": [ 0.5, 4.5, 3.5 ], "to": [ 2, 12.5, 11.5 ], "faces": { - "down": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, - "up": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, + "down": { "uv": [ 2, 14, 14, 16 ], "texture": "#texture", "rotation": 270 }, + "up": { "uv": [ 2, 0, 14, 3 ], "texture": "#texture", "rotation": 90 }, "north": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, "south": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, "west": { "uv": [ 2, 2, 14, 14 ], "texture": "#texture" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json index ff52e9d67..7ab452e94 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_upgrade_base_right.json @@ -8,8 +8,8 @@ "from": [ 14, 4.5, 3.5 ], "to": [ 15.5, 12.5, 11.5 ], "faces": { - "down": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, - "up": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, + "down": { "uv": [ 2, 14, 14, 16 ], "texture": "#texture", "rotation": 90 }, + "up": { "uv": [ 2, 0, 14, 3 ], "texture": "#texture", "rotation": 270 }, "north": { "uv": [ 13, 2, 16, 14 ], "texture": "#texture" }, "south": { "uv": [ 0, 2, 3, 14 ], "texture": "#texture" }, "east": { "uv": [ 2, 2, 14, 14 ], "texture": "#texture" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_white.json b/src/main/resources/assets/computercraft/models/block/turtle_white.json index 7e0d2df03..fe9a5c233 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_white.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_white.json @@ -8,46 +8,46 @@ "from": [ 2, 2, 2 ], "to": [ 14, 14, 13 ], "faces": { - "down": { "uv": [ 2.75, 5.75, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "up": { "uv": [ 5.75, 5.75, 8.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "north": { "uv": [ 8.5, 11.5, 11.5, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "south": { "uv": [ 2.75, 11.5, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "west": { "uv": [ 0, 11.5, 2.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, - "east": { "uv": [ 5.75, 11.5, 8.5, 8.555 ], "texture": "#texture", "tintindex": 0 } + "down": { "uv": [ 5.75, 8.5, 2.75, 5.75 ], "texture": "#texture", "tintindex": 0 }, + "up": { "uv": [ 8.75, 5.75, 5.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, + "north": { "uv": [ 11.5, 11.5, 8.5, 8.5 ], "texture": "#texture", "tintindex": 0 }, + "south": { "uv": [ 5.75, 11.5, 2.75, 8.5 ], "texture": "#texture", "tintindex": 0 }, + "west": { "uv": [ 8.5, 11.5, 5.75, 8.555 ], "texture": "#texture", "tintindex": 0 }, + "east": { "uv": [ 2.75, 11.5, 0, 8.5 ], "texture": "#texture", "tintindex": 0 } } }, { "from": [ 3, 6, 13 ], "to": [ 13, 13, 15 ], "faces": { - "down": { "uv": [ 9.25, 5.75, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "up": { "uv": [ 11.75, 5.75, 14.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "south": { "uv": [ 9.25, 8, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "west": { "uv": [ 8.75, 8, 9.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, - "east": { "uv": [ 11.75, 8, 12.25, 6.25 ], "texture": "#texture", "tintindex": 0 } + "down": { "uv": [ 11.75, 6.25, 9.25, 5.75 ], "texture": "#texture", "tintindex": 0 }, + "up": { "uv": [ 14.25, 5.75, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, + "south": { "uv": [ 11.75, 8, 9.25, 6.25 ], "texture": "#texture", "tintindex": 0 }, + "west": { "uv": [ 12.25, 8, 11.75, 6.25 ], "texture": "#texture", "tintindex": 0 }, + "east": { "uv": [ 9.25, 8, 8.75, 6.25 ], "texture": "#texture", "tintindex": 0 } } }, { "from": [ 2, 2, 2 ], "to": [ 14, 14, 13 ], "faces": { - "down": { "uv": [ 2.75, 0, 5.75, 2.75 ], "texture": "#texture" }, - "up": { "uv": [ 5.75, 0, 8.75, 2.75 ], "texture": "#texture" }, - "north": { "uv": [ 8.5, 5.75, 11.5, 2.75 ], "texture": "#texture" }, - "south": { "uv": [ 2.75, 5.75, 5.75, 2.75 ], "texture": "#texture" }, - "west": { "uv": [ 0, 5.75, 2.75, 2.75 ], "texture": "#texture" }, - "east": { "uv": [ 5.75, 5.75, 8.5, 2.75 ], "texture": "#texture" } + "down": { "uv": [ 5.75, 2.75, 2.75, 0 ], "texture": "#texture" }, + "up": { "uv": [ 8.75, 0, 5.75, 2.75 ], "texture": "#texture" }, + "north": { "uv": [ 11.5, 5.75, 8.5, 2.75 ], "texture": "#texture" }, + "south": { "uv": [ 5.75, 5.75, 2.75, 2.75 ], "texture": "#texture" }, + "west": { "uv": [ 8.5, 5.75, 5.75, 2.75 ], "texture": "#texture" }, + "east": { "uv": [ 2.75, 5.75, 0, 2.75 ], "texture": "#texture" } } }, { "from": [ 3, 6, 13 ], "to": [ 13, 13, 15 ], "faces": { - "down": { "uv": [ 9.25, 0, 11.75, 0.5 ], "texture": "#texture" }, - "up": { "uv": [ 11.75, 0, 14.25, 0.5 ], "texture": "#texture" }, - "south": { "uv": [ 9.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, - "west": { "uv": [ 8.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, - "east": { "uv": [ 11.75, 2.25, 12.25, 0.5 ], "texture": "#texture" } + "down": { "uv": [ 11.75, 0.5, 9.25, 0 ], "texture": "#texture" }, + "up": { "uv": [ 14.25, 0, 11.75, 0.5 ], "texture": "#texture" }, + "south": { "uv": [ 11.75, 2.25, 9.25, 0.5 ], "texture": "#texture" }, + "west": { "uv": [ 12.25, 2.25, 11.75, 0.5 ], "texture": "#texture" }, + "east": { "uv": [ 9.25, 2.25, 8.75, 0.5 ], "texture": "#texture" } } } ] From 0de5969ec135dfa3b7d96bbdc201964f07142da0 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 23 Jan 2020 15:11:50 +0000 Subject: [PATCH 138/711] Lint whitespace during CI --- .github/workflows/main-ci.yml | 3 + .../computercraft/lua/rom/help/adventure.txt | 2 +- .../computercraft/lua/rom/help/alias.txt | 2 +- .../computercraft/lua/rom/help/chat.txt | 2 +- .../computercraft/lua/rom/help/clear.txt | 2 +- .../computercraft/lua/rom/help/coroutine.txt | 2 +- .../computercraft/lua/rom/help/dance.txt | 2 +- .../computercraft/lua/rom/help/disk.txt | 2 +- .../assets/computercraft/lua/rom/help/dj.txt | 2 +- .../computercraft/lua/rom/help/drive.txt | 2 +- .../computercraft/lua/rom/help/drives.txt | 2 +- .../computercraft/lua/rom/help/earth.txt | 2 +- .../computercraft/lua/rom/help/edit.txt | 2 +- .../computercraft/lua/rom/help/exit.txt | 2 +- .../assets/computercraft/lua/rom/help/gps.txt | 4 +- .../computercraft/lua/rom/help/gpsapi.txt | 2 +- .../computercraft/lua/rom/help/hello.txt | 2 +- .../computercraft/lua/rom/help/help.txt | 2 +- .../assets/computercraft/lua/rom/help/id.txt | 2 +- .../assets/computercraft/lua/rom/help/io.txt | 2 +- .../computercraft/lua/rom/help/keys.txt | 4 +- .../computercraft/lua/rom/help/list.txt | 2 +- .../assets/computercraft/lua/rom/help/lua.txt | 2 +- .../computercraft/lua/rom/help/math.txt | 2 +- .../computercraft/lua/rom/help/mkdir.txt | 2 +- .../computercraft/lua/rom/help/modems.txt | 2 +- .../computercraft/lua/rom/help/monitor.txt | 2 +- .../computercraft/lua/rom/help/multishell.txt | 2 +- .../assets/computercraft/lua/rom/help/os.txt | 2 +- .../computercraft/lua/rom/help/parallel.txt | 2 +- .../computercraft/lua/rom/help/pocket.txt | 2 +- .../computercraft/lua/rom/help/printers.txt | 2 +- .../lua/rom/help/programming.txt | 2 +- .../computercraft/lua/rom/help/reboot.txt | 2 +- .../computercraft/lua/rom/help/redstone.txt | 2 +- .../computercraft/lua/rom/help/refuel.txt | 2 +- .../computercraft/lua/rom/help/repeat.txt | 2 +- .../computercraft/lua/rom/help/shell.txt | 2 +- .../computercraft/lua/rom/help/shutdown.txt | 2 +- .../computercraft/lua/rom/help/string.txt | 2 +- .../computercraft/lua/rom/help/table.txt | 2 +- .../computercraft/lua/rom/help/time.txt | 2 +- .../computercraft/lua/rom/help/type.txt | 2 +- .../GopherAtl/battleship/battleship.lua | 248 +++++------ .../treasure/GravityScore/LuaIDE/luaide.lua | 46 +- .../lua/treasure/JTK/maze3d/maze2d.lua | 76 ++-- .../lua/treasure/JTK/maze3d/maze3d.lua | 64 +-- .../lua/treasure/Lyqyd/nsh/get.lua | 2 +- .../lua/treasure/Lyqyd/nsh/nsh.lua | 2 +- .../lua/treasure/Lyqyd/nsh/put.lua | 2 +- .../TheOriginalBIT/tictactoe/tictactoe.lua | 12 +- .../dan200/alongtimeago/alongtimeago.lua | 2 +- .../deprecated/GopherAtl/talk/talk.lua | 2 +- .../fredthead/protector/protector.lua | 220 +++++----- .../nitrogenfingers/goldrunner/goldrunner.lua | 156 +++---- .../nitrogenfingers/npaintpro/3dprint.lua | 16 +- .../nitrogenfingers/npaintpro/gameutils.lua | 92 ++-- .../nitrogenfingers/npaintpro/npaintpro.lua | 406 +++++++++--------- .../treasure/vilsol/gameoflife/gameoflife.lua | 2 +- src/test/resources/test-rom/mcfly.lua | 2 +- .../test-rom/spec/programs/delete_spec.lua | 2 +- .../test-rom/spec/programs/edit_spec.lua | 2 +- .../spec/programs/http/pastebin_spec.lua | 2 +- .../test-rom/spec/programs/id_spec.lua | 2 +- .../test-rom/spec/programs/motd_spec.lua | 2 +- .../test-rom/spec/programs/set_spec.lua | 6 +- .../test-rom/spec/programs/time_spec.lua | 2 +- tools/check-lines.py | 28 ++ 68 files changed, 759 insertions(+), 728 deletions(-) create mode 100644 tools/check-lines.py diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index d0caedbf2..d499cd33f 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -37,3 +37,6 @@ jobs: test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/bin/illuaminate chmod +x bin/illuaminate bin/illuaminate lint + + - name: Check whitespace + run: python3 tools/check-lines.py diff --git a/src/main/resources/assets/computercraft/lua/rom/help/adventure.txt b/src/main/resources/assets/computercraft/lua/rom/help/adventure.txt index bd1d982cf..6a9880eba 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/adventure.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/adventure.txt @@ -1 +1 @@ -adventure is a text adventure game for CraftOS. To navigate around the world of adventure, type simple instructions to the interpreter, for example: "go north", "punch tree", "craft planks", "mine coal with pickaxe", "hit creeper with sword" \ No newline at end of file +adventure is a text adventure game for CraftOS. To navigate around the world of adventure, type simple instructions to the interpreter, for example: "go north", "punch tree", "craft planks", "mine coal with pickaxe", "hit creeper with sword" diff --git a/src/main/resources/assets/computercraft/lua/rom/help/alias.txt b/src/main/resources/assets/computercraft/lua/rom/help/alias.txt index 4d11d45ce..8f742bd3f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/alias.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/alias.txt @@ -3,4 +3,4 @@ alias assigns shell commands to run other programs. ex: "alias dir ls" will make the "dir" command run the "ls" program "alias dir" will remove the alias set on "dir" -"alias" will list all current aliases. \ No newline at end of file +"alias" will list all current aliases. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/chat.txt b/src/main/resources/assets/computercraft/lua/rom/help/chat.txt index 1e99ca45c..035cb463d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/chat.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/chat.txt @@ -2,4 +2,4 @@ Surf the rednet superhighway with "chat", the networked chat program for CraftOS ex: "chat host forgecraft" will create a chatroom with the name "forgecraft" -"chat join forgecraft direwolf20" will connect to the chatroom with the name "forgecraft", using the nickname "direwolf20" \ No newline at end of file +"chat join forgecraft direwolf20" will connect to the chatroom with the name "forgecraft", using the nickname "direwolf20" diff --git a/src/main/resources/assets/computercraft/lua/rom/help/clear.txt b/src/main/resources/assets/computercraft/lua/rom/help/clear.txt index ea517ddb3..6e3258411 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/clear.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/clear.txt @@ -1 +1 @@ -clear clears the screen. \ No newline at end of file +clear clears the screen. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/coroutine.txt b/src/main/resources/assets/computercraft/lua/rom/help/coroutine.txt index 12b366bd2..93d8f7b04 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/coroutine.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/coroutine.txt @@ -1,2 +1,2 @@ coroutine is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/dance.txt b/src/main/resources/assets/computercraft/lua/rom/help/dance.txt index 3c776f8f0..cef419ab9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/dance.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/dance.txt @@ -1 +1 @@ -dance is a program for Turtles. Turtles love to get funky. \ No newline at end of file +dance is a program for Turtles. Turtles love to get funky. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/disk.txt b/src/main/resources/assets/computercraft/lua/rom/help/disk.txt index f47bc625c..3c1348e6b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/disk.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/disk.txt @@ -14,4 +14,4 @@ disk.getID( drive ) Events fired by the disk API: "disk" when a disk or other item is inserted into a disk drive. Argument is the name of the drive "disk_eject" when a disk is removed from a disk drive. Argument is the name of the drive -Type "help events" to learn about the event system. \ No newline at end of file +Type "help events" to learn about the event system. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/dj.txt b/src/main/resources/assets/computercraft/lua/rom/help/dj.txt index 2c7a02bd1..c41dccc6e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/dj.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/dj.txt @@ -3,4 +3,4 @@ dj plays Music Discs from disk drives attached to the computer. ex: "dj" or "dj play" plays a random disc. "dj play left" plays the disc in the drive on the left of the computer. -"dj stop" stops the current disc. \ No newline at end of file +"dj stop" stops the current disc. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/drive.txt b/src/main/resources/assets/computercraft/lua/rom/help/drive.txt index 397c98c30..eb6472a8e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/drive.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/drive.txt @@ -2,4 +2,4 @@ drive tells you which disk drive the current or specified directory is located i ex: "drive" tell you the disk drive of the current directory. -"drive foo" tells you the disk drive of the subdirectory "foo" \ No newline at end of file +"drive foo" tells you the disk drive of the subdirectory "foo" diff --git a/src/main/resources/assets/computercraft/lua/rom/help/drives.txt b/src/main/resources/assets/computercraft/lua/rom/help/drives.txt index 6f15f40f3..b793f8e7d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/drives.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/drives.txt @@ -16,4 +16,4 @@ getDiskID() Events fired by the Disk Drive: "disk" when a disk or other item is inserted into the drive. Argument is the name of the drive. "disk_eject" when a disk is removed from a drive. Argument is the name of the drive. -Type "help events" to learn about the event system. \ No newline at end of file +Type "help events" to learn about the event system. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/earth.txt b/src/main/resources/assets/computercraft/lua/rom/help/earth.txt index d1b452673..b9842d064 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/earth.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/earth.txt @@ -1 +1 @@ -Mostly harmless. \ No newline at end of file +Mostly harmless. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/edit.txt b/src/main/resources/assets/computercraft/lua/rom/help/edit.txt index 31d044496..6e89a7e08 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/edit.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/edit.txt @@ -1,4 +1,4 @@ edit is a text editor for creating or modifying programs or text files. After creating a program with edit, type its filename in the shell to run it. You can open any of the builtin programs with edit to learn how to program. ex: -"edit hello" opens a file called "hello" for editing. \ No newline at end of file +"edit hello" opens a file called "hello" for editing. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/exit.txt b/src/main/resources/assets/computercraft/lua/rom/help/exit.txt index 9b6c4347f..891745139 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/exit.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/exit.txt @@ -1 +1 @@ -exit will exit the current shell. \ No newline at end of file +exit will exit the current shell. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/gps.txt b/src/main/resources/assets/computercraft/lua/rom/help/gps.txt index e3e14b566..35b833580 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/gps.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/gps.txt @@ -4,7 +4,7 @@ Type "help gpsapi" for help using GPS functions in lua programs. ex: "gps locate" will connect to nearby GPS servers, and try to determine the position of the computer or turtle. "gps host" will try to determine the position, and host a GPS server if successful. -"gps host 10 20 30" will host a GPS server, using the manually entered position 10,20,30. +"gps host 10 20 30" will host a GPS server, using the manually entered position 10,20,30. Take care when manually entering host positions. If the positions entered into multiple GPS hosts -are not consistent, the results of locate calls will be incorrect. \ No newline at end of file +are not consistent, the results of locate calls will be incorrect. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/gpsapi.txt b/src/main/resources/assets/computercraft/lua/rom/help/gpsapi.txt index 7bb9fe601..83116f669 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/gpsapi.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/gpsapi.txt @@ -1,4 +1,4 @@ Functions in the GPS API: gps.locate( timeout ) -The locate function will send a signal to nearby gps servers, and wait for responses before the timeout. If it receives enough responses to determine this computers position then x, y and z co-ordinates will be returned, otherwise it will return nil. If GPS hosts do not have their positions configured correctly, results will be inaccurate. \ No newline at end of file +The locate function will send a signal to nearby gps servers, and wait for responses before the timeout. If it receives enough responses to determine this computers position then x, y and z co-ordinates will be returned, otherwise it will return nil. If GPS hosts do not have their positions configured correctly, results will be inaccurate. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/hello.txt b/src/main/resources/assets/computercraft/lua/rom/help/hello.txt index a58ae9908..0f2017aad 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/hello.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/hello.txt @@ -1 +1 @@ -hello prints the text "Hello World!" to the screen. \ No newline at end of file +hello prints the text "Hello World!" to the screen. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/help.txt b/src/main/resources/assets/computercraft/lua/rom/help/help.txt index fe85a2370..29c0b3a32 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/help.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/help.txt @@ -1,4 +1,4 @@ help is the help tool you're currently using. Type "help index" to see all help topics. Type "help" to see the help intro. -Type "help helpapi" for information on the help Lua API. \ No newline at end of file +Type "help helpapi" for information on the help Lua API. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/id.txt b/src/main/resources/assets/computercraft/lua/rom/help/id.txt index f87492bee..e23f1290a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/id.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/id.txt @@ -2,4 +2,4 @@ id prints the unique identifier of this computer, or a Disk in an attached Disk ex: "id" will print this Computers ID and label -"id left" will print the ID and label of the disk in the Disk Drive on the left \ No newline at end of file +"id left" will print the ID and label of the disk in the Disk Drive on the left diff --git a/src/main/resources/assets/computercraft/lua/rom/help/io.txt b/src/main/resources/assets/computercraft/lua/rom/help/io.txt index f71cca207..8da72cbd1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/io.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/io.txt @@ -1,2 +1,2 @@ io is a standard Lua5.1 API, reimplemented for CraftOS. Not all the features are availiable. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/keys.txt b/src/main/resources/assets/computercraft/lua/rom/help/keys.txt index 0adb2016c..a46f10731 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/keys.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/keys.txt @@ -3,7 +3,7 @@ The keys API contains constants for all the key codes that can be returned by th Example usage: local sEvent, nKey = os.pullEvent() if sEvent == "key" and nKey == keys.enter then - -- Do something + -- Do something end -See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference. \ No newline at end of file +See http://www.minecraftwiki.net/wiki/Key_codes, or the source code, for a complete reference. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/list.txt b/src/main/resources/assets/computercraft/lua/rom/help/list.txt index 9ab8cd06c..16c0fdf52 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/list.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/list.txt @@ -1 +1 @@ -ls will list all the directories and files in the current location. Use "type" to find out if an item is a file or a directory. \ No newline at end of file +ls will list all the directories and files in the current location. Use "type" to find out if an item is a file or a directory. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/lua.txt b/src/main/resources/assets/computercraft/lua/rom/help/lua.txt index da1cb187a..4d164c8b0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/lua.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/lua.txt @@ -1 +1 @@ -lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language. \ No newline at end of file +lua is an interactive prompt for the lua programming language. It's a useful tool for learning the language. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/math.txt b/src/main/resources/assets/computercraft/lua/rom/help/math.txt index ed3da1e49..35ed34827 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/math.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/math.txt @@ -1,2 +1,2 @@ math is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/mkdir.txt b/src/main/resources/assets/computercraft/lua/rom/help/mkdir.txt index e7268dc63..e5e8fdab3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/mkdir.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/mkdir.txt @@ -2,4 +2,4 @@ mkdir creates a directory in the current location. ex: "mkdir foo" creates a directory named "foo". -"mkdir ../foo" creates a directory named "foo" in the directory above the current directory. \ No newline at end of file +"mkdir ../foo" creates a directory named "foo" in the directory above the current directory. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/modems.txt b/src/main/resources/assets/computercraft/lua/rom/help/modems.txt index 960bc5058..281a87582 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/modems.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/modems.txt @@ -9,4 +9,4 @@ transmit( channel, replyChannel, message ) isWireless() Events fired by Modems: -"modem_message" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance \ No newline at end of file +"modem_message" when a message is received on an open channel. Arguments are name, channel, replyChannel, message, distance diff --git a/src/main/resources/assets/computercraft/lua/rom/help/monitor.txt b/src/main/resources/assets/computercraft/lua/rom/help/monitor.txt index 6837b38d4..028a8bc80 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/monitor.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/monitor.txt @@ -3,4 +3,4 @@ Type "help monitors" for help using monitors as peripherals in lua programs. ex: "monitor left hello" will run the "hello" program on the monitor to the left of the computer. -"monitor top edit foo" will run the edit program on the top monitor, editing the file "foo". \ No newline at end of file +"monitor top edit foo" will run the edit program on the top monitor, editing the file "foo". diff --git a/src/main/resources/assets/computercraft/lua/rom/help/multishell.txt b/src/main/resources/assets/computercraft/lua/rom/help/multishell.txt index b16243112..8fbf8d75b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/multishell.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/multishell.txt @@ -1,2 +1,2 @@ multishell is the toplevel program on Advanced Computers which manages background tabs. -Type "help shellapi" for information about the shell lua api. \ No newline at end of file +Type "help shellapi" for information about the shell lua api. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/os.txt b/src/main/resources/assets/computercraft/lua/rom/help/os.txt index 442d4a89b..b57bef8da 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/os.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/os.txt @@ -23,4 +23,4 @@ os.reboot() Events emitted by the os API: "timer" when a timeout started by os.startTimer() completes. Argument is the token returned by os.startTimer(). "alarm" when a time passed to os.setAlarm() is reached. Argument is the token returned by os.setAlarm(). -Type "help events" to learn about the event system. \ No newline at end of file +Type "help events" to learn about the event system. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/parallel.txt b/src/main/resources/assets/computercraft/lua/rom/help/parallel.txt index 822dd47a7..4b958c442 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/parallel.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/parallel.txt @@ -1,4 +1,4 @@ Functions in the Parallel API: parallel.waitForAny( function1, function2, ... ) parallel.waitForAll( function1, function2, ... ) -These methods provide an easy way to run multiple lua functions simultaneously. \ No newline at end of file +These methods provide an easy way to run multiple lua functions simultaneously. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/pocket.txt b/src/main/resources/assets/computercraft/lua/rom/help/pocket.txt index fc498c669..72925bdea 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/pocket.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/pocket.txt @@ -3,4 +3,4 @@ Functions in the pocket API: pocket.equipBack() pocket.unequipBack() -When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand. \ No newline at end of file +When equipping upgrades, it will search your inventory for a suitable upgrade, starting in the selected slot. If one cannot be found then it will check your offhand. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/printers.txt b/src/main/resources/assets/computercraft/lua/rom/help/printers.txt index a855ab972..73295344e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/printers.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/printers.txt @@ -9,4 +9,4 @@ getPageSize() setCursorPos( x, y ) getCursorPos() write( text ) -endPage() \ No newline at end of file +endPage() diff --git a/src/main/resources/assets/computercraft/lua/rom/help/programming.txt b/src/main/resources/assets/computercraft/lua/rom/help/programming.txt index 68e8621fc..4a14fb2e3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/programming.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/programming.txt @@ -8,4 +8,4 @@ To quickly shutdown a computer, hold Ctrl+S for 1 second. To quickly reboot a computer, hold Ctrl+R for 1 second. To learn about the programming APIs availiable, type "apis" or "help apis". -If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials. \ No newline at end of file +If you get stuck, visit the forums at http://www.computercraft.info/ for advice and tutorials. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/reboot.txt b/src/main/resources/assets/computercraft/lua/rom/help/reboot.txt index 6cae9184d..525c9c979 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/reboot.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/reboot.txt @@ -1,2 +1,2 @@ reboot will turn the computer off and on again. -You can also hold Ctrl+R at any time to quickly reboot. \ No newline at end of file +You can also hold Ctrl+R at any time to quickly reboot. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/redstone.txt b/src/main/resources/assets/computercraft/lua/rom/help/redstone.txt index ea76f7827..ce86bb6b4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/redstone.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/redstone.txt @@ -6,4 +6,4 @@ ex: "redstone set right blue false" turns off the blue wire in the bundled cable on the right redstone output. "redstone pulse front 10 1" emits 10 one second redstone pulses on the front redstone output. -Type "help redstoneapi" or "help rs" for information on the redstone Lua API. \ No newline at end of file +Type "help redstoneapi" or "help rs" for information on the redstone Lua API. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/refuel.txt b/src/main/resources/assets/computercraft/lua/rom/help/refuel.txt index 9fab3fa18..86e806b2c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/refuel.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/refuel.txt @@ -3,4 +3,4 @@ refuel is a program for Turtles. Refuel will consume items from the inventory as ex: "refuel" will refuel with at most one fuel item "refuel 10" will refuel with at most 10 fuel items -"refuel all" will refuel with as many fuel items as possible \ No newline at end of file +"refuel all" will refuel with as many fuel items as possible diff --git a/src/main/resources/assets/computercraft/lua/rom/help/repeat.txt b/src/main/resources/assets/computercraft/lua/rom/help/repeat.txt index f65697d4a..a08ebf8da 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/repeat.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/repeat.txt @@ -1 +1 @@ -repeat is a program for repeating rednet messages across long distances. To use, connect 2 or more modems to a computer and run the "repeat" program; from then on, any rednet message sent from any computer in wireless range or connected by networking cable to either of the modems will be repeated to those on the other side. \ No newline at end of file +repeat is a program for repeating rednet messages across long distances. To use, connect 2 or more modems to a computer and run the "repeat" program; from then on, any rednet message sent from any computer in wireless range or connected by networking cable to either of the modems will be repeated to those on the other side. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/shell.txt b/src/main/resources/assets/computercraft/lua/rom/help/shell.txt index 080b8390a..9be848561 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/shell.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/shell.txt @@ -1,2 +1,2 @@ shell is the toplevel program which interprets commands and runs program. -Type "help shellapi" for information about the shell lua api. \ No newline at end of file +Type "help shellapi" for information about the shell lua api. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/shutdown.txt b/src/main/resources/assets/computercraft/lua/rom/help/shutdown.txt index 4a63391db..8bc734fc9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/shutdown.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/shutdown.txt @@ -1 +1 @@ -shutdown will turn off the computer. \ No newline at end of file +shutdown will turn off the computer. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/string.txt b/src/main/resources/assets/computercraft/lua/rom/help/string.txt index 5dfe5d501..ce30dc916 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/string.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/string.txt @@ -1,2 +1,2 @@ string is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/table.txt b/src/main/resources/assets/computercraft/lua/rom/help/table.txt index 80760d0de..d6943d035 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/table.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/table.txt @@ -1,2 +1,2 @@ table is a standard Lua5.1 API. -Refer to http://www.lua.org/manual/5.1/ for more information. \ No newline at end of file +Refer to http://www.lua.org/manual/5.1/ for more information. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/time.txt b/src/main/resources/assets/computercraft/lua/rom/help/time.txt index ae5113599..4a67ab57d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/time.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/time.txt @@ -1 +1 @@ -time prints the current time of day. \ No newline at end of file +time prints the current time of day. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/type.txt b/src/main/resources/assets/computercraft/lua/rom/help/type.txt index 74a4e8e79..1c8cad512 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/type.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/type.txt @@ -1 +1 @@ -type determines the type of a file or directory. Prints "file", "directory" or "does not exist". \ No newline at end of file +type determines the type of a file or directory. Prints "file", "directory" or "does not exist". diff --git a/src/main/resources/assets/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua b/src/main/resources/assets/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua index 03431406c..8d48eaaf5 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua @@ -1,8 +1,8 @@ --[[ battleship, - + by GopherAtl, 2013 - + Do whatever you want, just don't judge me by what a mess this code is. --]] @@ -17,21 +17,21 @@ local myTurn local targetX,targetY local shipsLeft=5 local oppShipsLeft=5 - + local originalTerm = term.current() - + --bounding box of the target grid local targetGridBounds={ minX=16, maxX=25, minY=4, maxY=13 } - - + + local function doColor(text,background) term.setTextColor(text) term.setBackgroundColor(background) end - + local function doColor_mono(text,background) if text==colors.blue or text==colors.red or text==colors.black or text==colors.lime or background==colors.lightGray then term.setTextColor(colors.black) @@ -39,9 +39,9 @@ local function doColor_mono(text,background) else term.setTextColor(colors.white) term.setBackgroundColor(colors.black) - end + end end - + local function doScreenColor() if term.isColor() then doColor(colors.white,colors.lightGray) @@ -49,16 +49,16 @@ local function doScreenColor() doColor(colors.black,colors.white) end end - + local function toGridRef(x,y) return string.sub("ABCDEFGHIJ",x,x)..string.sub("1234567890",y,y) end - - + + if not term.isColor() then doColor=doColor_mono end - + local function quit() if openedSide then rednet.close(openedSide) @@ -68,7 +68,7 @@ local function quit() print() error() end - + local foundModem=false --find modem for k,v in pairs(redstone.getSides()) do @@ -81,17 +81,17 @@ for k,v in pairs(redstone.getSides()) do break end end - + if not foundModem then print("You must have a modem to play!") return end - + if action==nil or (action~="join" and action~="host") then print("Invalid parameters. Usage:\n> battleship host\nHosts a game, waits for another computer to join\n> battleship join\nLooks for another game to join") quit() end - + --get player name while true do doColor(colors.cyan,colors.black) @@ -108,13 +108,13 @@ while true do break end end - + if action=="join" then print("Attempting to join a game...\n(press q to cancel)") while true do local retryTimer=os.startTimer(1); rednet.broadcast("bs join "..myName); - + while true do local event,p1,p2,p3=os.pullEvent(); if event=="rednet_message" then @@ -131,7 +131,7 @@ if action=="join" then end end local joined=false - + if opponentID then print("Joining game!") rednet.send(opponentID,"bs start") @@ -142,7 +142,7 @@ elseif action=="host" then print("Waiting for challenger...\n(Press q to cancel)") while true do while true do - local event,p1,p2=os.pullEvent() + local event,p1,p2=os.pullEvent() if event=="rednet_message" then opponent=string.match(p2,"bs join %s*(.+)%s*") if opponent then print("found player, inviting..") @@ -154,7 +154,7 @@ elseif action=="host" then quit() end end - + if opponentID then rednet.send(opponentID,"bs accept "..myName) local timeout=os.startTimer(1) @@ -166,17 +166,17 @@ elseif action=="host" then elseif event=="timer" and p1==timeout then print("player joined another game. Waiting for another...") opponentID=nil - break + break end end - + if opponentID then break end end end end - + local ships={ {pos=nil,dir="h",size=5,name="carrier",hits=0}, {pos=nil,dir="h",size=4,name="battleship",hits=0}, @@ -184,12 +184,12 @@ local ships={ {pos=nil,dir="h",size=3,name="submarine",hits=0}, {pos=nil,dir="h",size=2,name="destroyer",hits=0}, } - + local myShotTable={ {1,1,true},{5,5,false} } local oppShotTable={ } - + local myGrid,oppGrid={title=myName},{title=opponent} - + --setup grids for i=1,10 do myGrid[i]={} @@ -199,8 +199,8 @@ for i=1,10 do oppGrid[i][j]={hit=false,ship=false} end end - -local function drawShipsToGrid(ships,grid) + +local function drawShipsToGrid(ships,grid) for i=1,#ships do local x,y=table.unpack(ships[i].pos) local stepX=ships[i].dir=="h" and 1 or 0 @@ -211,18 +211,18 @@ local function drawShipsToGrid(ships,grid) end end end - + local function drawShotToGrid(shot,grid) grid[shot[1]][shot[2]].shot=true - grid[shot[1]][shot[2]].hit=shot[3] + grid[shot[1]][shot[2]].hit=shot[3] end - + local function makeShot(x,y,grid) local tile=grid[x][y] if tile.shot==true then return nil --already shot here! - end - + end + local shot={x,y,tile.ship} drawShotToGrid(shot,grid) if tile.ship then @@ -232,12 +232,12 @@ local function makeShot(x,y,grid) end end return shot -end - - +end + + local function drawTile(scrX,scrY,tile) term.setCursorPos(scrX,scrY) - + if tile.ship then if tile.shot then doColor(colors.red,colors.gray) @@ -259,31 +259,31 @@ local function drawTile(scrX,scrY,tile) end end end - + local function drawGrid(scrX,scrY,grid) doColor(colors.white,colors.black) term.setCursorPos(scrX,scrY+1) term.write(" ") - doColor(colors.white,colors.gray) + doColor(colors.white,colors.gray) term.setCursorPos(scrX,scrY) local pad=11-#grid.title term.write(string.rep(" ",math.ceil(pad/2))..grid.title..string.rep(" ",math.floor(pad/2))) - + for gx=1,10 do term.setTextColor(colors.white) term.setBackgroundColor(colors.black) term.setCursorPos(scrX+gx,scrY+1) term.write(gx==10 and "0" or string.char(string.byte("0")+gx)) - + term.setCursorPos(scrX,scrY+gx+1) term.write(string.char(string.byte("A")+gx-1)) for gy=1,10 do - drawTile(scrX+gx,scrY+gy+1,grid[gx][gy]) + drawTile(scrX+gx,scrY+gy+1,grid[gx][gy]) end end doColor(colors.white,colors.black) end - + function moveTargetIndicator(newX,newY) --if x has changed... if targetX and targetY then @@ -303,8 +303,8 @@ function moveTargetIndicator(newX,newY) term.write("^") term.setCursorPos(targetGridBounds.minX+newX-1,targetGridBounds.minY-3) term.write("v") - - targetX=newX + + targetX=newX end if newY~=targetY then --space over old @@ -319,11 +319,11 @@ function moveTargetIndicator(newX,newY) term.write("<") term.setCursorPos(targetGridBounds.minX-2,targetGridBounds.minY+newY-1) term.write(">") - + targetY=newY end term.setCursorPos(15,15) - term.write("Target : "..toGridRef(targetX,targetY)) + term.write("Target : "..toGridRef(targetX,targetY)) --if the target tile is a valid target, draw a "+" if not oppGrid[targetX][targetY].shot then term.setCursorPos(targetX+targetGridBounds.minX-1,targetY+targetGridBounds.minY-1) @@ -331,18 +331,18 @@ function moveTargetIndicator(newX,newY) term.write("+") end end - + local log={} - + local termWidth,termHeight=term.getSize() - + local logHeight=termHeight-3 local logWidth=termWidth-28 - + for i=1,logHeight do log[i]="" end - + local function printLog() doColor(colors.white,colors.black) for i=1,logHeight do @@ -358,9 +358,9 @@ local function printLog() end end end - - - + + + --shipX/Y are the position of ship on grid; gridX/Y are the offset of the top-left of grid local function drawShip(size,align,x,y,char) local stepX=align=="h" and 1 or 0 @@ -371,31 +371,31 @@ local function drawShip(size,align,x,y,char) x,y=x+stepX,y+stepY end end - + local function setStatusLine(lineNum,text) doScreenColor() local pad=math.floor((termWidth-#text)/2) term.setCursorPos(1,16+lineNum) term.write((" "):rep(pad)..text..(" "):rep(termWidth-#text-pad)) end - - + + doScreenColor() term.clear() - + drawGrid(2,2,myGrid) - + setStatusLine(1,"Started game with "..opponent.." at computer #"..(opponentID or "nil")) - + local function getShipBounds(ship) return { minX=ship.pos[1], minY=ship.pos[2], maxX=ship.pos[1]+(ship.dir=="h" and ship.size-1 or 0), maxY=ship.pos[2]+(ship.dir=="v" and ship.size-1 or 0) - } + } end - + local function getPointBounds(x,y) return { minX=x, @@ -404,20 +404,20 @@ local function getPointBounds(x,y) maxY=y, } end - + local function boundsIntersect(boundsA,boundsB) return not ( boundsA.minX>boundsB.maxX or boundsA.maxXboundsB.maxY or boundsA.maxY="0" and p1<="9" then local t=string.byte(p1)-string.byte("0") if t==0 then t=10 end - moveTargetIndicator(t,targetY) + moveTargetIndicator(t,targetY) end elseif e=="key" then if p1==keys.enter or p1==keys.space and targetX and targetY then @@ -736,7 +736,7 @@ local function runGame() moveTargetIndicator(math.max(targetX-1,1),targetY) elseif p1==keys.right then moveTargetIndicator(math.min(targetX+1,10),targetY) - end + end end end --shot sent, wait for my turn to resolve (top coroutine will switch turns and draw the hit to the grid) @@ -746,12 +746,12 @@ local function runGame() end end end - + local gameRoutine=coroutine.create(runGame) --if advanced terminal, default focus to chat, can play with mouse local inChat=term.isColor() local savedCursorPos={7,19} - + --redirect just to block scroll local redir={} for k,v in pairs(originalTerm) do @@ -762,12 +762,12 @@ for k,v in pairs(originalTerm) do end end originalTerm = term.redirect(redir) - + --run the game routine once coroutine.resume(gameRoutine) --hide cursor term.setCursorBlink(false) - + while true do local e,p1,p2,p3,p4,p5=os.pullEventRaw() if e=="terminate" then @@ -791,7 +791,7 @@ while true do opponentReady=true os.queueEvent("kickcoroutine") elseif cmd=="cointoss" then - myTurn=args=="true" + myTurn=args=="true" if myTurn then setStatusLine(2,"Your turn, take your shot!") else @@ -807,11 +807,11 @@ while true do local tile=myGrid[tx][ty] local shot=makeShot(tx,ty,myGrid) rednet.send(opponentID,"bs result "..(shot[3] and "hit" or "miss")) - drawTile(2+tx,3+ty,tile) + drawTile(2+tx,3+ty,tile) myTurn=true os.queueEvent("kickcoroutine") displayGameHelp() - setStatusLine(1,opponent.." fired at "..toGridRef(tx,ty).." and "..(shot[3] and "hit" or "missed")) + setStatusLine(1,opponent.." fired at "..toGridRef(tx,ty).." and "..(shot[3] and "hit" or "missed")) setStatusLine(2,"Your turn, take your shot!") end elseif cmd=="sink" then @@ -838,7 +838,7 @@ while true do setStatusLine(2,"Waiting for opponent...") os.queueEvent("kickcoroutine") end - + elseif cmd=="win" then --we won! setStatusLine(3,"You won the game! Congratulations!") @@ -852,24 +852,24 @@ while true do print("game coroutine crashed with the following error: "..err) quit() end - + if coroutine.status(gameRoutine)=="dead" then --game over break end end - + end - + term.setCursorPos(1,19) term.clearLine() term.write(" Press any key to continue...") os.pullEvent("key") --if a char event was queued following the key event, this will eat it os.sleep(0) - + term.setTextColor(colors.white) term.setBackgroundColor(colors.black) term.clear() quit() --- \ No newline at end of file +-- diff --git a/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua b/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua index b8de7b147..7ec78c299 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua @@ -1,8 +1,8 @@ --- +-- -- Lua IDE -- Made by GravityScore --- +-- -- -------- Variables @@ -44,7 +44,7 @@ local function isAdvanced() return term.isColor and term.isColor() end local function modRead(properties) local w, h = term.getSize() - local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, + local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, liveUpdates = nil, exitOnKey = nil} if not properties then properties = {} end for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end @@ -58,7 +58,7 @@ local function modRead(properties) local function redraw(repl) local scroll = 0 - if properties.visibleLength and sx + pos > properties.visibleLength + 1 then + if properties.visibleLength and sx + pos > properties.visibleLength + 1 then scroll = (sx + pos) - (properties.visibleLength + 1) end @@ -133,9 +133,9 @@ local function modRead(properties) elseif (but == keys.up or but == keys.down) and properties.history then redraw(" ") if but == keys.up then - if historyPos == nil and #properties.history > 0 then + if historyPos == nil and #properties.history > 0 then historyPos = #properties.history - elseif historyPos > 1 then + elseif historyPos > 1 then historyPos = historyPos - 1 end elseif but == keys.down then @@ -173,9 +173,9 @@ local function modRead(properties) elseif but == keys["end"] then pos = line:len() redraw() - elseif properties.exitOnKey then - if but == properties.exitOnKey or (properties.exitOnKey == "control" and - (but == 29 or but == 157)) then + elseif properties.exitOnKey then + if but == properties.exitOnKey or (properties.exitOnKey == "control" and + (but == 29 or but == 157)) then term.setCursorBlink(false) return nil end @@ -296,7 +296,7 @@ end local function centerRead(wid, begt) local function liveUpdate(line, e, but, x, y, p4, p5) - if isAdvanced() and e == "mouse_click" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10 + if isAdvanced() and e == "mouse_click" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10 and y >= 13 and y <= 15 then return true, "" end @@ -707,7 +707,7 @@ languages.brainfuck.mapLoops = function(code) loopLocations[loc] = true elseif let == "]" then local found = false - for i = loc, 1, -1 do + for i = loc, 1, -1 do if loopLocations[i] == true then loopLocations[i] = loc found = true @@ -877,7 +877,7 @@ local function run(path, lines, useArgs) local s = centerRead(w - 13, fs.getName(path) .. " ") for m in string.gmatch(s, "[^ \t]+") do ar[#ar + 1] = m:gsub("^%s*(.-)%s*$", "%1") end end - + saveFile(path, lines) term.setCursorBlink(false) term.setBackgroundColor(colors.black) @@ -949,7 +949,7 @@ local function run(path, lines, useArgs) term.setCursorPos(5, 14) term.write(b) end - + local opt = prompt({{"Error Help", w/2 - 15, 17}, {"Go To Line", w/2 + 2, 17}}, "horizontal") if opt == "Error Help" then @@ -1459,7 +1459,7 @@ end local function writeHighlighted(line) if curLanguage == languages.lua then - while line:len() > 0 do + while line:len() > 0 do line = attemptToHighlight(line, "^%-%-%[%[.-%]%]", colors[theme.comment]) or attemptToHighlight(line, "^%-%-.*", colors[theme.comment]) or attemptToHighlight(line, "^\".*[^\\]\"", colors[theme.string]) or @@ -1491,7 +1491,7 @@ local function draw() for i = 1, edh do local a = lines[scrolly + i] if a then - local ln = string.rep(" ", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i) + local ln = string.rep(" ", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i) local l = a:sub(scrollx + 1, edw + scrollx + 1) ln = ln .. ":" @@ -1541,7 +1541,7 @@ local function drawLine(...) for _, ly in pairs(ls) do local a = lines[ly] if a then - local ln = string.rep(" ", offx - 1 - tostring(ly):len()) .. tostring(ly) + local ln = string.rep(" ", offx - 1 - tostring(ly):len()) .. tostring(ly) local l = a:sub(scrollx + 1, edw + scrollx + 1) ln = ln .. ":" @@ -1651,7 +1651,7 @@ local function edit(path) draw() term.setCursorPos(x + offx, y + offy) term.setCursorBlink(true) - + -- Main loop local tid = os.startTimer(3) while true do @@ -1692,8 +1692,8 @@ local function edit(path) if f then table.insert(lines, y + 1, string.rep(" ", spaces + 2)) if not f:find("else", 1, true) and not f:find("elseif", 1, true) then - table.insert(lines, y + 2, string.rep(" ", spaces) .. - (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or + table.insert(lines, y + 2, string.rep(" ", spaces) .. + (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or "end")) end x, y = spaces + 3, y + 1 @@ -1771,7 +1771,7 @@ local function edit(path) x = math.min(lines[y]:len() + 1, x) cursorLoc(x, y, true) end - elseif e == "char" and allowEditorEvent and (displayCode and true or + elseif e == "char" and allowEditorEvent and (displayCode and true or y + scrolly - 1 == liveErr.line) then local shouldIgnore = false for k, v in pairs(liveCompletions) do @@ -2083,7 +2083,7 @@ local function changeTheme() sleep(1.6) return "menu" end - + term.write("LuaIDE - Could Not Load Theme!") fs.delete("/.LuaIDE_temp_theme_file") sleep(1.6) @@ -2100,7 +2100,7 @@ local function settings() title("LuaIDE - Settings") local opt = prompt({{"Change Theme", w/2 - 17, 8}, {"Return to Menu", w/2 - 19, 13}, - --[[{"Check for Updates", w/2 + 2, 8},]] {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err], + --[[{"Check for Updates", w/2 + 2, 8},]] {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err], highlight = colors[theme.errHighlight]}}, "vertical", true) if opt == "Change Theme" then return changeTheme() -- elseif opt == "Check for Updates" then return update() @@ -2189,7 +2189,7 @@ if err and not err:find("Terminated") then term.write("Please report this error to") term.setCursorPos(6, cy + 3) term.write("GravityScore! ") - + term.setBackgroundColor(colors[theme.background]) if isAdvanced() then centerPrint("Click to Exit...", h - 1) else centerPrint("Press Any Key to Exit...", h - 1) end diff --git a/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze2d.lua b/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze2d.lua index ccc85fb29..be942df95 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze2d.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze2d.lua @@ -1,6 +1,6 @@ --[[ Project info: - + Name: Maze Creator: Jesusthekiller Language: Lua (CC) @@ -24,7 +24,7 @@ --[[ LICENSE: - + Maze Copyright (c) 2013 Jesusthekiller @@ -73,7 +73,7 @@ repeat cwrite("Enter maze size (5-99):") size = read() - + size = tonumber(size) if not size then size = 0 @@ -82,18 +82,18 @@ until size > 4 and size < 100 -- The generate local function mazeGen(mx, my) - + --[[ Format: - + maze.x.y.(1/2/3/4) = true/false - + 1 - top 2 - bottom 3 - right 4 - left ]]-- - + local maze = {} for i = 1, mx do maze[i] = {} @@ -116,26 +116,26 @@ local function mazeGen(mx, my) local intact = {} local x = curr.x local y = curr.y - + if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells intact[#intact+1] = {x-1, y, 1} end - + if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then intact[#intact+1] = {x+1, y, 2} end - + if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then intact[#intact+1] = {x, y+1, 3} end - + if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then intact[#intact+1] = {x, y-1, 4} end - + if #intact > 0 then local i = math.random(1, #intact) -- Choose random - + if intact[i][3] == 1 then -- Set intact's attached wall to false maze[intact[i][1]][intact[i][2]][2] = false elseif intact[i][3] == 2 then @@ -145,11 +145,11 @@ local function mazeGen(mx, my) elseif intact[i][3] == 4 then maze[intact[i][1]][intact[i][2]][3] = false end - + maze[x][y][intact[i][3]] = false -- Set attached wall to false - + vis = vis + 1 -- Increase vis - + stack[#stack+1] = intact[i] -- Add to stack else local tmp = table.remove(stack) -- Get last cell @@ -157,7 +157,7 @@ local function mazeGen(mx, my) curr.y = tmp[2] end end - + return maze end @@ -177,7 +177,7 @@ local tab = {} for x = 1, size * 2 + 1 do tab[x] = {} - + for y = 1, size * 2 + 1 do if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty) tab[x][y] = false @@ -201,7 +201,7 @@ repeat -- Print map term.setBackgroundColor(colors.white) term.clear() - + if posx == 2 and posy == 2 then term.setCursorPos(1, 1) term.setTextColor(colors.black) @@ -211,27 +211,27 @@ repeat print("Goal: Step on # (It's on bottom right corner)") print("\nGood Luck!") end - + --[[ term.setTextColor(colors.black) term.setCursorPos(1, 19) write("X: "..posx.." Y: "..posy) ]] - + for x, tV in ipairs(tab) do -- Print the map for y, v in ipairs(tV) do if offsety+y > 20 then break end - + term.setCursorPos(offsetx+x, offsety+y) - + if v then term.setBackgroundColor(colors.black) else term.setBackgroundColor(colors.white) end - + if offsety+y < 20 and offsety+y > 0 and offsetx+x < 52 and offsetx+x > 0 then if x == size*2 and y == size*2 then if term.isColor() then @@ -243,51 +243,51 @@ repeat end end end - + if offsetx+x > 51 then break end - end - + end + term.setCursorPos(51/2, 19/2) term.setBackgroundColor(colors.white) - + if term.isColor() then term.setTextColor(colors.red) else term.setTextColor(colors.black) end - + write("X") - + -- Wait for key - + local e, k = os.pullEvent("char") - + if k == "a" and (not tab[posx-1][posy]) then posx = posx - 1 offsetx = offsetx + 1 end - + if k == "d" and (not tab[posx+1][posy]) then posx = posx + 1 offsetx = offsetx - 1 end - + if k == "w" and (not tab[posx][posy-1]) then posy = posy - 1 offsety = offsety + 1 end - + if k == "s" and (not tab[posx][posy+1]) then posy = posy + 1 offsety = offsety - 1 end - + if k == "q" then break end - + if k == "r" then posx = 2 posy = 2 @@ -324,4 +324,4 @@ term.setBackgroundColor(colors.black) term.setTextColor(colors.white) term.clear() term.setCursorPos(1, 1) -cprint(" Maze by JTK. Thanks for playing!") \ No newline at end of file +cprint(" Maze by JTK. Thanks for playing!") diff --git a/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze3d.lua b/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze3d.lua index 85343aeab..a8a04ee85 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze3d.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/JTK/maze3d/maze3d.lua @@ -1,6 +1,6 @@ --[[ Project info: - + Name: Maze 3D Creator: Jesusthekiller Language: Lua (CC) @@ -28,7 +28,7 @@ --[[ LICENSE: - + Maze 3D Copyright (c) 2013 Jesusthekiller @@ -78,7 +78,7 @@ repeat cwrite("Enter maze size (5-99):") size = read() - + size = tonumber(size) if not size then size = 0 @@ -87,18 +87,18 @@ until size > 4 and size < 100 -- The generate local function mazeGen(mx, my) - + --[[ Format: - + maze.x.y.(1/2/3/4) = true/false - + 1 - top 2 - bottom 3 - right 4 - left ]]-- - + local maze = {} for i = 1, mx do maze[i] = {} @@ -121,26 +121,26 @@ local function mazeGen(mx, my) local intact = {} local x = curr.x local y = curr.y - + if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells intact[#intact+1] = {x-1, y, 1} end - + if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then intact[#intact+1] = {x+1, y, 2} end - + if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then intact[#intact+1] = {x, y+1, 3} end - + if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then intact[#intact+1] = {x, y-1, 4} end - + if #intact > 0 then local i = math.random(1, #intact) -- Choose random - + if intact[i][3] == 1 then -- Set intact's attached wall to false maze[intact[i][1]][intact[i][2]][2] = false elseif intact[i][3] == 2 then @@ -150,11 +150,11 @@ local function mazeGen(mx, my) elseif intact[i][3] == 4 then maze[intact[i][1]][intact[i][2]][3] = false end - + maze[x][y][intact[i][3]] = false -- Set attached wall to false - + vis = vis + 1 -- Increase vis - + stack[#stack+1] = intact[i] -- Add to stack else local tmp = table.remove(stack) -- Get last cell @@ -162,7 +162,7 @@ local function mazeGen(mx, my) curr.y = tmp[2] end end - + return maze end @@ -180,7 +180,7 @@ local tab = {} for x = 1, size * 2 + 1 do tab[x] = {} - + for y = 1, size * 2 + 1 do if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty) tab[x][y] = " " @@ -263,13 +263,13 @@ if redirect then print("redirect API found, using buffer") else local pe=printError - rawset(_G,"printError",error) + rawset(_G,"printError",error) local ok, err=pcall(os.loadAPI,"redirect") if not ok then print("trying "..shell.dir().."/redirect") ok,err=pcall(os.loadAPI,shell.dir().."/redirect") end - if ok then + if ok then print("Loaded redirect API, using buffer") buffer=redirect.createRedirectBuffer() loadedAPI=true @@ -277,7 +277,7 @@ else print("redirect API not found or could not be loaded, drawing directly; this may cause flickering.") end rawset(_G,"printError",pe) -end +end local colorSchemes = { {0,8}, --white+gray @@ -338,10 +338,10 @@ local function cast(cx,cy,angle) end local wall=map[y]:sub(x,x) if wall~=" " then - + return colorSchemes[tonumber(wall)][isX and 1 or 2], hitD end - end + end end local w,h=term.getSize() @@ -370,7 +370,7 @@ for x=1,w do t.angle=math.atan2(x-centerX,screenDist) t.dist=((x-centerX)^2+screenDist^2)^.5/screenDist end - + local function redraw() local oldTerm if buffer.isBuffer then @@ -411,15 +411,15 @@ local function clampCollision(x,y,radius) --I am. Complete fail, do nothing. return x,y end - + --ok, check the neighbors. local right=math.floor(x+radius)>gx local left=math.floor(x-radius)gy - + local pushed=false - + if right and map[gy]:sub(gx+1,gx+1)~=" " then --push left pushed=true @@ -429,7 +429,7 @@ local function clampCollision(x,y,radius) pushed=true x=gx+radius end - + if front and map[gy-1]:sub(gx,gx)~=" " then --push back pushed=true @@ -442,7 +442,7 @@ local function clampCollision(x,y,radius) y=gy+1-radius end - + --if I wasn't pushed out on any side, I might be hitting a corner if not pushed then --square rad @@ -482,7 +482,7 @@ local function clampCollision(x,y,radius) x=x+pushx y=y+pushy end - + return x,y end @@ -533,7 +533,7 @@ while true do redraw() dirty=false end - + local e={os.pullEvent()} if e[1]=="key" then if e[2]==keys.left then @@ -565,7 +565,7 @@ while true do dir=startdir dirty=true end - + if px >= mapW-1 and py >= mapH-1 then win = true break diff --git a/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/get.lua b/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/get.lua index 6c95fbd6d..a8d7901d3 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/get.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/get.lua @@ -23,4 +23,4 @@ if fs.exists(args[1]) then else print("Client rejected file!") end -end \ No newline at end of file +end diff --git a/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua b/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua index a76aba8d6..df62694fc 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua @@ -718,4 +718,4 @@ elseif #args >= 1 then --either no server running or we are the local shell on t else print("Usage: nsh [resume]") print(" nsh host [remote [local [name]]]") -end \ No newline at end of file +end diff --git a/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/put.lua b/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/put.lua index 23e6a2e3c..a31fe0be9 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/put.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/Lyqyd/nsh/put.lua @@ -32,4 +32,4 @@ if message ~= "fileNotFound" then else print("Empty file not written!") end -end \ No newline at end of file +end diff --git a/src/main/resources/assets/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua b/src/main/resources/assets/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua index 8fdfbbf85..88e394b1e 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua @@ -124,7 +124,7 @@ end local function getAIMove() -- make it seem like the computer actually has to think about its move sleep(0.8) - + -- check if AI can win and return the 3rd tile to create a win, if it cannot, check for a human attempt at winning and stop it, if there is none, return a random return (search(currentPlayer) or search(opposites[currentPlayer])) or math.random(1,9) end @@ -177,7 +177,7 @@ local function modread( _mask, _history, _limit ) redraw(' ') if event[2] == keys.up then if not historyPos then - historyPos = #_history + historyPos = #_history elseif historyPos > 1 then historyPos = historyPos - 1 end @@ -308,14 +308,14 @@ local function render() writeAt('+'..string.rep('-', sw-2)..'+', 1, 3) writeAt('+'..string.rep('-', sw-2)..'+', 1, sh-2) writeAt('+'..string.rep('-', sw-2)..'+', 1, sh) - + if term.isColor and term.isColor() then term.setCursorPos(sw, 1) term.setBackgroundColor(colors.red) term.setTextColor(colors.black) writeWithFormat('X') end - + -- set our colours term.setBackgroundColor(colors.white) term.setTextColor(colors.black) @@ -359,7 +359,7 @@ local function render() writeAt((board[i + 6] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 14) end end - + -- draw the current player term.setCursorPos(3, sh - 3) if not winner then @@ -441,4 +441,4 @@ cwriteWithFormat('&4Thank you for playing CCTicTacToe v1.0', 1) cwriteWithFormat('&4By &8TheOriginal&3BIT\n', 2) -- restore the default terminal object -term.redirect( oldTermObj ) \ No newline at end of file +term.redirect( oldTermObj ) diff --git a/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua b/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua index bf126850d..dc1672f70 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua @@ -22,7 +22,7 @@ while not bFinished do break end - -- Get this every frame incase the monitor resizes + -- Get this every frame incase the monitor resizes local w,h = term.getSize() local startX = math.floor( (w - 65) / 2 ) local startY = math.floor( (h - 14) / 2 ) diff --git a/src/main/resources/assets/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua b/src/main/resources/assets/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua index ee7e8a8f8..c43fd6d4a 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua @@ -1 +1 @@ -print( "\"talk\" was removed in ComputerCraft 1.6, use the builtin \"chat\" program instead!" ) \ No newline at end of file +print( "\"talk\" was removed in ComputerCraft 1.6, use the builtin \"chat\" program instead!" ) diff --git a/src/main/resources/assets/computercraft/lua/treasure/fredthead/protector/protector.lua b/src/main/resources/assets/computercraft/lua/treasure/fredthead/protector/protector.lua index 255c238d1..bd88cee1d 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/fredthead/protector/protector.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/fredthead/protector/protector.lua @@ -27,11 +27,11 @@ function initVariables() human6x = 85 human6y = 18 human1 = true - human2 = true - human3 = true - human4 = true - human5 = true - human6 = true + human2 = true + human3 = true + human4 = true + human5 = true + human6 = true human1Abducted=false human2Abducted=false human3Abducted=false @@ -245,7 +245,7 @@ function printScore() end function rewriteScores() - if newScore > score1 then + if newScore > score1 then name5=name4 score5=score4 name4=name3 score4=score3 name3=name2 score3=score2 @@ -264,7 +264,7 @@ function rewriteScores() name5=name4 score5=score4 name4=newName score4=newScore elseif newScore > score5 then - name5=newName score5=newScore + name5=newName score5=newScore end local highScoreTable = {{name1, score1}, {name2,score2}, {name3,score3}, {name4,score4}, {name5,score5}} local newHighScoreStr = textutils.serialize(highScoreTable) @@ -289,7 +289,7 @@ function newHighScoreObtained() newNameStr=newNameStr..p1 newNameStrLen=newNameStrLen+1 printCent(14,newNameStr.." ") - + elseif event=="key" and p1 == 14 and newNameStrLen>0 then newNameStr=string.sub(newNameStr,1,string.len(newNameStr)-1) newNameStrLen=newNameStrLen-1 @@ -303,9 +303,9 @@ function newHighScoreObtained() printScore() end end - - + + end function highScore() @@ -327,8 +327,8 @@ function highScore() newHighScoreObtained() end printScore() - - + + end @@ -351,24 +351,24 @@ function gameOver(gameOverMsg) running=false sleep(1.5) highScore()-- new - --playAgain + --playAgain end function playAgain() sleep(1) printCent(12,"Play again (Y or N)") - + while true do local event,p1,p2,p3 = os.pullEvent() if event=="char" then - if string.lower(p1)=="y" then + if string.lower(p1)=="y" then runGame() - elseif string.lower(p1)=="n" then + elseif string.lower(p1)=="n" then os.shutdown() end end end - + end function killPlayer() @@ -378,7 +378,7 @@ function killPlayer() moveDown=false delShip(shipYPos) lives=lives-1 - if lives==0 then + if lives==0 then gameOver("OUT OF LIVES") end killedState=true @@ -438,7 +438,7 @@ function right() end function up() - if shipYPos > 2 then + if shipYPos > 2 then delShip(shipYPos) shipYPos=shipYPos-1 checkShipCollision() @@ -449,7 +449,7 @@ function up() end function down() - if shipYPos<17 then + if shipYPos<17 then delShip(shipYPos) shipYPos=shipYPos+1 checkShipCollision() @@ -480,7 +480,7 @@ function checkShipCollision() if human3x >=24 and human3x <= 26 then human3=false humanHitRoutine() - end + end elseif human4==true and human4y==shipYPos then if human4x >=24 and human4x <= 26 then human4=false @@ -495,7 +495,7 @@ function checkShipCollision() if human6x >=24 and human6x <= 26 then human6=false humanHitRoutine() - end + end end end end @@ -551,7 +551,7 @@ function alienDown() alien1Abduct=true alien1Carry=true alien1Step=17 - end + end end end @@ -564,74 +564,74 @@ function alienRoutine() end alien1Abduct=false alien1Carry=false - if humansLeft==0 then + if humansLeft==0 then gameOver("NO HUMANS LEFT") end - + end function alienUp() if alien1==true and alien1Abduct==true then - if alien1x+1 == human1x then + if alien1x+1 == human1x then human1Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human1y=math.floor(alien1Step)+1 human1x=alien1x+1 - if human1y<=2 then + if human1y<=2 then alienRoutine() human1=false end - elseif alien1x+1 == human2x then + elseif alien1x+1 == human2x then human2Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human2y=math.floor(alien1Step)+1 human2x=alien1x+1 - if human2y<=2 then + if human2y<=2 then alienRoutine() human2=false end - elseif alien1x+1 == human3x then + elseif alien1x+1 == human3x then human3Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human3y=math.floor(alien1Step)+1 human3x=alien1x+1 - if human3y<=2 then + if human3y<=2 then alienRoutine() human3=false end - elseif alien1x+1 == human4x then + elseif alien1x+1 == human4x then human4Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human4y=math.floor(alien1Step)+1 human4x=alien1x+1 - if human4y<=2 then + if human4y<=2 then alienRoutine() human4=false end - elseif alien1x+1 == human5x then + elseif alien1x+1 == human5x then human5Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human5y=math.floor(alien1Step)+1 human5x=alien1x+1 - if human5y<=2 then + if human5y<=2 then alienRoutine() human5=false end - elseif alien1x+1 == human6x then + elseif alien1x+1 == human6x then human6Abducted=true alien1Step=alien1Step-stepValue alien1y=math.floor(alien1Step) human6y=math.floor(alien1Step)+1 human6x=alien1x+1 - if human6y<=2 then + if human6y<=2 then alienRoutine() human6=false - end + end end end if alien1==false then alienGen() end @@ -645,7 +645,7 @@ function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q moveDown=true moveUp=false elseif pressedKey==203 or pressedKey == 30 then -- left - moveLeft=true + moveLeft=true moveRight=false elseif pressedKey==205 or pressedKey == 32 then -- right moveRight=true @@ -654,7 +654,7 @@ function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q if bulletState==false then bulletYPos=shipYPos bulletState=true - if shipFacingRight==true then + if shipFacingRight==true then bulletXPos=shipXPos+3 bulletGoingRight=true else @@ -665,13 +665,13 @@ function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q elseif pressedKey==25 then -- q (use 25 if p for quit) gameOver("YOU QUIT") end - + --term.setCursorPos(30,1) --write(pressedKey.." ") end function removeBullet() - if bulletGoingRight==true then + if bulletGoingRight==true then bulletXPos = 60 else bulletXPos = -10 @@ -691,7 +691,7 @@ end function humanHitRoutine() score=score-50 humansLeft=humansLeft-1 - if humansLeft==0 then + if humansLeft==0 then gameOver("NO HUMANS LEFT") end if alien1Carry==true then alien1Carry=false end @@ -699,9 +699,9 @@ end function checkBulletCollision() - if alien1 == true and bulletYPos == alien1y then - if bulletXPos >= alien1x and bulletXPos <= alien1x + 3 then - alien1Hit() + if alien1 == true and bulletYPos == alien1y then + if bulletXPos >= alien1x and bulletXPos <= alien1x + 3 then + alien1Hit() end end if human1 == true and bulletYPos == human1y and bulletXPos == human1x then human1=false humanHitRoutine() end @@ -737,15 +737,15 @@ end function gameControl() gameTimer=os.startTimer(0.1) - + while running do local event,p1,p2,p3 = os.pullEvent() if score<0 then score=0 end term.setCursorPos(1,1) term.setBackgroundColour(colours.yellow) write(string.rep(" ",w)) - - + + term.setTextColour(colours.red) term.setCursorPos(5,1) write("Score: "..score.." ") @@ -753,15 +753,15 @@ function gameControl() write("Humans Left: "..humansLeft.." ") term.setCursorPos(40,1) write("Lives: "..lives.." ") - + term.setBackgroundColour(colours.black) term.setTextColour(colours.white) - + local newStepValue = (score+0.1)/1000 if newStepValue > stepValue then stepValue= newStepValue end if stepValue>0.4 then stepValue=0.4 end - - + + --[[DEBUG term.setCursorPos(2,2) write("human1x "..human1x.." ") @@ -776,10 +776,10 @@ function gameControl() term.setCursorPos(2,7) write("human6x "..human6x.." ") ]]-- - - + + if event=="timer" and gameTimer == p1 then - if killedState==true then + if killedState==true then delShip(shipYPos) delHumans() dropHumans() @@ -800,15 +800,15 @@ function gameControl() else moveLeft=true moveRight=false - end + end killedDelay=0 end else - + --alienGen() drawShip(shipYPos) delAliens() - + delHumans() dropHumans() alienDown() @@ -817,7 +817,7 @@ function gameControl() drawHumans() drawBorder() end - + if bulletState==true then if bulletGoingRight==true then delBullet() @@ -839,7 +839,7 @@ function gameControl() end end end - + if moveLeft==true then left() end @@ -852,16 +852,16 @@ function gameControl() if moveDown==true then down() end - + gameTimer=os.startTimer(0.1) - - elseif event=="key" and killedState==false then + + elseif event=="key" and killedState==false then pressedKey=p1 keyPress() end - - end - + + end + end function runGame() @@ -875,7 +875,7 @@ end function pix(xCo,yCo,text,col) - if col== nil then term.setBackgroundColour(colours.black) + if col== nil then term.setBackgroundColour(colours.black) elseif col =="white" then term.setBackgroundColour(colours.white) elseif col =="green" then term.setBackgroundColour(colours.green) elseif col =="pink" then term.setBackgroundColour(colours.pink) @@ -977,7 +977,7 @@ function line2() pix(38,5," ","white") pix(40,5," ","white") pix(42,5," ","white") - + end function line3() @@ -1030,7 +1030,7 @@ function startScreen() term.setCursorPos(1,h) write(string.rep(" ",w)) local screenStage=0 - + screenTimer=os.startTimer(0.1) while true do local event,p1,p2,p3=os.pullEvent() @@ -1039,12 +1039,12 @@ function startScreen() clear() runGame() elseif event=="timer" and screenTimer == p1 then - + --term.setCursorPos(1,1) write("screenStage: "..screenStage.." ") - + term.setBackgroundColour(colours.black) term.setCursorPos(35,1) write("SPACE WHEN READY") - + if screenStage>0 and screenStage<0.5 then humanPixY = 18 drawHumanPix() @@ -1055,17 +1055,17 @@ function startScreen() alienPixY = -2 delAlienPix() alienPixY = -1 - drawAlienPix() + drawAlienPix() elseif screenStage>4 and screenStage<4.9 then alienPixY = -1 delAlienPix() alienPixY = 0 - drawAlienPix() + drawAlienPix() elseif screenStage>5 and screenStage<5.9 then alienPixY = 0 delAlienPix() alienPixY = 1 - drawAlienPix() + drawAlienPix() elseif screenStage>6 and screenStage<6.9 then alienPixY = 1 delAlienPix() @@ -1080,7 +1080,7 @@ function startScreen() alienPixY = 3 delAlienPix() alienPixY = 4 - drawAlienPix() + drawAlienPix() elseif screenStage>8 and screenStage<9.9 then alienPixY = 4 delAlienPix() @@ -1120,7 +1120,7 @@ function startScreen() pix(22,17," ","yellow") pix(22,18," ","yellow") humanPixY = 18 - drawHumanPix() + drawHumanPix() elseif screenStage>10.8 and screenStage<11 then pix(25,8," ","yellow") pix(24,9," ","yellow") @@ -1134,7 +1134,7 @@ function startScreen() pix(20,17," ","yellow") pix(20,18," ","yellow") humanPixY = 18 - drawHumanPix() + drawHumanPix() elseif screenStage>11.9 and screenStage<12 then pix(1,6," ","yellow") elseif screenStage>12 and screenStage<12.1 then @@ -1142,7 +1142,7 @@ function startScreen() pix(3,6," ","yellow") elseif screenStage>12.1 and screenStage<12.2 then pix(3,6," ") - pix(5,6," ","yellow") + pix(5,6," ","yellow") elseif screenStage>12.2 and screenStage<12.3 then pix(5,6," ") pix(7,6," ","yellow") @@ -1166,102 +1166,102 @@ function startScreen() end humanPixY=18 drawHumanPix() - elseif screenStage>13 and screenStage<13.1 then + elseif screenStage>13 and screenStage<13.1 then shipPixX= -16 drawShipPix() - elseif screenStage>13 and screenStage<13.1 then + elseif screenStage>13 and screenStage<13.1 then delShipPix() shipPixX= -15 - drawShipPix() - elseif screenStage>13.1 and screenStage<13.2 then + drawShipPix() + elseif screenStage>13.1 and screenStage<13.2 then delShipPix() shipPixX= -12 - drawShipPix() - elseif screenStage>13.2 and screenStage<13.3 then + drawShipPix() + elseif screenStage>13.2 and screenStage<13.3 then delShipPix() shipPixX= -9 drawShipPix() - elseif screenStage>13.2 and screenStage<13.3 then + elseif screenStage>13.2 and screenStage<13.3 then delShipPix() shipPixX= -6 drawShipPix() - elseif screenStage>13.3 and screenStage<13.4 then + elseif screenStage>13.3 and screenStage<13.4 then delShipPix() shipPixX= -3 drawShipPix() - elseif screenStage>13.4 and screenStage<13.5 then + elseif screenStage>13.4 and screenStage<13.5 then delShipPix() shipPixX= 0 drawShipPix() - elseif screenStage>13.6 and screenStage<13.7 then + elseif screenStage>13.6 and screenStage<13.7 then delShipPix() shipPixX= 3 drawShipPix() - elseif screenStage>13.8 and screenStage<13.9 then + elseif screenStage>13.8 and screenStage<13.9 then delShipPix() shipPixX= 6 drawShipPix() - elseif screenStage>13.9 and screenStage<14 then + elseif screenStage>13.9 and screenStage<14 then delShipPix() shipPixX= 9 drawShipPix() - elseif screenStage>14.1 and screenStage<14.2 then + elseif screenStage>14.1 and screenStage<14.2 then delShipPix() shipPixX= 12 drawShipPix() - elseif screenStage>14.2 and screenStage<14.3 then + elseif screenStage>14.2 and screenStage<14.3 then delShipPix() shipPixX= 15 drawShipPix() - elseif screenStage>14.3 and screenStage<14.4 then + elseif screenStage>14.3 and screenStage<14.4 then delShipPix() shipPixX= 18 drawShipPix() - elseif screenStage>14.4 and screenStage<14.5 then + elseif screenStage>14.4 and screenStage<14.5 then delShipPix() shipPixX= 21 drawShipPix() - elseif screenStage>14.5 and screenStage<14.6 then + elseif screenStage>14.5 and screenStage<14.6 then delShipPix() shipPixX= 24 drawShipPix() - elseif screenStage>14.6 and screenStage<14.7 then + elseif screenStage>14.6 and screenStage<14.7 then delShipPix() shipPixX= 27 drawShipPix() - elseif screenStage>14.7 and screenStage<14.8 then + elseif screenStage>14.7 and screenStage<14.8 then delShipPix() shipPixX= 30 drawShipPix() - elseif screenStage>14.8 and screenStage<14.9 then + elseif screenStage>14.8 and screenStage<14.9 then delShipPix() shipPixX= 33 drawShipPix() - elseif screenStage>14.9 and screenStage<15 then + elseif screenStage>14.9 and screenStage<15 then delShipPix() shipPixX= 36 drawShipPix() - elseif screenStage>15 and screenStage<15.1 then + elseif screenStage>15 and screenStage<15.1 then delShipPix() shipPixX= 39 drawShipPix() - elseif screenStage>15.1 and screenStage<15.2 then + elseif screenStage>15.1 and screenStage<15.2 then delShipPix() shipPixX= 41 drawShipPix() - elseif screenStage>15.2 and screenStage<15.3 then + elseif screenStage>15.2 and screenStage<15.3 then delShipPix() shipPixX= 44 drawShipPix() - elseif screenStage>15.3 and screenStage<15.4 then + elseif screenStage>15.3 and screenStage<15.4 then delShipPix() shipPixX= 47 drawShipPix() - elseif screenStage>15.4 and screenStage<15.5 then + elseif screenStage>15.4 and screenStage<15.5 then delShipPix() shipPixX= 50 drawShipPix() - elseif screenStage>15.5 and screenStage<15.6 then + elseif screenStage>15.5 and screenStage<15.6 then delShipPix() elseif screenStage>16 and screenStage<16.9 then humanPixY=18 @@ -1284,7 +1284,7 @@ function startScreen() write("Fire when ready") elseif screenStage>22.1 and screenStage <27 then introHighScoreTable() - elseif screenStage>27 then + elseif screenStage>27 then term.setBackgroundColour(colours.black) for i = 2,h-1 do term.setCursorPos(1,i) @@ -1292,7 +1292,7 @@ function startScreen() end screenStage=0 end - + screenStage=screenStage+0.1 screenTimer=os.startTimer(0.025) end @@ -1308,4 +1308,4 @@ else term.setCursorPos(1,1) print("I'm sorry, Protector requires an Advanced Computer to run") print(" ") -end \ No newline at end of file +end diff --git a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua index 2aeaf4072..b75a5ca79 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua @@ -89,7 +89,7 @@ local titleLevel = { local function parseValue(x, y, lchar) if tonumber(lchar, 16) then lchar = math.pow(2, tonumber(lchar,16)) - + if lchar == colours.blue then map[y][x] = 0 elseif lchar == colours.brown then @@ -146,7 +146,7 @@ local function loadMap(_sPath) goldMap = {} monks = {} goldCount = 0 - + local file = fs.open(_sPath, "r") local line = file:readLine() while line do @@ -279,14 +279,14 @@ local function resetMap() monk.x = monk.spawnX monk.y = monk.spawnY end - + for _,timer in pairs(blockTimers) do map[timer.y][timer.x] = 0 end blockTimers = {} plX = plspawnX plY = plspawnY - + moveTimer = -1 shootTimer = -1 spawnTimer = -1 @@ -320,27 +320,27 @@ end local function drawLevelList() local minLev = ((levelLot-1) * 10 + 1) local maxLev = minLev + math.min(10, #levelList - (levelLot-1) * 10) - 1 - + term.setCursorPos(7, 2) term.setBackgroundColour(colours.black) term.clearLine() for j = 1,49 do updateMap(j,2) end - + term.setBackgroundColour(colours.black) term.setTextColour(colours.white) term.setCursorPos(7, 2) local msg = "Levels "..minLev.." to "..maxLev.." of "..#levelList term.write(msg) - + term.setTextColour(colours.yellow) term.setCursorPos(4, 2) if levelLot > 1 then term.write("<-") - else term.write(" ") end - + else term.write(" ") end + term.setCursorPos(8 + #msg, 2) if maxLev < #levelList then term.write("->") else term.write(" ") end - + for i = 1,10 do term.setCursorPos(1, 3+i) for j = 1,49 do updateMap(j,3+i) end @@ -371,12 +371,12 @@ local function loadTitleScreen() if #map == 18 then break end end maxGoldCount = goldCount - + drawMap() term.setCursorPos(1,19) term.setBackgroundColour(colours.blue) term.clearLine() - + menIndex = 1 titleLoaded = true end @@ -384,22 +384,22 @@ end --Opens an in-game menu to display a series of options. local function inGameMenu(menuList) menIndex = 1 - + local squareTop,squareBottom = 4,6 + #menuList * 2 local squareSize = 0 for i=1,#menuList do squareSize = math.max(squareSize, #menuList[i] + 6) end - + for y=squareTop,squareBottom do term.setCursorPos(w/2 - squareSize/2, y) term.setBackgroundColour(colours.lightBlue) term.write(string.rep(" ", squareSize)) - + if y ~= squareTop and y ~= squareBottom then term.setCursorPos(w/2 - squareSize/2 + 1, y) term.setBackgroundColour(colours.black) term.write(string.rep(" ", squareSize - 2)) end - + if y ~= squareTop and y ~= squareBottom and y % 2 == 0 then local opt = menuList[(y - squareTop) / 2] term.setCursorPos(w/2 - #opt/2, y) @@ -407,7 +407,7 @@ local function inGameMenu(menuList) term.write(opt) end end - + local p1 = nil repeat for i=1,#menuList do @@ -426,20 +426,20 @@ local function inGameMenu(menuList) end end _,p1 = os.pullEvent("key") - + if p1 == keys.up and menIndex > 1 then menIndex = menIndex - 1 elseif p1 == keys.down and menIndex < #menuList then menIndex = menIndex + 1 end until p1 == keys.enter - + return menuList[menIndex] end --Checks to see if any given desired move is legal. Monks and players both use this. local function isLegalMove(initX,initY,finX,finY) - if finY < 1 or finY > #map or finX < 1 or finX > 49 then - return false + if finY < 1 or finY > #map or finX < 1 or finX > 49 then + return false end - + if map[finY][finX] ~= 0 and map[finY][finX] ~= '#' then --This reports 'self moves' as being illegal, but that's fine for _,monk in pairs(monks) do @@ -450,10 +450,10 @@ local function isLegalMove(initX,initY,finX,finY) then return true elseif finY == initY+1 and (map[finY][finX] == "H" or (map[finY][finX] == "h" and goldCount == 0) or (type(map[finY][finX]) == "number" and map[finY][finX] > 0) or map[finY][finX] == nil or - map[finY][finX] == "V" or map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0)) + map[finY][finX] == "V" or map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0)) then return true - elseif finX == initX-1 or finX == initX+1 then - return true + elseif finX == initX-1 or finX == initX+1 then + return true end end end @@ -461,12 +461,12 @@ end --Moves the player to a given step. local function movePlayer(x,y,ignoreLegal) if not ignoreLegal and not isLegalMove(plX,plY,x,y) then return false end - + local ox = plX local oy = plY plX = x plY = y - + updateMap(ox,oy) updateMap(x,y) if goldMap[y][x] == 1 then @@ -481,14 +481,14 @@ local function movePlayer(x,y,ignoreLegal) started = false nextLevel = true end - - pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) + + pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) and (map[y+1][x] == nil or map[y+1][x] == "V" or map[y+1][x] == 2 or map[y+1][x] == '-')) if (y < #map and map[y+1][x] == 'h' and goldCount ~= 0) then pfalling = true end for _,monk in pairs(monks) do if monk.x == plX and monk.y == plY + 1 then pfalling = false break end end - + return true end @@ -634,7 +634,7 @@ local function updateMonks() end end end - + if not (monk.trapped or monk.dead) then --Has the monk decided on moving left or right? If so we try to move him if monk.desX and not monk.falling then @@ -708,7 +708,7 @@ local function updateBlockTimer(tid) end local function shootBlock(x,y) - if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil + if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil or map[y-1][x] == 2 or (map[y-1][x] == 'h' and goldCount > 0)) then map[y][x] = 3 table.insert(blockTimers, {x = x; y = y; timer = os.startTimer(0.1);} ) @@ -718,14 +718,14 @@ end local function handleEvents() local id,p1,p2,p3 = os.pullEvent() - + if id == "key" then --Menu Handling if p1 == keys.up then if menIndex > 1 then menIndex = menIndex - 1 end elseif p1 == keys.down then - if inLevelSelect then - if menIndex < math.min(10, #levelList - (levelLot-1)*10) then + if inLevelSelect then + if menIndex < math.min(10, #levelList - (levelLot-1)*10) then menIndex = menIndex + 1 end elseif menIndex < #titleOptions then menIndex = menIndex + 1 end @@ -736,7 +736,7 @@ local function handleEvents() levelLot = levelLot + 1 drawLevelList() end - + --Game Handling if p1 == keys.a and moveTimer == -1 and spawnTimer == -1 then movePlayer(plX-1,plY) @@ -811,7 +811,7 @@ local function handleEvents() monk.trapped = nil monk.behaviour = "none" monk.justEscaped = true - + updateMap(monk.x, monk.y+1) drawMonk(monk) end @@ -859,12 +859,12 @@ local pallette = { { t = colours.black, b = colours.blue, s = " ", n = "Solid G local brushType = 1 local function getHexOf(colour) - if not colour or not tonumber(colour) then - return " " + if not colour or not tonumber(colour) then + return " " end local value = math.log(colour)/math.log(2) - if value > 9 then - value = hexnums[value] + if value > 9 then + value = hexnums[value] end return value end @@ -878,7 +878,7 @@ local function drawFooter() term.setCursorPos(w,i) term.write(" ") end - + term.setBackgroundColour(colours.black) term.setTextColour(colours.blue) term.setCursorPos(2,h) @@ -904,7 +904,7 @@ local function drawPallette(xpos,ypos) local top = ypos if xpos + xdim > w then left = left + (w - xpos - xdim) end if ypos + ydim > h then top = top + (h - ypos - ydim) end - + --There's no easy way to do this... so we draw it manually :( for i=0,4 do term.setCursorPos(left, top + i) @@ -913,25 +913,25 @@ local function drawPallette(xpos,ypos) if i == 0 or i == 4 then term.write("*-----*") else term.write("* *") end end - + for i=1,#pallette-1 do local ypl = 1 local xmv = i if i > 5 then ypl = 2 xmv = i - 5 end - + term.setCursorPos(left + xmv, top+ypl) term.setBackgroundColour(pallette[i].b) term.setTextColour(pallette[i].t) term.write(pallette[i].s) end - + term.setCursorPos(left + 1, top + 3) term.setBackgroundColour(colours.red) term.setTextColour(colours.black) term.write("ERASE") - + local _,button,x,y = os.pullEvent("mouse_click") - + if button == 1 then if y == top + 1 and x > left and x < left + 6 then brushType = x-left @@ -941,9 +941,9 @@ local function drawPallette(xpos,ypos) brushType = 11 end end - + for y = top,top+ydim do - for x = left,left+xdim do + for x = left,left+xdim do --Not sure why the -2 is necessary if map[y+drawOffsetY] then updateMap(x-2,y+drawOffsetY) end end @@ -955,7 +955,7 @@ end local function saveCurrentMap(path) local file = io.open(shell.resolve(".").."/levels/"..path, "w") if not file then return false end - + drawMap() drawFooter() local msg = "Saving.." @@ -968,7 +968,7 @@ local function saveCurrentMap(path) term.write(string.rep(" ", 18)) term.setCursorPos(w/2-9,6) term.setBackgroundColour(colours.lime) - + for y=1,#map do local xstr = "" for x=1,49 do @@ -1016,14 +1016,14 @@ local function runLevelEditor() end monks = {} end - + drawMap() drawFooter() - + while inLevelEditor do local id,button,x,y = os.pullEvent() if id == "mouse_click" or id == "mouse_drag" then - if button == 2 then + if button == 2 then drawPallette(x,y) elseif x > drawOffsetX and x <= 49 + drawOffsetX and y > drawOffsetY and y <= 18 + drawOffsetY then if pallette[brushType].v == "player" then @@ -1095,7 +1095,7 @@ local function runLevelSelect() if not titleLoaded then loadTitleScreen() monkTimer = os.startTimer(moveIntv * 1.5) - else + else drawMap() drawEndgameMap() term.setCursorPos(1,19) @@ -1103,11 +1103,11 @@ local function runLevelSelect() term.clearLine() end drawLevelList() - + menSel = "none" repeat handleEvents() - + term.setBackgroundColour(colours.black) term.setTextColour(colours.yellow) for i=1,10 do @@ -1131,23 +1131,23 @@ local function runTitle() term.write("Gold Runner") term.setCursorPos(16,4) term.write("By Nitrogen Fingers") - + term.setTextColour(colours.white) for i=1,#titleOptions do term.setCursorPos(19, 5 + (i*2)) term.write(titleOptions[i]) end - + term.setCursorPos(16, 7) term.setTextColour(colours.yellow) term.write("->") - + menSel = "none" monkTimer = os.startTimer(moveIntv * 1.5) - + repeat handleEvents() - + term.setBackgroundColour(colours.black) term.setTextColour(colours.yellow) for i=1,#titleOptions do @@ -1166,25 +1166,25 @@ local function playLevel() drawHUD() os.pullEvent("key") movePlayer(plX,plY,true) - + monkTimer = os.startTimer(moveIntv * 1.5) moveTimer = os.startTimer(moveIntv) shootTimer = -1 spawnTimer = -1 - + started = true while started do handleEvents() end - + if menSel == "Quit" or menSel == "Back to Title" or menSel == "Edit Level" then running = false return end menSel = "none" - + if nextLevel then - if currentLevel == #levelList then + if currentLevel == #levelList then started = false running = false break @@ -1198,12 +1198,12 @@ local function playLevel() else playerLives = playerLives-1 if playerLives > 0 then resetMap() - else - running = false + else + running = false end end end - + if nextLevel then local msg = "All levels defeated, Gold Runner!" term.setBackgroundColour(colours.black) @@ -1247,7 +1247,7 @@ while menSel ~= "Quit" do term.setCursorPos(1,19) term.setBackgroundColour(colours.blue) term.clearLine() - + term.setCursorPos(16,10) term.setBackgroundColour(colours.black) term.setTextColour(colours.white) @@ -1256,13 +1256,13 @@ while menSel ~= "Quit" do term.setCursorPos(17,11) term.setCursorBlink(true) local levelName = "" - + local id,p1 repeat id,p1 = os.pullEvent() if id == "key" and p1 == keys.backspace then levelName = string.sub(levelName, 1, #levelName - 1) - elseif id == "timer" and p1 == monkTimer then + elseif id == "timer" and p1 == monkTimer then updateMonks() monkTimer = os.startTimer(moveIntv * 2) elseif id == "char" and #levelName < 14 then @@ -1273,15 +1273,15 @@ while menSel ~= "Quit" do term.write(levelName..string.rep(" ",14 - #levelName)) term.setCursorPos(17 + #levelName ,11) until id == "key" and p1 == keys.enter and #levelName > 0 - + term.setCursorBlink(false) levelEditName = levelName runLevelEditor() - + if menSel == "Play Level" then currentLevel = nil levelList = fs.list(shell.resolve(".").."/levels") - for num,name in pairs(levelList) do + for num,name in pairs(levelList) do if name == levelName then currentLevel = num break @@ -1296,7 +1296,7 @@ while menSel ~= "Quit" do runLevelEditor() term.setBackgroundColour(colours.black) term.clear() - + if menSel == "Play Level" then menSel = "New Game" else diff --git a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua index be40631ff..89dc031cc 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua @@ -1,7 +1,7 @@ --[[ 3D Print A printing program for use with NPaintPro - + By NitrogenFingers ]]-- @@ -30,7 +30,7 @@ local commandList = { ["DE"] = endPrint; } ---Splits a string according to a pattern into a table +--Splits a string according to a pattern into a table local function split(str, pattern) local t = { } local fpat = "(.-)" .. pattern @@ -56,11 +56,11 @@ local function respondToQuery() print("Listening for ACT/ID query") local id,key = rednet.receive() print("Received : "..key) - + if key == "$3DPRINT IDENTIFY" then print("Requested Identification") rednet.send(id, "$3DPRINT IDACK "..os.getComputerLabel()) - + elseif key == "$3DPRINT ACTIVATE" then print("Requested Activation") activeCommander = id @@ -76,10 +76,10 @@ local function performPrint() while operatingPrint do local id,msg = rednet.receive() print("Command : "..msg) - + if id == activeCommander and string.find(msg, "$PC") == 1 then local cmds = split(msg, " ") - + --It's a bit of a hack, but those are the 2 methods required for a refuel if turtle.getFuelLevel() == 0 and cmds[2] ~= "SS" and cmds[2] ~= "RF" then rednet.send(id, "$3DPRINT OOF") @@ -95,7 +95,7 @@ local function performPrint() commandList[cmds[2]][i](tonumber(cmds[3])) end end - + rednet.send(activeCommander, "$3DPRINT ACK") end end @@ -116,4 +116,4 @@ while true do respondToQuery() --Perform the print performPrint() -end \ No newline at end of file +end diff --git a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua index 8a029e83b..dac2bcc78 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua @@ -25,7 +25,7 @@ function initializeBuffer(terminal) if not terminal.isColour() then error("Parameter does not represent an advanced computer.") end - + tw,th = terminal.getSize() backbuffer = { } for y=1,th do @@ -41,8 +41,8 @@ end function clearBuffer(colour) if not backbuffer then error("Back buffer not yet initialized!") - end - + end + for y=1,#backbuffer do backbuffer[y] = { } if colour then @@ -60,26 +60,26 @@ end function writeToBuffer(entity) if not backbuffer then error("Back buffer not yet initialized!") - end - + end + local image = nil if entity.type == "animation" then image = entity.frames[entity.currentFrame] else image = entity.image end - + for y=1,image.dimensions.height do for x=1,image.dimensions.width do if image[y][x] then local xpos,ypos = x,y if entity.mirror.x then xpos = image.dimensions.width - x + 1 end if entity.mirror.y then ypos = image.dimensions.height - y + 1 end - + --If the YPos doesn't exist, no need to loop through the rest of X! --Don't you love optimization? if not backbuffer[entity.y + ypos - 1] then break end - + backbuffer[entity.y + ypos - 1][entity.x + xpos - 1] = image[y][x] end end @@ -93,7 +93,7 @@ end function drawBuffer(terminal) if not backbuffer then error("Back buffer not yet initialized!") - end + end if not terminal then terminal = term end if not terminal.setCursorPos or not terminal.setBackgroundColour or not terminal.write then error("Parameter cannot be used to initialize the backbuffer.") @@ -101,7 +101,7 @@ function drawBuffer(terminal) if not terminal.isColour() then error("Parameter does not represent an advanced computer.") end - + for y=1,math.min(#backbuffer, th) do for x=1,tw do if backbuffer[y][x] then @@ -167,14 +167,14 @@ end ]]-- local function drawS(self) local image = self.image - + for y=1,image.dimensions.height do for x=1,image.dimensions.width do if image[y][x] then local xpos,ypos = x,y if self.mirror.x then xpos = image.dimensions.width - x + 1 end if self.mirror.y then ypos = image.dimensions.height - y + 1 end - + term.setBackgroundColour(image[y][x]) term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1) term.write(" ") @@ -198,7 +198,7 @@ local function drawA(self, frame) local xpos,ypos = x,y if self.mirror.x then xpos = image.dimensions.width - x + 1 end if self.mirror.y then ypos = image.dimensions.height - y + 1 end - + term.setBackgroundColour(image[y][x]) term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1) term.write(" ") @@ -259,16 +259,16 @@ local function drawBounds(entity, colour) local image = nil if entity.type == "animation" then image = entity.frames[entity.currentFrame] else image = entity.image end - + term.setBackgroundColour(colour) - + corners = { topleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y - 1 }; topright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y - 1 }; botleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y + image.bounds.height - 2 }; botright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y + image.bounds.height - 2 }; } - + term.setCursorPos(corners.topleft.x, corners.topleft.y) term.write(" ") term.setCursorPos(corners.topright.x, corners.topright.y) @@ -308,7 +308,7 @@ end local function rCollidesWith(self, other) --First we construct the rectangles local img1C, img2C = createRectangle(self), createRectangle(other) - + --We then determine the "relative position" , in terms of which is farther left or right leftmost,rightmost,topmost,botmost = nil,nil,nil,nil if img1C.left < img2C.left then @@ -325,13 +325,13 @@ local function rCollidesWith(self, other) topmost = img2C botmost = img1C end - + --Then we determine the distance between the "extreme" edges- --distance between leftmost/right edge and rightmost/left edge --distance between topmost/bottom edge and bottommost/top edge local xdist = rightmost.left - leftmost.right local ydist = botmost.top - topmost.bottom - + --If both are negative, our rectangles intersect! return xdist <= 0 and ydist <= 0 end @@ -352,13 +352,13 @@ local function pCollidesWith(self, other) else img1 = self.image end if other.type == "animation" then img2 = other.frames[other.currentFrame] else img2 = other.image end - + --...then we position them... leftmost,rightmost,topmost,botmost = nil,nil,nil,nil --We also keep track of which is left and which is right- it doesn't matter in a rectangle --collision but it does in a pixel collision. img1T,img2T = {},{} - + if img1C.left < img2C.left then leftmost = img1C rightmost = img2C @@ -377,15 +377,15 @@ local function pCollidesWith(self, other) botmost = img1C img2T.top = true end - + --...and we again find the distances between the extreme edges. local xdist = rightmost.left - leftmost.right local ydist = botmost.top - topmost.bottom - + --If these distances are > 0 then we stop- no need to go any farther. if xdist > 0 or ydist > 0 then return false end - - + + for x = rightmost.left, rightmost.left + math.abs(xdist) do for y = botmost.top, botmost.top + math.abs(ydist) do --We know a collision has occurred if a pixel is occupied by both images. We do this by @@ -398,16 +398,16 @@ local function pCollidesWith(self, other) else testX = x - img1C.left + 1 end if img1T.top then testY = y - img1C.top + 1 else testY = y - img1C.top + 1 end - + local occupy1 = img1[testY + img1.bounds.y-1][testX + img1.bounds.x-1] ~= nil - + if img2T.left then testX = x - img2C.left + 1 else testX = x - img2C.left + 1 end if img2T.top then testY = y - img2C.top + 1 else testY = y - img2C.top + 1 end - + local occupy2 = img2[testY + img2.bounds.y-1][testX + img2.bounds.x-1] ~= nil - + if occupy1 and occupy2 then return true end end end @@ -429,7 +429,7 @@ local function moveTo(self, x, y) else image = self.image end - + self.x = x - image.bounds.x + 1 self.y = y - image.bounds.y + 1 end @@ -448,7 +448,7 @@ image:table = a table of the image. Indexed by height, a series of sub-tables, e dimensions:table = width = the width of the entire image in pixels height = the height of the entire image in pixels - + mirror:table = x:bool = whether or not the image is mirrored on the X axis y:bool = whether or not the image is mirrored on the Y axis @@ -464,19 +464,19 @@ draw:function = see drawS (above) y:number = the initial Y position of the sprite ]]-- function loadSprite(path, x, y) - local sprite = { + local sprite = { type = "sprite", x = x, y = y, image = { }, mirror = { x = false, y = false } } - + if fs.exists(path) then local file = io.open(path, "r" ) local leftX, rightX = math.huge, 0 local topY, botY = nil,nil - + local lcount = 0 for line in file:lines() do lcount = lcount+1 @@ -492,7 +492,7 @@ function loadSprite(path, x, y) end end file:close() - + sprite.image.bounds = { x = leftX, width = rightX - leftX + 1, @@ -503,10 +503,10 @@ function loadSprite(path, x, y) width = rightX, height = botY } - + sprite.x = sprite.x - leftX + 1 sprite.y = sprite.y - topY + 1 - + sprite.repaint = repaintS sprite.rCollidesWith = rCollidesWith sprite.pCollidesWith = pCollidesWith @@ -536,13 +536,13 @@ function loadAnimation(path, x, y, currentFrame) mirror = { x = false, y = false }, currentFrame = currentFrame } - + table.insert(anim.frames, { }) if fs.exists(path) then local file = io.open(path, "r") local leftX, rightX = math.huge, 0 local topY, botY = nil,nil - + local lcount = 0 for line in file:lines() do lcount = lcount+1 @@ -589,17 +589,17 @@ function loadAnimation(path, x, y, currentFrame) } anim.x = anim.x - leftX + 1 anim.y = anim.y - topY + 1 - - if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or - currentFrame > #anim.frames then - anim.currentFrame = 1 + + if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or + currentFrame > #anim.frames then + anim.currentFrame = 1 end - + anim.timerID = nil anim.lowerBound = 1 anim.upperBound = #anim.frames anim.updating = false - + anim.repaint = repaintA anim.rCollidesWith = rCollidesWith anim.pCollidesWith = pCollidesWith @@ -612,4 +612,4 @@ function loadAnimation(path, x, y, currentFrame) else error(path.." not found!") end -end \ No newline at end of file +end diff --git a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua index 0c214a60d..826468eb7 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua @@ -68,7 +68,7 @@ local px,py,pz,pfx,pfz = 0,0,0,0,0 --The form of layering used local layering = "up" ---The animation state of the selection rectangle and image buffer +--The animation state of the selection rectangle and image buffer local rectblink = 0 --The ID for the timer local recttimer = nil @@ -268,7 +268,7 @@ local helpTopics = { message = "Clicking on the mode display at the bottom of the screen will open the options menu. Here you can".. " activate all of the modes in the program with a simple mouse click. Pressing left control will open up the".. " file menu automatically.", - controls = { + controls = { { "leftCtrl", "Opens the file menu" }, { "leftAlt", "Opens the paint menu" } } @@ -317,8 +317,8 @@ local toplim,botlim,leflim,riglim = nil,nil,nil,nil --The selected path local sPath = nil ---[[ - Section: Helpers +--[[ + Section: Helpers ]]-- --[[Converts a colour parameter into a single-digit hex coordinate for the colour @@ -326,12 +326,12 @@ local sPath = nil Returns:string A string conversion of the colour ]]-- local function getHexOf(colour) - if not colour or not tonumber(colour) then - return " " + if not colour or not tonumber(colour) then + return " " end local value = math.log(colour)/math.log(2) - if value > 9 then - value = hexnums[value] + if value > 9 then + value = hexnums[value] end return value end @@ -355,7 +355,7 @@ end local function updateImageLims(forAllFrames) local f,l = sFrame,sFrame if forAllFrames == true then f,l = 1,framecount end - + toplim,botlim,leflim,riglim = nil,nil,nil,nil for locf = f,l do for y,_ in pairs(frames[locf]) do @@ -371,7 +371,7 @@ local function updateImageLims(forAllFrames) end end end - + --There is just... no easier way to do this. It's horrible, but necessary if textEnabled then for locf = f,l do @@ -406,19 +406,19 @@ end function calculateMaterials() updateImageLims(animated) requiredMaterials = {} - for i=1,16 do - requiredMaterials[i] = 0 + for i=1,16 do + requiredMaterials[i] = 0 end - + if not toplim then return end - + for i=1,#frames do for y = toplim, botlim do for x = leflim, riglim do if type(frames[i][y][x]) == "number" then requiredMaterials[math.log(frames[i][y][x],10)/math.log(2,10) + 1] = requiredMaterials[math.log(frames[i][y][x],10)/math.log(2,10) + 1] + 1 - end + end end end end @@ -455,16 +455,16 @@ end local function rsTimeReceive(timeout) local timerID if timeout then timerID = os.startTimer(timeout) end - + local id,key,msg = nil,nil while true do id,key,msg = os.pullEvent() - + if id == "timer" then if key == timerID then return else updateTimer(key) end end - if id == "rednet_message" then + if id == "rednet_message" then return key,msg end end @@ -490,9 +490,9 @@ local function drawPictureTable(image, xinit, yinit, alpha) end end ---[[ - Section: Loading -]]-- +--[[ + Section: Loading +]]-- --[[Loads a non-animted paint file into the program Params: path:string = The path in which the file is located @@ -526,7 +526,7 @@ local function loadNFT(path) frames[sFrame] = { } frames[sFrame].text = { } frames[sFrame].textcol = { } - + if fs.exists(path) then local file = io.open(path, "r") local sLine = file:read() @@ -535,7 +535,7 @@ local function loadNFT(path) table.insert(frames[sFrame], num, {}) table.insert(frames[sFrame].text, num, {}) table.insert(frames[sFrame].textcol, num, {}) - + --As we're no longer 1-1, we keep track of what index to write to local writeIndex = 1 --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour @@ -614,13 +614,13 @@ local function saveNFP(path) local file = io.open(path, "w") updateImageLims(false) - if not toplim then + if not toplim then file:close() return end for y=1,botlim do local line = "" - if frames[sFrame][y] then + if frames[sFrame][y] then for x=1,riglim do line = line..getHexOf(frames[sFrame][y][x]) end @@ -639,7 +639,7 @@ local function saveNFT(path) if not fs.exists(sDir) then fs.makeDir(sDir) end - + local file = io.open(path, "w") updateImageLims(false) if not toplim then @@ -678,17 +678,17 @@ local function saveNFA(path) if not fs.exists(sDir) then fs.makeDir(sDir) end - + local file = io.open(path, "w") updateImageLims(true) - if not toplim then + if not toplim then file:close() return end for i=1,#frames do for y=1,botlim do local line = "" - if frames[i][y] then + if frames[i][y] then for x=1,riglim do line = line..getHexOf(frames[i][y][x]) end @@ -709,14 +709,14 @@ local function init() if textEnabled then loadNFT(sPath) table.insert(ddModes, 2, { "text", "textpaint", name = "text"}) - elseif animated then + elseif animated then loadNFA(sPath) table.insert(ddModes, #ddModes, { "record", "play", name = "anim" }) table.insert(ddModes, #ddModes, { "go to", "remove", name = "frames"}) table.insert(ddModes[2], #ddModes[2], "blueprint on") table.insert(ddModes[2], #ddModes[2], "layers on") - else - loadNFP(sPath) + else + loadNFP(sPath) table.insert(ddModes[2], #ddModes[2], "blueprint on") end @@ -725,8 +725,8 @@ local function init() end end ---[[ - Section: Drawing +--[[ + Section: Drawing ]]-- @@ -747,7 +747,7 @@ local function drawLogo() msg = "By NitrogenFingers" term.setCursorPos(w/2 - #msg/2, h-2) term.write(msg) - + os.pullEvent() end @@ -772,13 +772,13 @@ local function drawCanvas() if pz >= 1 and pz <= #frames then sFrame = pz end - + if py < sy then sy = py elseif py > sy + h - 1 then sy = py + h - 1 end if px < sx then sx = px elseif px > sx + w - 2 then sx = px + w - 2 end end - + if pfx == 1 then turtlechar = ">" elseif pfx == -1 then turtlechar = "<" elseif pfz == 1 then turtlechar = "V" @@ -794,10 +794,10 @@ local function drawCanvas() else topLayer,botLayer = sFrame,sFrame end - + for currframe = botLayer,topLayer,1 do for y=sy+1,sy+h-1 do - if frames[currframe][y] then + if frames[currframe][y] then for x=sx+1,sx+w-2 do term.setCursorPos(x-sx,y-sy) if frames[currframe][y][x] then @@ -808,7 +808,7 @@ local function drawCanvas() else term.write(" ") end - else + else tileExists = false for i=currframe-1,botLayer,-1 do if frames[i][y][x] then @@ -816,7 +816,7 @@ local function drawCanvas() break end end - + if not tileExists then if blueprint then term.setBackgroundColour(colours.blue) @@ -835,7 +835,7 @@ local function drawCanvas() term.write(" ") end else - term.setBackgroundColour(alphaC) + term.setBackgroundColour(alphaC) if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then term.setTextColour(frames[currframe].textcol[y][x]) term.write(frames[currframe].text[y][x]) @@ -849,7 +849,7 @@ local function drawCanvas() else for x=sx+1,sx+w-2 do term.setCursorPos(x-sx,y-sy) - + tileExists = false for i=currframe-1,botLayer,-1 do if frames[i][y] and frames[i][y][x] then @@ -857,7 +857,7 @@ local function drawCanvas() break end end - + if not tileExists then if blueprint then term.setBackgroundColour(colours.blue) @@ -876,7 +876,7 @@ local function drawCanvas() term.write(" ") end else - term.setBackgroundColour(alphaC) + term.setBackgroundColour(alphaC) term.write(" ") end end @@ -884,7 +884,7 @@ local function drawCanvas() end end end - + --Then the printer, if he's on if state == "active print" then local bgColour = alphaC @@ -899,14 +899,14 @@ local function drawCanvas() bgColour = frames[sFrame][py-sy][px-sx] elseif blueprint then bgColour = colours.blue end end - + term.setBackgroundColour(bgColour) if bgColour == colours.black then term.setTextColour(colours.white) else term.setTextColour(colours.black) end - + term.write(turtlechar) end - + --Then the buffer if selectrect then if buffer and rectblink == 1 then @@ -920,12 +920,12 @@ local function drawCanvas() end end end - + --This draws the "selection" box local add = nil if buffer then term.setBackgroundColour(colours.lightGrey) - else + else term.setBackgroundColour(colours.grey) end for i=selectrect.x1, selectrect.x2 do @@ -947,7 +947,7 @@ local function drawCanvas() end end ---[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any +--[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any messages currently being displayed Params: none Returns:nil @@ -1001,7 +1001,7 @@ local function drawInterface() end --Footer if inMenu then return end - + term.setCursorPos(1, h) term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.grey) @@ -1016,14 +1016,14 @@ local function drawInterface() term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.grey) term.write(getStateMessage()) - + local coords="X:"..sx.." Y:"..sy if animated then coords = coords.." Frame:"..sFrame.."/"..framecount.." " end term.setCursorPos(w-#coords+1,h) if state == "play" then term.setBackgroundColour(colours.lime) elseif record then term.setBackgroundColour(colours.red) end term.write(coords) - + if animated then term.setCursorPos(w-1,h) term.setBackgroundColour(colours.grey) @@ -1075,17 +1075,17 @@ local function drawHelpScreen() print(helpTopics[selectedHelp].controls[i][2]) end end - + local id,p1,p2,p3 = os.pullEvent() - + if id == "timer" then updateTimer(p1) - elseif id == "key" then + elseif id == "key" then if selectedHelp then selectedHelp = nil else break end elseif id == "mouse_click" then - if not selectedHelp then + if not selectedHelp then if p3 >=3 and p3 <= 2+#helpTopics then - selectedHelp = p3-2 + selectedHelp = p3-2 else break end else selectedHelp = nil @@ -1137,7 +1137,7 @@ local function wprintOffCenter(msg, height, width, offset) end term.setCursorPos(width/2 - #string.sub(msg, ops)/2 + offset, height + inc) term.write(string.sub(msg, ops)) - + return inc + 1 end @@ -1151,7 +1151,7 @@ local function displayConfirmDialogue(ctitle, msg) local dialogoffset = 8 --We actually print twice- once to get the lines, second time to print proper. Easier this way. local lines = wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2) - + term.setCursorPos(dialogoffset, 3) term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) @@ -1163,11 +1163,11 @@ local function displayConfirmDialogue(ctitle, msg) term.setCursorPos(dialogoffset, 4) term.write(string.rep(" ", w - dialogoffset * 2)) for i=5,5+lines do - term.setCursorPos(dialogoffset, i) + term.setCursorPos(dialogoffset, i) term.write(" "..string.rep(" ", w - (dialogoffset) * 2 - 2).." ") end wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2) - + --In the event of a message, the player hits anything to continue while true do local id,key = os.pullEvent() @@ -1190,24 +1190,24 @@ local function displayDropDown(x, y, options) for i=1,#options do local currVal = options[i] if type(currVal) == "table" then currVal = currVal.name end - + longestX = math.max(longestX, #currVal) end local xOffset = math.max(0, longestX - ((w-2) - x) + 1) local yOffset = math.max(0, #options - ((h-1) - y)) - + local clickTimes = 0 local tid = nil local selection = nil while clickTimes < 2 do drawCanvas() drawInterface() - + term.setCursorPos(x-xOffset,y-yOffset) term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) term.write(options.name..string.rep(" ", longestX-#options.name + 2)) - + for i=1,#options do term.setCursorPos(x-xOffset, y-yOffset+i) if i==selection and clickTimes % 2 == 0 then @@ -1218,7 +1218,7 @@ local function displayDropDown(x, y, options) term.setTextColour(colours.grey) end local currVal = options[i] - if type(currVal) == "table" then + if type(currVal) == "table" then term.write(currVal.name..string.rep(" ", longestX-#currVal.name + 1)) term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) @@ -1227,18 +1227,18 @@ local function displayDropDown(x, y, options) term.write(currVal..string.rep(" ", longestX-#currVal + 2)) end end - + local id, p1, p2, p3 = os.pullEvent() if id == "timer" then - if p1 == tid then + if p1 == tid then clickTimes = clickTimes + 1 - if clickTimes > 2 then + if clickTimes > 2 then break - else - tid = os.startTimer(0.1) + else + tid = os.startTimer(0.1) end - else - updateTimer(p1) + else + updateTimer(p1) drawCanvas() drawInterface() end @@ -1252,15 +1252,15 @@ local function displayDropDown(x, y, options) end end end - + if type(selection) == "number" then selection = options[selection] end - - if type(selection) == "string" then + + if type(selection) == "string" then inDropDown = false return selection - elseif type(selection) == "table" then + elseif type(selection) == "table" then return displayDropDown(x, y, selection) end end @@ -1285,16 +1285,16 @@ local function readInput(lim) --As events queue immediately, we may get an unwanted key... this will solve that problem local inputTimer = os.startTimer(0.01) local keysAllowed = false - + while true do local id,key = os.pullEvent() - + if keysAllowed then if id == "key" and key == 14 and #inputString > 0 then inputString = string.sub(inputString, 1, #inputString-1) term.setCursorPos(ox + #inputString,oy) term.write(" ") - elseif id == "key" and key == 28 and inputString ~= string.rep(" ", #inputString) then + elseif id == "key" and key == 28 and inputString ~= string.rep(" ", #inputString) then break elseif id == "key" and key == keys.leftCtrl then return "" @@ -1302,9 +1302,9 @@ local function readInput(lim) inputString = inputString..key end end - + if id == "timer" then - if key == inputTimer then + if key == inputTimer then keysAllowed = true else updateTimer(key) @@ -1318,7 +1318,7 @@ local function readInput(lim) term.write(inputString) term.setCursorPos(ox + #inputString, oy) end - + while string.sub(inputString, 1, 1) == " " do inputString = string.sub(inputString, 2, #inputString) end @@ -1326,12 +1326,12 @@ local function readInput(lim) inputString = string.sub(inputString, 1, #inputString-1) end term.setCursorBlink(false) - + return inputString end ---[[ - Section: Image tools +--[[ + Section: Image tools ]]-- @@ -1341,13 +1341,13 @@ end ]]-- local function copyToBuffer(removeImage) buffer = { width = selectrect.x2 - selectrect.x1 + 1, height = selectrect.y2 - selectrect.y1 + 1, contents = { } } - + local containsSomething = false for y=1,buffer.height do buffer.contents[y] = { } local f,l = sFrame,sFrame if record then f,l = 1, framecount end - + for fra = f,l do if frames[fra][selectrect.y1 + y - 1] then for x=1,buffer.width do @@ -1372,7 +1372,7 @@ local function copyFromBuffer(removeBuffer) for y = 1, math.min(buffer.height,selectrect.y2-selectrect.y1+1) do local f,l = sFrame, sFrame if record then f,l = 1, framecount end - + for fra = f,l do if not frames[fra][selectrect.y1+y-1] then frames[fra][selectrect.y1+y-1] = { } end for x = 1, math.min(buffer.width,selectrect.x2-selectrect.x1+1) do @@ -1380,7 +1380,7 @@ local function copyFromBuffer(removeBuffer) end end end - + if removeBuffer then buffer = nil end end @@ -1394,7 +1394,7 @@ local function moveImage(newx,newy) if newx <=0 or newy <=0 then return end local f,l = sFrame,sFrame if record then f,l = 1,framecount end - + for i=f,l do local newlines = { } for y=toplim,botlim do @@ -1418,7 +1418,7 @@ local function moveImage(newx,newy) end end end - + newlines.textcol = { } for y=toplim,botlim do local line = frames[i].textcol[y] @@ -1430,7 +1430,7 @@ local function moveImage(newx,newy) end end end - + frames[i] = newlines end end @@ -1451,7 +1451,7 @@ local function clearImage() if string.find(string.upper(readInput(1)), "Y") then local f,l = sFrame,sFrame if record then f,l = 1,framecount end - + for i=f,l do frames[i] = { } end @@ -1470,9 +1470,9 @@ end local function floodFill(x, y, targetColour, newColour) if not newColour or not targetColour then return end local nodeList = { } - + table.insert(nodeList, {x = x, y = y}) - + while #nodeList > 0 do local node = nodeList[1] if frames[sFrame][node.y] and frames[sFrame][node.y][node.x] == targetColour then @@ -1486,8 +1486,8 @@ local function floodFill(x, y, targetColour, newColour) end end ---[[ - Section: Animation Tools +--[[ + Section: Animation Tools ]]-- --[[Enters play mode, allowing the animation to play through. Interface is restricted to allow this, @@ -1498,14 +1498,14 @@ end local function playAnimation() state = "play" selectedrect = nil - + local animt = os.startTimer(animtime) repeat drawCanvas() drawInterface() - + local id,key,_,y = os.pullEvent() - + if id=="timer" then if key == animt then animt = os.startTimer(animtime) @@ -1536,15 +1536,15 @@ local function changeFrame(newframe) term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.grey) term.clearLine() - + term.write("Go to frame: ") newframe = tonumber(readInput(2)) if not newframe or newframe <= 0 then inMenu = false - return + return end elseif newframe <= 0 then return end - + if newframe > framecount then for i=framecount+1,newframe do frames[i] = {} @@ -1570,12 +1570,12 @@ local function removeFramesAfter(frame) if frame==framecount then return end drawMessage("Remove frames "..(frame+1).."/"..framecount.."? Y/N :") local answer = string.upper(readInput(1)) - - if string.find(answer, string.upper("Y")) ~= 1 then + + if string.find(answer, string.upper("Y")) ~= 1 then inMenu = false - return + return end - + for i=frame+1, framecount do frames[i] = nil end @@ -1596,7 +1596,7 @@ end local function getLeft(curx, curz) local hand = "left" if layering == "up" then hand = "right" end - + if hand == "right" then if curx == 1 then return 0,-1 end if curx == -1 then return 0,1 end @@ -1619,7 +1619,7 @@ end local function getRight(curx, curz) local hand = "left" if layering == "up" then hand = "right" end - + if hand == "right" then if curx == 1 then return 0,1 end if curx == -1 then return 0,-1 end @@ -1647,7 +1647,7 @@ local function locatePrinters() drawCanvas() drawInterface() state = oldState - + local modemOpened = false for k,v in pairs(rs.getSides()) do if peripheral.isPresent(v) and peripheral.getType(v) == "modem" then @@ -1656,17 +1656,17 @@ local function locatePrinters() break end end - + if not modemOpened then displayConfirmDialogue("Modem not found!", "No modem peripheral. Must have network modem to locate printers.") return false end - + rednet.broadcast("$3DPRINT IDENTIFY") - + while true do local id, msg = rsTimeReceive(1) - + if not id then break end if string.find(msg, "$3DPRINT IDACK") == 1 then msg = string.gsub(msg, "$3DPRINT IDACK ", "") @@ -1674,7 +1674,7 @@ local function locatePrinters() table.insert(printerNames, msg) end end - + if #printerList == 0 then displayConfirmDialogue("Printers not found!", "No active printers found in proximity of this computer.") return false @@ -1692,7 +1692,7 @@ local function sendPC(command,param) local msg = "$PC "..command if param then msg = msg.." "..param end rednet.send(printerList[selectedPrinter], msg) - + while true do local id,key = rsTimeReceive() if id == printerList[selectedPrinter] then @@ -1713,7 +1713,7 @@ local function sendPC(command,param) end end end - + --Changes to position are handled after the event has been successfully completed if command == "FW" then px = px + pfx @@ -1724,13 +1724,13 @@ local function sendPC(command,param) elseif command == "UP" then if layering == "up" then py = py + 1 - else + else py = py - 1 end elseif command == "DW" then if layering == "up" then py = py - 1 - else + else py = py + 1 end elseif command == "TL" then @@ -1741,7 +1741,7 @@ local function sendPC(command,param) pfx = -pfx pfz = -pfz end - + drawCanvas() drawInterface() end @@ -1788,7 +1788,7 @@ local function performPrint() --An up layering starts our builder bot on the bottom left corner of our build px,py,pz = leflim, 0, botlim + 1 pfx,pfz = 0,-1 - + --We move him forward and up a bit from his original position. sendPC("FW") sendPC("UP") @@ -1801,7 +1801,7 @@ local function performPrint() else rowbot,rowtop,rowinc = toplim,botlim,1 end - + for rows = rowbot,rowtop,rowinc do --Then we decide if we're going left or right, depending on what side we're on local linebot,linetop,lineinc = nil,nil,nil @@ -1814,7 +1814,7 @@ local function performPrint() turnToFace(-1,0) linebot,linetop,lineinc = riglim,leflim,-1 end - + for lines = linebot,linetop,lineinc do --We move our turtle forward, placing the right material at each step local material = frames[py][pz][px] @@ -1827,7 +1827,7 @@ local function performPrint() sendPC("FW") end end - + --The printer then has to do a U-turn, depending on which way he's facing and --which way he needs to go local temppfx,temppfz = getLeft(pfx,pfz) @@ -1873,7 +1873,7 @@ local function performPrint() while pz < #frames do sendPC("FW") end - + --For each layer in the frame we build our wall, the move back for layers = 1,#frames do --We first decide if we're going left or right based on our position @@ -1883,7 +1883,7 @@ local function performPrint() else rowbot,rowtop,rowinc = riglim,leflim,-1 end - + for rows = rowbot,rowtop,rowinc do --Then we decide if we're going up or down, depending on our given altitude local linebot,linetop,lineinc = nil,nil,nil @@ -1892,7 +1892,7 @@ local function performPrint() else linebot,linetop,lineinc = toplim,botlim,1 end - + for lines = linebot,linetop,lineinc do --We move our turtle up/down, placing the right material at each step local material = frames[pz][py][px] @@ -1906,14 +1906,14 @@ local function performPrint() else sendPC("UP") end end end - + if rows ~= rowtop then turnToFace(rowinc,0) sendPC("FW") turnToFace(0,1) end end - + if layers ~= #frames then sendPC("TU") sendPC("FW") @@ -1927,14 +1927,14 @@ local function performPrint() end turnToFace(0,1) end - + sendPC("DE") - + displayConfirmDialogue("Print complete", "The 3D print was successful.") end ---[[ - Section: Interface +--[[ + Section: Interface ]]-- --[[Runs the printing interface. Allows users to find/select a printer, the style of printing to perform and to begin the operation @@ -1953,7 +1953,7 @@ local function runPrintInterface() if not locatePrinters() then return false end - + layering = "up" requirementsDisplayed = false selectedPrinter = 1 @@ -1967,7 +1967,7 @@ local function runPrintInterface() drawInterface() term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.black) - + local msg = "3D Printing" term.setCursorPos(w/2-#msg/2 - 2, 1) term.write(msg) @@ -1982,7 +1982,7 @@ local function runPrintInterface() term.write(msg) term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.black) - + term.setCursorPos(7, 2) term.write("Layering") drawPictureTable(layerUpIcon, 3, 3, colours.white) @@ -2001,7 +2001,7 @@ local function runPrintInterface() end term.setCursorPos(12, 9) term.write("Forward") - + term.setBackgroundColour(colours.lightGrey) term.setTextColour(colours.black) term.setCursorPos(31, 2) @@ -2014,16 +2014,16 @@ local function runPrintInterface() term.setTextColour(colours.red) end term.write(" "..printerNames[selectedPrinter].." ") - + term.setBackgroundColour(colours.grey) term.setTextColour(colours.lightGrey) term.setCursorPos(25, 10) term.write(" Cancel ") term.setCursorPos(40, 10) term.write(" Print ") - + local id, p1, p2, p3 = os.pullEvent() - + if id == "timer" then updateTimer(p1) elseif id == "mouse_click" then @@ -2052,7 +2052,7 @@ local function runPrintInterface() ready = false while true do local id,msg = rsTimeReceive(10) - + if id == printerList[selectedPrinter] and msg == "$3DPRINT ACTACK" then ready = true break @@ -2077,100 +2077,100 @@ end ]]-- local function performSelection(mode) if not mode or mode == "" then return - + elseif mode == "help" then drawHelpScreen() - + elseif mode == "blueprint on" then blueprint = true ddModes[2][3] = "blueprint off" - + elseif mode == "blueprint off" then blueprint = false ddModes[2][3] = "blueprint on" - + elseif mode == "layers on" then layerDisplay = true ddModes[2][4] = "layers off" - + elseif mode == "layers off" then layerDisplay = false ddModes[2][4] = "layers on" - + elseif mode == "direction on" then printDirection = true ddModes[2][5] = "direction off" - + elseif mode == "direction off" then printDirection = false ddModes[2][5] = "direction on" - + elseif mode == "go to" then changeFrame() - + elseif mode == "remove" then removeFramesAfter(sFrame) - + elseif mode == "play" then playAnimation() - + elseif mode == "copy" then if selectrect and selectrect.x1 ~= selectrect.x2 then copyToBuffer(false) end - + elseif mode == "cut" then - if selectrect and selectrect.x1 ~= selectrect.x2 then + if selectrect and selectrect.x1 ~= selectrect.x2 then copyToBuffer(true) end - + elseif mode == "paste" then - if selectrect and selectrect.x1 ~= selectrect.x2 then + if selectrect and selectrect.x1 ~= selectrect.x2 then copyFromBuffer(false) end - + elseif mode == "hide" then selectrect = nil if state == "select" then state = "corner select" end - + elseif mode == "alpha to left" then if lSel then alphaC = lSel end - + elseif mode == "alpha to right" then if rSel then alphaC = rSel end - + elseif mode == "record" then record = not record - + elseif mode == "clear" then if state=="select" then buffer = nil else clearImage() end - + elseif mode == "select" then if state=="corner select" or state=="select" then state = "paint" elseif selectrect and selectrect.x1 ~= selectrect.x2 then state = "select" else - state = "corner select" + state = "corner select" end - + elseif mode == "print" then state = "print" runPrintInterface() state = "paint" - + elseif mode == "save" then if animated then saveNFA(sPath) elseif textEnabled then saveNFT(sPath) else saveNFP(sPath) end - + elseif mode == "exit" then isRunning = false - + elseif mode ~= state then state = mode else state = "paint" - + end end @@ -2184,12 +2184,12 @@ local function handleEvents() while isRunning do drawCanvas() drawInterface() - + if state == "text" then term.setCursorPos(textCurX - sx, textCurY - sy) term.setCursorBlink(true) end - + local id,p1,p2,p3 = os.pullEvent() term.setCursorBlink(false) if id=="timer" then @@ -2212,20 +2212,20 @@ local function handleEvents() if state=="pippette" then if p1==1 then if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then - lSel = frames[sFrame][p3+sy][p2+sx] + lSel = frames[sFrame][p3+sy][p2+sx] end elseif p1==2 then if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then - rSel = frames[sFrame][p3+sy][p2+sx] + rSel = frames[sFrame][p3+sy][p2+sx] end end elseif state=="move" then updateImageLims(record) moveImage(p2,p3) elseif state=="flood" then - if p1 == 1 and lSel and frames[sFrame][p3+sy] then + if p1 == 1 and lSel and frames[sFrame][p3+sy] then floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],lSel) - elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then + elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],rSel) end elseif state=="corner select" then @@ -2234,10 +2234,10 @@ local function handleEvents() elseif selectrect.x1 ~= p2+sx and selectrect.y1 ~= p3+sy then if p2+sx w + sx - 2 then sx = textCurX - w + 2 end elseif tonumber(p1) then @@ -2335,16 +2335,16 @@ local function handleEvents() textCurY = textCurY+1 if textCurY > h + sy - 1 then sy = textCurY - h + 1 end end - + elseif p1==keys.leftCtrl then - local sel = displayDropDown(1, h-1, ddModes[#ddModes]) + local sel = displayDropDown(1, h-1, ddModes[#ddModes]) performSelection(sel) elseif p1==keys.leftAlt then - local sel = displayDropDown(1, h-1, ddModes[1]) + local sel = displayDropDown(1, h-1, ddModes[1]) performSelection(sel) - elseif p1==keys.h then + elseif p1==keys.h then performSelection("help") - elseif p1==keys.x then + elseif p1==keys.x then performSelection("cut") elseif p1==keys.c then performSelection("copy") @@ -2415,7 +2415,7 @@ local function handleEvents() selectrect.y1 = selectrect.y1-1 selectrect.y2 = selectrect.y2-1 elseif sy > 0 then sy=sy-1 end - elseif p1==keys.down then + elseif p1==keys.down then if state == "move" then updateImageLims(record) if toplim and leflim then @@ -2431,7 +2431,7 @@ local function handleEvents() end --[[ - Section: Main + Section: Main ]]-- if not term.isColour() then @@ -2475,15 +2475,15 @@ if fs.exists(sPath) then print("Can only edit .nfp, .nft and .nfa files:",string.find(sPath, ".nfp"),#sPath-3) return end - + if string.find(sPath, ".nfa") == #sPath-3 then animated = true end - + if string.find(sPath, ".nft") == #sPath-3 then textEnabled = true - end - + end + if string.find(sPath, ".nfp") == #sPath-3 and animated then print("Convert to nfa? Y/N") if string.find(string.lower(io.read()), "y") then @@ -2494,24 +2494,24 @@ if fs.exists(sPath) then animated = false end end - + --Again this is possible, I just haven't done it. Maybe I will? if textEnabled and (string.find(sPath, ".nfp") == #sPath-3 or string.find(sPath, ".nfa") == #sPath-3) then print("Cannot convert to nft") end else - if not animated and not textEnabled and string.find(sPath, ".nfp") ~= #sPath-3 then + if not animated and not textEnabled and string.find(sPath, ".nfp") ~= #sPath-3 then sPath = sPath..".nfp" - elseif animated and string.find(sPath, ".nfa") ~= #sPath-3 then + elseif animated and string.find(sPath, ".nfa") ~= #sPath-3 then sPath = sPath..".nfa" elseif textEnabled and string.find(sPath, ".nft") ~= #sPath-3 then sPath = sPath..".nft" end -end +end drawLogo() init() handleEvents() term.setBackgroundColour(colours.black) -shell.run("clear") \ No newline at end of file +shell.run("clear") diff --git a/src/main/resources/assets/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua b/src/main/resources/assets/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua index bcd57c718..2a1a447a4 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua @@ -175,4 +175,4 @@ drawScreen() while true do loop() parallel.waitForAny(loop, compute) -end \ No newline at end of file +end diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index d1b0ad599..ac64ad565 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -13,7 +13,7 @@ -- -- @tparam string func The function's name -- @tparam int idx The argument index to this function --- @tparam string ty The type this argument should have. May be 'value' for +-- @tparam string ty The type this argument should have. May be 'value' for -- any non-nil value. -- @param val val The value to check -- @throws If this value doesn't match the expected type. diff --git a/src/test/resources/test-rom/spec/programs/delete_spec.lua b/src/test/resources/test-rom/spec/programs/delete_spec.lua index 5036f7eae..1eec95cc4 100644 --- a/src/test/resources/test-rom/spec/programs/delete_spec.lua +++ b/src/test/resources/test-rom/spec/programs/delete_spec.lua @@ -39,7 +39,7 @@ describe("The rm program", function() expect(capture(stub, "rm")) :matches { ok = true, output = "Usage: rm \n", error = "" } end) - + it("errors when trying to delete a read-only file", function() expect(capture(stub, "rm /rom/startup.lua")) :matches { ok = true, output = "", error = "/rom/startup.lua: Access denied\n" } diff --git a/src/test/resources/test-rom/spec/programs/edit_spec.lua b/src/test/resources/test-rom/spec/programs/edit_spec.lua index 7ca0b04f2..e58938e23 100644 --- a/src/test/resources/test-rom/spec/programs/edit_spec.lua +++ b/src/test/resources/test-rom/spec/programs/edit_spec.lua @@ -2,7 +2,7 @@ local capture = require "test_helpers".capture_program describe("The edit program", function() - it("displays its usage when given no argument", function() + it("displays its usage when given no argument", function() expect(capture(stub, "edit")) :matches { ok = true, output = "Usage: edit \n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua index 5b13d59a9..831d88fc1 100644 --- a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -51,7 +51,7 @@ describe("The pastebin program", function() local file = fs.open( "testup", "w" ) file.close() - + expect(capture(stub, "pastebin", "put", "testup" )) :matches { ok = true, output = "Connecting to pastebin.com... Success.\nUploaded as https://pastebin.com/abcde\nRun \"pastebin get abcde\" to download anywhere\n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/id_spec.lua b/src/test/resources/test-rom/spec/programs/id_spec.lua index 73206e7fb..7c5d47da7 100644 --- a/src/test/resources/test-rom/spec/programs/id_spec.lua +++ b/src/test/resources/test-rom/spec/programs/id_spec.lua @@ -1,7 +1,7 @@ local capture = require "test_helpers".capture_program describe("The id program", function() - + it("displays computer id", function() local id = os.getComputerID() diff --git a/src/test/resources/test-rom/spec/programs/motd_spec.lua b/src/test/resources/test-rom/spec/programs/motd_spec.lua index 3781e2e16..72becbf30 100644 --- a/src/test/resources/test-rom/spec/programs/motd_spec.lua +++ b/src/test/resources/test-rom/spec/programs/motd_spec.lua @@ -7,7 +7,7 @@ describe("The motd program", function() file.write("Hello World!") file.close() settings.set("motd.path", "/modt_check.txt") - + expect(capture(stub, "motd")) :matches { ok = true, output = "Hello World!\n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/set_spec.lua b/src/test/resources/test-rom/spec/programs/set_spec.lua index 64dba1447..46cf0b84d 100644 --- a/src/test/resources/test-rom/spec/programs/set_spec.lua +++ b/src/test/resources/test-rom/spec/programs/set_spec.lua @@ -6,7 +6,7 @@ describe("The set program", function() settings.clear() settings.set("Test", "Hello World!") settings.set("123", 456) - + expect(capture(stub, "set")) :matches { ok = true, output = '"123" is 456\n"Test" is "Hello World!"\n', error = "" } end) @@ -15,12 +15,12 @@ describe("The set program", function() settings.clear() settings.set("Test", "Hello World!") settings.set("123", 456) - + expect(capture(stub, "set Test")) :matches { ok = true, output = '"Test" is "Hello World!"\n', error = "" } end) - it("set a setting", function() + it("set a setting", function() expect(capture(stub, "set Test Hello")) :matches { ok = true, output = '"Test" set to "Hello"\n', error = "" } diff --git a/src/test/resources/test-rom/spec/programs/time_spec.lua b/src/test/resources/test-rom/spec/programs/time_spec.lua index e9c1eff31..91f82fef0 100644 --- a/src/test/resources/test-rom/spec/programs/time_spec.lua +++ b/src/test/resources/test-rom/spec/programs/time_spec.lua @@ -5,7 +5,7 @@ describe("The time program", function() it("displays time", function() local time = textutils.formatTime(os.time()) local day = os.day() - + expect(capture(stub, "time")) :matches { ok = true, output = "The time is " .. time .. " on Day " .. day .. "\n", error = "" } end) diff --git a/tools/check-lines.py b/tools/check-lines.py new file mode 100644 index 000000000..e1fcba620 --- /dev/null +++ b/tools/check-lines.py @@ -0,0 +1,28 @@ +import pathlib, sys + +problems = False + +# Skip images and files without extensions +exclude = [ ".png", "" ] + +for path in pathlib.Path(".").glob("src/**/*"): + if path.is_dir() or path.suffix in exclude: + continue + + with path.open(encoding="utf-8") as file: + has_dos, has_trailing, needs_final = False, False, False + for i, line in enumerate(file): + if len(line) >= 2 and line[-2] == "\r" and line[-1] == "\n" and not has_line: + print("%s has contains '\\r\\n' on line %d" % (path, i + 1)) + problems = has_dos = True + + if len(line) >= 2 and line[-2] in " \t" and line[-1] == "\n" and not has_trailing: + print("%s has trailing whitespace on line %d" % (path, i + 1)) + problems = has_trailing = True + + if line is not None and len(line) >= 1 and line[-1] != "\n": + print("%s should end with '\\n'" % path) + problems = True + +if problems: + sys.exit(1) From fb440b0d2e09d048ab519062a1fa09e7908560c3 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Jan 2020 11:14:30 +0000 Subject: [PATCH 139/711] Update to 1.15 Most of the port is pretty simple. The main problems are regarding changes to Minecraft's rendering system. - Remove several rendering tweaks until Forge's compatibility it brought up-to-date - Map rendering for pocket computers and printouts - Item frame rendering for printouts - Custom block outlines for monitors and cables/wired modems - Custom breaking progress for cables/wired modems - Turtle "Dinnerbone" rendering is currently broken, as normals are not correctly transformed. - Rewrite FixedWidthFontRenderer to to the buffer in a single sweep. In order to do this, the term_font now also bundles a "background" section, which is just a blank region of the screen. - Render monitors using a VBO instead of a call list. I haven't compared performance yet, but it manages to render a 6x5 array of _static_ monitors at almost 60fps, which seems pretty reasonable. --- build.gradle | 29 +- config/checkstyle/checkstyle.xml | 4 + gradle.properties | 6 +- .../api/client/TransformedModel.java | 61 +++ .../api/turtle/ITurtleUpgrade.java | 9 +- .../computercraft/client/ClientRegistry.java | 45 +-- .../client/gui/FixedWidthFontRenderer.java | 381 ++++++++++++------ .../computercraft/client/gui/GuiComputer.java | 4 +- .../client/gui/GuiDiskDrive.java | 4 +- .../computercraft/client/gui/GuiPrinter.java | 4 +- .../computercraft/client/gui/GuiPrintout.java | 12 +- .../computercraft/client/gui/GuiTurtle.java | 6 +- .../client/gui/widgets/WidgetTerminal.java | 114 +----- .../proxy/ComputerCraftProxyClient.java | 21 +- .../client/render/ItemMapLikeRenderer.java | 117 ------ .../client/render/ModelTransformer.java | 269 ------------- .../client/render/PrintoutRenderer.java | 42 +- .../render/TileEntityMonitorRenderer.java | 327 +++++---------- .../render/TileEntityTurtleRenderer.java | 245 +++++------ .../client/render/TurtleModelLoader.java | 70 +--- .../client/render/TurtleMultiModel.java | 58 +-- .../client/render/TurtleSmartItemModel.java | 47 +-- .../CableHighlightRenderer.java | 35 +- .../render_old/ItemMapLikeRenderer.java | 133 ++++++ .../ItemPocketRenderer.java | 53 +-- .../ItemPrintoutRenderer.java | 32 +- .../MonitorHighlightRenderer.java | 79 ++-- .../TileEntityCableRenderer.java | 33 +- .../dan200/computercraft/shared/Config.java | 2 +- .../shared/common/BlockGeneric.java | 9 +- .../shared/common/TileGeneric.java | 6 +- .../computer/blocks/TileComputerBase.java | 12 +- .../shared/network/NetworkHandler.java | 10 +- .../peripheral/diskdrive/TileDiskDrive.java | 11 +- .../peripheral/modem/wired/BlockCable.java | 7 - .../peripheral/modem/wired/TileCable.java | 11 +- .../modem/wired/TileWiredModemFull.java | 8 +- .../peripheral/monitor/BlockMonitor.java | 19 +- .../peripheral/monitor/ClientMonitor.java | 36 +- .../peripheral/monitor/TileMonitor.java | 10 +- .../peripheral/printer/TilePrinter.java | 15 +- .../shared/pocket/apis/PocketAPI.java | 4 +- .../proxy/ComputerCraftProxyCommon.java | 8 - .../shared/turtle/blocks/TileTurtle.java | 12 +- .../shared/turtle/core/TurtleBrain.java | 3 +- .../turtle/core/TurtlePlaceCommand.java | 21 +- .../shared/turtle/core/TurtlePlayer.java | 7 +- .../turtle/upgrades/TurtleCraftingTable.java | 20 +- .../shared/turtle/upgrades/TurtleModem.java | 32 +- .../shared/turtle/upgrades/TurtleSpeaker.java | 19 +- .../shared/turtle/upgrades/TurtleTool.java | 22 +- .../computercraft/shared/util/NBTUtil.java | 6 +- .../computercraft/shared/util/WorldUtil.java | 10 +- .../resources/META-INF/accesstransformer.cfg | 4 +- src/main/resources/META-INF/mods.toml | 4 +- .../models/block/turtle_advanced.json | 6 +- .../models/block/turtle_advanced_base.json | 6 + .../models/block/turtle_elf_overlay.json | 2 +- .../models/block/turtle_normal.json | 6 +- .../models/block/turtle_normal_base.json | 6 + ...ormal_overlay.json => turtle_overlay.json} | 0 .../textures/gui/term_background.png | Bin 123 -> 0 bytes .../computercraft/textures/gui/term_font.png | Bin 1245 -> 3904 bytes .../computercraft/lua/rom/help/changelog.txt | 2 + .../computercraft/lua/rom/help/whatsnew.txt | 2 + 65 files changed, 1066 insertions(+), 1532 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/client/TransformedModel.java delete mode 100644 src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java delete mode 100644 src/main/java/dan200/computercraft/client/render/ModelTransformer.java rename src/main/java/dan200/computercraft/client/{render => render_old}/CableHighlightRenderer.java (71%) create mode 100644 src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java rename src/main/java/dan200/computercraft/client/{render => render_old}/ItemPocketRenderer.java (84%) rename src/main/java/dan200/computercraft/client/{render => render_old}/ItemPrintoutRenderer.java (80%) rename src/main/java/dan200/computercraft/client/{render => render_old}/MonitorHighlightRenderer.java (56%) rename src/main/java/dan200/computercraft/client/{render => render_old}/TileEntityCableRenderer.java (84%) create mode 100644 src/main/resources/assets/computercraft/models/block/turtle_advanced_base.json create mode 100644 src/main/resources/assets/computercraft/models/block/turtle_normal_base.json rename src/main/resources/assets/computercraft/models/block/{turtle_normal_overlay.json => turtle_overlay.json} (100%) delete mode 100644 src/main/resources/assets/computercraft/textures/gui/term_background.png diff --git a/build.gradle b/build.gradle index 10b5f77f8..98eb01cc3 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.154' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.159' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } @@ -73,14 +73,6 @@ repositories { name "SquidDev" url "https://squiddev.cc/maven" } - ivy { - name "Charset" - artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" - } - maven { - name "Amadornes" - url "https://maven.amadornes.com/" - } maven { name "CraftTweaker" url "https://maven.blamejared.com/" @@ -98,10 +90,8 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.25:api") - compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.14.4:5.0.1.150") - - runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.25") + compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.2:api") + runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.2") shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' @@ -111,6 +101,15 @@ dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" } +sourceSets { + main { + java { + exclude 'dan200/computercraft/client/render_old' + exclude 'dan200/computercraft/shared/integration/crafttweaker' + } + } +} + // Compile tasks javadoc { @@ -372,7 +371,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'release' + releaseType = 'alpha' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { @@ -450,7 +449,7 @@ githubRelease { .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() } - prerelease false + prerelease true } def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 77ce7f67d..6cc5fe765 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -10,6 +10,10 @@ + + + + diff --git a/gradle.properties b/gradle.properties index 4654613df..cc2ce1680 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.86.2 # Minecraft properties (update mods.toml when changing) -mc_version=1.14.4 -forge_version=28.1.71 -mappings_version=20191123-1.14.3 +mc_version=1.15.2 +forge_version=31.0.1 +mappings_version=20200124-1.15.1 diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java new file mode 100644 index 000000000..c4c88eec3 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -0,0 +1,61 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.TransformationMatrix; +import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.model.ModelManager; +import net.minecraft.client.renderer.model.ModelResourceLocation; +import net.minecraft.item.ItemStack; + +import javax.annotation.Nonnull; +import java.util.Objects; + +/** + * A model to render, combined with a transformation matrix to apply. + */ +public final class TransformedModel +{ + private final IBakedModel model; + private final TransformationMatrix matrix; + + public TransformedModel( @Nonnull IBakedModel model, @Nonnull TransformationMatrix matrix ) + { + this.model = Objects.requireNonNull( model ); + this.matrix = Objects.requireNonNull( matrix ); + } + + public TransformedModel( @Nonnull IBakedModel model ) + { + this.model = Objects.requireNonNull( model ); + this.matrix = TransformationMatrix.identity(); + } + + public static TransformedModel of( @Nonnull ModelResourceLocation location ) + { + ModelManager modelManager = Minecraft.getInstance().getModelManager(); + return new TransformedModel( modelManager.getModel( location ) ); + } + + public static TransformedModel of( @Nonnull ItemStack item, @Nonnull TransformationMatrix transform ) + { + IBakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getItemModel( item ); + return new TransformedModel( model, transform ); + } + + @Nonnull + public IBakedModel getModel() + { + return model; + } + + @Nonnull + public TransformationMatrix getMatrix() + { + return matrix; + } +} diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index f9636421a..70d80e38c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -6,10 +6,10 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; @@ -18,11 +18,9 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.world.BlockEvent; -import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.vecmath.Matrix4f; /** * The primary interface for defining an update for Turtles. A turtle update @@ -126,12 +124,11 @@ public interface ITurtleUpgrade * * @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models! * @param side Which side of the turtle (left or right) the upgrade resides on. - * @return The model that you wish to be used to render your upgrade, and a transformation to apply to it. Returning - * a transformation of {@code null} has the same effect as the identify matrix. + * @return The model that you wish to be used to render your upgrade. */ @Nonnull @OnlyIn( Dist.CLIENT ) - Pair getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side ); + TransformedModel getModel( @Nullable ITurtleAccess turtle, @Nonnull TurtleSide side ); /** * Called once per tick for each turtle which has the upgrade equipped. diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index e6fab7952..f1d123281 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -11,20 +11,19 @@ import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IUnbakedModel; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.inventory.container.PlayerContainer; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.event.ModelBakeEvent; import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.TextureStitchEvent; -import net.minecraftforge.client.model.BasicState; import net.minecraftforge.client.model.ModelLoader; import net.minecraftforge.client.model.ModelLoaderRegistry; +import net.minecraftforge.client.model.SimpleModelTransform; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -71,13 +70,13 @@ public final class ClientRegistry @SubscribeEvent public static void registerModels( ModelRegistryEvent event ) { - ModelLoaderRegistry.registerLoader( TurtleModelLoader.INSTANCE ); + ModelLoaderRegistry.registerLoader( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ), TurtleModelLoader.INSTANCE ); } @SubscribeEvent public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) { - if( event.getMap() != Minecraft.getInstance().getTextureMap() ) return; + if( !event.getMap().getBasePath().equals( PlayerContainer.LOCATION_BLOCKS_TEXTURE ) ) return; for( String extra : EXTRA_TEXTURES ) { @@ -92,29 +91,18 @@ public final class ClientRegistry ModelLoader loader = event.getModelLoader(); Map registry = event.getModelRegistry(); - for( String model : EXTRA_MODELS ) + for( String modelName : EXTRA_MODELS ) { - IBakedModel bakedModel = bake( loader, loader.getUnbakedModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/" + model ) ) ); + ResourceLocation location = new ResourceLocation( ComputerCraft.MOD_ID, "item/" + modelName ); + IUnbakedModel model = loader.getUnbakedModel( location ); + model.getTextures( loader::getUnbakedModel, new HashSet<>() ); - if( bakedModel != null ) + IBakedModel baked = model.bakeModel( loader, ModelLoader.defaultTextureGetter(), SimpleModelTransform.IDENTITY, location ); + if( baked != null ) { - registry.put( - new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, model ), "inventory" ), - bakedModel - ); + registry.put( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, modelName ), "inventory" ), baked ); } } - - // And load the custom turtle models in too. - registry.put( - new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), "inventory" ), - bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_normal" ) ) ) - ); - - registry.put( - new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), "inventory" ), - bake( loader, TurtleModelLoader.INSTANCE.loadModel( new ResourceLocation( ComputerCraft.MOD_ID, "item/turtle_advanced" ) ) ) - ); } @SubscribeEvent @@ -153,15 +141,4 @@ public final class ClientRegistry ComputerCraft.Blocks.turtleNormal, ComputerCraft.Blocks.turtleAdvanced ); } - - private static IBakedModel bake( ModelLoader loader, IUnbakedModel model ) - { - model.getTextures( loader::getUnbakedModel, new HashSet<>() ); - - return model.bake( - loader, - ModelLoader.defaultTextureGetter(), - new BasicState( model.getDefaultState(), false ), DefaultVertexFormats.BLOCK - ); - } } diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index ebc42734d..b86131df3 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -5,195 +5,322 @@ */ package dan200.computercraft.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; -import java.util.Arrays; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class FixedWidthFontRenderer { + private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix(); + private static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" ); - public static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/term_background.png" ); public static final int FONT_HEIGHT = 9; public static final int FONT_WIDTH = 6; + public static final float WIDTH = 256.0f; - private static FixedWidthFontRenderer instance; + public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; + public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; - public static FixedWidthFontRenderer instance() - { - if( instance != null ) return instance; - return instance = new FixedWidthFontRenderer(); - } - - private final TextureManager m_textureManager; + public static final RenderType TYPE = Type.MAIN; private FixedWidthFontRenderer() { - m_textureManager = Minecraft.getInstance().getTextureManager(); } - private static void greyscaleify( double[] rgb ) + private static float toGreyscale( double[] rgb ) { - Arrays.fill( rgb, (rgb[0] + rgb[1] + rgb[2]) / 3.0f ); + return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); } - private void drawChar( BufferBuilder renderer, double x, double y, int index, int color, Palette p, boolean greyscale ) + private static void drawChar( Matrix4f transform, IVertexBuilder buffer, float x, float y, int index, float r, float g, float b ) { int column = index % 16; int row = index / 16; - double[] colour = p.getColour( 15 - color ); - if( greyscale ) - { - greyscaleify( colour ); - } - float r = (float) colour[0]; - float g = (float) colour[1]; - float b = (float) colour[2]; - int xStart = 1 + column * (FONT_WIDTH + 2); int yStart = 1 + row * (FONT_HEIGHT + 2); - renderer.pos( x, y, 0.0 ).tex( xStart / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( xStart / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( xStart / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + FONT_WIDTH, y + FONT_HEIGHT, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, x, y, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, yStart / WIDTH ).endVertex(); + buffer.pos( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); + buffer.pos( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex(); + buffer.pos( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex(); + buffer.pos( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); + buffer.pos( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); } - private void drawQuad( BufferBuilder renderer, double x, double y, int color, double width, Palette p, boolean greyscale ) + private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, float r, float g, float b ) { - double[] colour = p.getColour( 15 - color ); - if( greyscale ) + buffer.pos( transform, x, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_START ).endVertex(); + buffer.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex(); + buffer.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex(); + buffer.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex(); + buffer.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex(); + buffer.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_END ).endVertex(); + } + + private static void drawBackground( + @Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y, + @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, + float leftMarginSize, float rightMarginSize, float height + ) + { + if( leftMarginSize > 0 ) { - greyscaleify( colour ); - } - float r = (float) colour[0]; - float g = (float) colour[1]; - float b = (float) colour[2]; - - renderer.pos( x, y, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + width, y, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + width, y, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + width, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - } - - private boolean isGreyScale( int colour ) - { - return colour == 0 || colour == 15 || colour == 7 || colour == 8; - } - - public void drawStringBackgroundPart( int x, int y, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale, Palette p ) - { - // Draw the quads - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder renderer = tessellator.getBuffer(); - renderer.begin( GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR ); - if( leftMarginSize > 0.0 ) - { - int colour1 = "0123456789abcdef".indexOf( backgroundColour.charAt( 0 ) ); - if( colour1 < 0 || (greyScale && !isGreyScale( colour1 )) ) + double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( backgroundColour.charAt( 0 ) ) ); + float r, g, b; + if( greyscale ) { - colour1 = 15; + r = g = b = toGreyscale( colour ); } - drawQuad( renderer, x - leftMarginSize, y, colour1, leftMarginSize, p, greyScale ); - } - if( rightMarginSize > 0.0 ) - { - int colour2 = "0123456789abcdef".indexOf( backgroundColour.charAt( backgroundColour.length() - 1 ) ); - if( colour2 < 0 || (greyScale && !isGreyScale( colour2 )) ) + else { - colour2 = 15; + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; } - drawQuad( renderer, x + backgroundColour.length() * FONT_WIDTH, y, colour2, rightMarginSize, p, greyScale ); + + drawQuad( transform, renderer, x - leftMarginSize, y, leftMarginSize, height, r, g, b ); } + + if( rightMarginSize > 0 ) + { + double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( backgroundColour.charAt( backgroundColour.length() - 1 ) ) ); + float r, g, b; + if( greyscale ) + { + r = g = b = toGreyscale( colour ); + } + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; + } + + drawQuad( transform, renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, r, g, b ); + } + for( int i = 0; i < backgroundColour.length(); i++ ) { - int colour = "0123456789abcdef".indexOf( backgroundColour.charAt( i ) ); - if( colour < 0 || (greyScale && !isGreyScale( colour )) ) + double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( backgroundColour.charAt( i ) ) ); + float r, g, b; + if( greyscale ) { - colour = 15; + r = g = b = toGreyscale( colour ); } - drawQuad( renderer, x + i * FONT_WIDTH, y, colour, FONT_WIDTH, p, greyScale ); + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; + } + + drawQuad( transform, renderer, x + i * FONT_WIDTH, y, FONT_WIDTH, height, r, g, b ); } - GlStateManager.disableTexture(); - tessellator.draw(); - GlStateManager.enableTexture(); } - public void drawStringTextPart( int x, int y, TextBuffer s, TextBuffer textColour, boolean greyScale, Palette p ) + public static void drawString( + @Nonnull Matrix4f transform, @Nonnull IVertexBuilder renderer, float x, float y, + @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, + @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize + ) { - // Draw the quads - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder renderer = tessellator.getBuffer(); - renderer.begin( GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_TEX_COLOR ); - for( int i = 0; i < s.length(); i++ ) + if( backgroundColour != null ) { - // Switch colour - int colour = "0123456789abcdef".indexOf( textColour.charAt( i ) ); - if( colour < 0 || (greyScale && !isGreyScale( colour )) ) + drawBackground( transform, renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT ); + } + + for( int i = 0; i < text.length(); i++ ) + { + double[] colour = palette.getColour( 15 - "0123456789abcdef".indexOf( textColour.charAt( i ) ) ); + float r, g, b; + if( greyscale ) { - colour = 0; + r = g = b = toGreyscale( colour ); + } + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; } // Draw char - int index = s.charAt( i ); - if( index < 0 || index > 255 ) + int index = text.charAt( i ); + if( index > 255 ) index = '?'; + drawChar( transform, renderer, x + i * FONT_WIDTH, y, index, r, g, b ); + } + + } + + public static void drawString( + float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, + @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize + ) + { + Minecraft.getInstance().getTextureManager().bindTexture( FONT ); + // TODO: RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + + IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); + drawString( IDENTITY, ((IRenderTypeBuffer) renderer).getBuffer( TYPE ), x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize ); + renderer.finish(); + } + + public static void drawTerminalWithoutCursor( + @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y, + @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + Palette palette = terminal.getPalette(); + int height = terminal.getHeight(); + + // Top and bottom margins + drawBackground( + transform, buffer, x, y - topMarginSize, + terminal.getBackgroundColourLine( 0 ), palette, greyscale, + leftMarginSize, rightMarginSize, topMarginSize + ); + + drawBackground( + transform, buffer, x, y + height * FONT_HEIGHT, + terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, + leftMarginSize, rightMarginSize, bottomMarginSize + ); + + // The main text + for( int i = 0; i < height; i++ ) + { + drawString( + transform, buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i, + terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ), + palette, greyscale, leftMarginSize, rightMarginSize + ); + } + } + + public static void drawCursor( + @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y, + @Nonnull Terminal terminal, boolean greyscale + ) + { + Palette palette = terminal.getPalette(); + int width = terminal.getWidth(); + int height = terminal.getHeight(); + + int cursorX = terminal.getCursorX(); + int cursorY = terminal.getCursorY(); + if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() ) + { + double[] colour = palette.getColour( 15 - terminal.getTextColour() ); + float r, g, b; + if( greyscale ) { - index = '?'; + r = g = b = toGreyscale( colour ); + } + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; } - drawChar( renderer, x + i * FONT_WIDTH, y, index, colour, p, greyScale ); - } - tessellator.draw(); - } - public void drawString( TextBuffer s, int x, int y, TextBuffer textColour, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale, Palette p ) - { - // Draw background - if( backgroundColour != null ) - { - // Bind the background texture - m_textureManager.bindTexture( BACKGROUND ); - - // Draw the quads - drawStringBackgroundPart( x, y, backgroundColour, leftMarginSize, rightMarginSize, greyScale, p ); - } - - // Draw text - if( s != null && textColour != null ) - { - // Bind the font texture - bindFont(); - - // Draw the quads - drawStringTextPart( x, y, s, textColour, greyScale, p ); + drawChar( transform, buffer, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', r, g, b ); } } - public int getStringWidth( String s ) + public static void drawTerminal( + @Nonnull Matrix4f transform, @Nonnull IVertexBuilder buffer, float x, float y, + @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) { - if( s == null ) - { - return 0; - } - return s.length() * FONT_WIDTH; + drawTerminalWithoutCursor( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + drawCursor( transform, buffer, x, y, terminal, greyscale ); } - public void bindFont() + public static void drawTerminal( + float x, float y, @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) { - m_textureManager.bindTexture( FONT ); - GlStateManager.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + Minecraft.getInstance().getTextureManager().bindTexture( FONT ); + // TODO: Is this the most sane thing? + RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + + IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); + IVertexBuilder buffer = renderer.getBuffer( TYPE ); + drawTerminal( IDENTITY, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + renderer.finish( TYPE ); + } + + public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height ) + { + Colour colour = Colour.Black; + drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); + } + + public static void drawEmptyTerminal( float x, float y, float width, float height ) + { + Minecraft.getInstance().getTextureManager().bindTexture( FONT ); + RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + + IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); + drawEmptyTerminal( IDENTITY, renderer, x, y, width, height ); + renderer.finish(); + } + + public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height ) + { + Colour colour = Colour.Black; + drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); + } + + private static final class Type extends RenderState + { + private static final int GL_MODE = GL11.GL_TRIANGLES; + + private static final VertexFormat FORMAT = DefaultVertexFormats.POSITION_COLOR_TEX; + + static final RenderType MAIN = RenderType.get( + "terminal_font", FORMAT, GL_MODE, 1024, + false, false, // useDelegate, needsSorting + RenderType.State.builder() + .texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap + .alpha( DEFAULT_ALPHA ) + .lightmap( LIGHTMAP_DISABLED ) + .writeMask( COLOR_WRITE ) + .build( false ) + ); + + static final RenderType BLOCKER = RenderType.get( + "terminal_blocker", FORMAT, GL_MODE, 256, + false, false, // useDelegate, needsSorting + RenderType.State.builder() + .texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap + .alpha( DEFAULT_ALPHA ) + .writeMask( DEPTH_WRITE ) + .lightmap( LIGHTMAP_DISABLED ) + .build( false ) + ); + + private Type( String name, Runnable setup, Runnable destroy ) + { + super( name, setup, destroy ); + } } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 9bcb3a458..049123de7 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; @@ -134,7 +134,7 @@ public final class GuiComputer extends Containe terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw a border around the terminal - GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); + RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); switch( m_family ) { case Normal: diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index f116ae164..59b6e38d2 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; @@ -32,7 +32,7 @@ public class GuiDiskDrive extends ContainerScreen @Override protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { - GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); + RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( BACKGROUND ); blit( guiLeft, guiTop, 0, 0, xSize, ySize ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index f1dabbb89..6073a459f 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.resources.I18n; @@ -33,7 +33,7 @@ public class GuiPrinter extends ContainerScreen @Override protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { - GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); + RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( BACKGROUND ); blit( guiLeft, guiTop, 0, 0, xSize, ySize ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 249678995..9c609be91 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; @@ -88,10 +88,10 @@ public class GuiPrintout extends ContainerScreen public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { // Draw the printout - GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - GlStateManager.enableDepthTest(); + RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); + RenderSystem.enableDepthTest(); - drawBorder( guiLeft, guiTop, blitOffset, m_page, m_pages, m_book ); + drawBorder( guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book ); drawText( guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); } @@ -99,9 +99,9 @@ public class GuiPrintout extends ContainerScreen public void render( int mouseX, int mouseY, float partialTicks ) { // We must take the background further back in order to not overlap with our printed pages. - blitOffset--; + setBlitOffset( getBlitOffset() - 1 ); renderBackground(); - blitOffset++; + setBlitOffset( getBlitOffset() + 1 ); super.render( mouseX, mouseY, partialTicks ); renderHoveredToolTip( mouseX, mouseY ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index eea36917b..a6fe9868a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.client.gui; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; @@ -98,7 +98,7 @@ public class GuiTurtle extends ContainerScreen int slot = m_container.getSelectedSlot(); if( slot >= 0 ) { - GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); + RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); int slotX = slot % 4; int slotY = slot / 4; minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); @@ -114,7 +114,7 @@ public class GuiTurtle extends ContainerScreen terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw border/inventory - GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); + RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); blit( guiLeft, guiTop, 0, 0, xSize, ySize ); diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 04f844091..79a172129 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -5,28 +5,20 @@ */ package dan200.computercraft.client.gui.widgets; -import com.mojang.blaze3d.platform.GlStateManager; -import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.IGuiEventListener; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.SharedConstants; import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.GL11; import java.util.BitSet; import java.util.function.Supplier; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.BACKGROUND; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; public class WidgetTerminal implements IGuiEventListener { @@ -184,8 +176,8 @@ public class WidgetTerminal implements IGuiEventListener Terminal term = computer.getTerminal(); if( term != null ) { - int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); - int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + int charX = (int) (mouseX / FONT_WIDTH); + int charY = (int) (mouseY / FONT_HEIGHT); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); @@ -208,8 +200,8 @@ public class WidgetTerminal implements IGuiEventListener Terminal term = computer.getTerminal(); if( term != null ) { - int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); - int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + int charX = (int) (mouseX / FONT_WIDTH); + int charY = (int) (mouseY / FONT_HEIGHT); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); @@ -235,8 +227,8 @@ public class WidgetTerminal implements IGuiEventListener Terminal term = computer.getTerminal(); if( term != null ) { - int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); - int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + int charX = (int) (mouseX / FONT_WIDTH); + int charY = (int) (mouseY / FONT_HEIGHT); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); @@ -260,8 +252,8 @@ public class WidgetTerminal implements IGuiEventListener Terminal term = computer.getTerminal(); if( term != null ) { - int charX = (int) (mouseX / FixedWidthFontRenderer.FONT_WIDTH); - int charY = (int) (mouseY / FixedWidthFontRenderer.FONT_HEIGHT); + int charX = (int) (mouseX / FONT_WIDTH); + int charY = (int) (mouseY / FONT_HEIGHT); charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); @@ -329,89 +321,15 @@ public class WidgetTerminal implements IGuiEventListener Terminal terminal = computer != null ? computer.getTerminal() : null; if( terminal != null ) { - // Draw the terminal - boolean greyscale = !computer.isColour(); - Palette palette = terminal.getPalette(); - - // Get the data from the terminal first - // Unfortunately we have to keep the lock for the whole of drawing, so the text doesn't change under us. - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - boolean tblink = terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink(); - int tw = terminal.getWidth(); - int th = terminal.getHeight(); - int tx = terminal.getCursorX(); - int ty = terminal.getCursorY(); - - // Draw margins - TextBuffer emptyLine = new TextBuffer( ' ', tw ); - if( topMargin > 0 ) - { - fontRenderer.drawString( emptyLine, originX, originY - topMargin, - terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), - leftMargin, rightMargin, greyscale, palette ); - } - - if( bottomMargin > 0 ) - { - fontRenderer.drawString( emptyLine, originX, originY + bottomMargin + (th - 1) * FixedWidthFontRenderer.FONT_HEIGHT, - terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ), - leftMargin, rightMargin, greyscale, palette ); - } - - // Draw lines - int y = originY; - for( int line = 0; line < th; line++ ) - { - TextBuffer text = terminal.getLine( line ); - TextBuffer colour = terminal.getTextColourLine( line ); - TextBuffer backgroundColour = terminal.getBackgroundColourLine( line ); - fontRenderer.drawString( text, originX, y, colour, backgroundColour, leftMargin, rightMargin, greyscale, palette ); - y += FixedWidthFontRenderer.FONT_HEIGHT; - } - - if( tblink && tx >= 0 && ty >= 0 && tx < tw && ty < th ) - { - TextBuffer cursor = new TextBuffer( '_', 1 ); - TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); - - fontRenderer.drawString( - cursor, - originX + FixedWidthFontRenderer.FONT_WIDTH * tx, - originY + FixedWidthFontRenderer.FONT_HEIGHT * ty, - cursorColour, null, - 0, 0, - greyscale, - palette - ); - } + FixedWidthFontRenderer.drawTerminal( originX, originY, terminal, !computer.isColour(), topMargin, bottomMargin, leftMargin, rightMargin ); } else { - // Draw a black background - Colour black = Colour.Black; - GlStateManager.color4f( black.getR(), black.getG(), black.getB(), 1.0f ); - try - { - int x = originX - leftMargin; - int y = originY - rightMargin; - int width = termWidth * FixedWidthFontRenderer.FONT_WIDTH + leftMargin + rightMargin; - int height = termHeight * FixedWidthFontRenderer.FONT_HEIGHT + topMargin + bottomMargin; - - client.getTextureManager().bindTexture( BACKGROUND ); - - Tessellator tesslector = Tessellator.getInstance(); - BufferBuilder buffer = tesslector.getBuffer(); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX ); - buffer.pos( x, y + height, 0 ).tex( 0 / 256.0, height / 256.0 ).endVertex(); - buffer.pos( x + width, y + height, 0 ).tex( width / 256.0, height / 256.0 ).endVertex(); - buffer.pos( x + width, y, 0 ).tex( width / 256.0, 0 / 256.0 ).endVertex(); - buffer.pos( x, y, 0 ).tex( 0 / 256.0, 0 / 256.0 ).endVertex(); - tesslector.draw(); - } - finally - { - GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - } + FixedWidthFontRenderer.drawEmptyTerminal( + originX - leftMargin, originY - rightMargin, + termWidth * FONT_WIDTH + leftMargin + rightMargin, + termHeight * FONT_HEIGHT + topMargin + bottomMargin + ); } } } diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index fc913fb81..b3cabf6cc 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -7,14 +7,12 @@ package dan200.computercraft.client.proxy; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.*; -import dan200.computercraft.client.render.TileEntityCableRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; -import dan200.computercraft.shared.peripheral.modem.wired.TileCable; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; @@ -22,6 +20,8 @@ import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.client.gui.ScreenManager; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -37,10 +37,21 @@ public final class ComputerCraftProxyClient { registerContainers(); + // While turtles themselves are not transparent, their upgrades may be. + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleNormal, RenderType.translucent() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleAdvanced, RenderType.translucent() ); + + // Monitors' textures have _entirely_ transparent sections which, while not translucent, requires being rendered + // as transparent. + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.translucent() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.translucent() ); + // Setup TESRs - ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() ); - ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() ); - ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() ); + ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_NORMAL, TileEntityMonitorRenderer::new ); + ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_ADVANCED, TileEntityMonitorRenderer::new ); + ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_NORMAL, TileEntityTurtleRenderer::new ); + ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_ADVANCED, TileEntityTurtleRenderer::new ); + // TODO: ClientRegistry.bindTileEntityRenderer( TileCable.FACTORY, x -> new TileEntityCableRenderer() ); } private static void registerContainers() diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java deleted file mode 100644 index fee08fd12..000000000 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.client.render; - -import com.mojang.blaze3d.platform.GlStateManager; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.FirstPersonRenderer; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.util.Hand; -import net.minecraft.util.HandSide; -import net.minecraft.util.math.MathHelper; - -public abstract class ItemMapLikeRenderer -{ - /** - * The main rendering method for the item. - * - * @param stack The stack to render - * @see FirstPersonRenderer#renderMapFirstPerson(ItemStack) - */ - protected abstract void renderItem( ItemStack stack ); - - protected void renderItemFirstPerson( Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) - { - PlayerEntity player = Minecraft.getInstance().player; - - GlStateManager.pushMatrix(); - if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) - { - renderItemFirstPersonCenter( pitch, equipProgress, swingProgress, stack ); - } - else - { - renderItemFirstPersonSide( - hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(), - equipProgress, swingProgress, stack - ); - } - GlStateManager.popMatrix(); - } - - /** - * Renders the item to one side of the player. - * - * @param side The side to render on - * @param equipProgress The equip progress of this item - * @param swingProgress The swing progress of this item - * @param stack The stack to render - * @see FirstPersonRenderer#renderMapFirstPersonSide(float, HandSide, float, ItemStack) - */ - private void renderItemFirstPersonSide( HandSide side, float equipProgress, float swingProgress, ItemStack stack ) - { - Minecraft minecraft = Minecraft.getInstance(); - float offset = side == HandSide.RIGHT ? 1f : -1f; - GlStateManager.translatef( offset * 0.125f, -0.125f, 0f ); - - // If the player is not invisible then render a single arm - if( !minecraft.player.isInvisible() ) - { - GlStateManager.pushMatrix(); - GlStateManager.rotatef( offset * 10f, 0f, 0f, 1f ); - minecraft.getFirstPersonRenderer().renderArmFirstPerson( equipProgress, swingProgress, side ); - GlStateManager.popMatrix(); - } - - // Setup the appropriate transformations. This is just copied from the - // corresponding method in ItemRenderer. - GlStateManager.pushMatrix(); - GlStateManager.translatef( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); - float f1 = MathHelper.sqrt( swingProgress ); - float f2 = MathHelper.sin( f1 * (float) Math.PI ); - float f3 = -0.5f * f2; - float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); - float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); - GlStateManager.translatef( offset * f3, f4 - 0.3f * f2, f5 ); - GlStateManager.rotatef( f2 * -45f, 1f, 0f, 0f ); - GlStateManager.rotatef( offset * f2 * -30f, 0f, 1f, 0f ); - - renderItem( stack ); - - GlStateManager.popMatrix(); - } - - /** - * Render an item in the middle of the screen. - * - * @param pitch The pitch of the player - * @param equipProgress The equip progress of this item - * @param swingProgress The swing progress of this item - * @param stack The stack to render - * @see FirstPersonRenderer#renderMapFirstPerson(float, float, float) - */ - private void renderItemFirstPersonCenter( float pitch, float equipProgress, float swingProgress, ItemStack stack ) - { - FirstPersonRenderer renderer = Minecraft.getInstance().getFirstPersonRenderer(); - - // Setup the appropriate transformations. This is just copied from the - // corresponding method in ItemRenderer. - float swingRt = MathHelper.sqrt( swingProgress ); - float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI ); - float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI ); - GlStateManager.translatef( 0f, -tX / 2f, tZ ); - float pitchAngle = renderer.getMapAngleFromPitch( pitch ); - GlStateManager.translatef( 0f, 0.04f + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); - GlStateManager.rotatef( pitchAngle * -85f, 1f, 0f, 0f ); - renderer.renderArms(); - float rX = MathHelper.sin( swingRt * (float) Math.PI ); - GlStateManager.rotatef( rX * 20f, 1f, 0f, 0f ); - GlStateManager.scalef( 2f, 2f, 2f ); - - renderItem( stack ); - } -} diff --git a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java b/src/main/java/dan200/computercraft/client/render/ModelTransformer.java deleted file mode 100644 index 0ae9d188f..000000000 --- a/src/main/java/dan200/computercraft/client/render/ModelTransformer.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.client.render; - -import net.minecraft.client.renderer.model.BakedQuad; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.vertex.VertexFormat; -import net.minecraft.util.Direction; -import net.minecraftforge.client.model.pipeline.IVertexConsumer; -import net.minecraftforge.client.model.pipeline.LightUtil; -import net.minecraftforge.client.model.pipeline.VertexTransformer; -import net.minecraftforge.common.model.TRSRTransformation; - -import javax.annotation.Nonnull; -import javax.vecmath.Matrix4f; -import javax.vecmath.Point3f; -import javax.vecmath.Vector3f; -import java.util.List; - -/** - * Transforms vertices of a model, remaining aware of winding order, and rearranging - * vertices if needed. - */ -public final class ModelTransformer -{ - private static final Matrix4f identity; - - static - { - identity = new Matrix4f(); - identity.setIdentity(); - } - - private ModelTransformer() - { - } - - public static void transformQuadsTo( List output, List input, Matrix4f transform ) - { - if( transform == null || transform.equals( identity ) ) - { - output.addAll( input ); - } - else - { - Matrix4f normalMatrix = new Matrix4f( transform ); - normalMatrix.invert(); - normalMatrix.transpose(); - - for( BakedQuad quad : input ) output.add( doTransformQuad( quad, transform, normalMatrix ) ); - } - } - - public static BakedQuad transformQuad( BakedQuad input, Matrix4f transform ) - { - if( transform == null || transform.equals( identity ) ) return input; - - Matrix4f normalMatrix = new Matrix4f( transform ); - normalMatrix.invert(); - normalMatrix.transpose(); - return doTransformQuad( input, transform, normalMatrix ); - } - - private static BakedQuad doTransformQuad( BakedQuad input, Matrix4f positionMatrix, Matrix4f normalMatrix ) - { - - BakedQuadBuilder builder = new BakedQuadBuilder( input.getFormat() ); - NormalAwareTransformer transformer = new NormalAwareTransformer( builder, positionMatrix, normalMatrix ); - input.pipe( transformer ); - - if( transformer.areNormalsInverted() ) - { - builder.swap( 1, 3 ); - transformer.areNormalsInverted(); - } - - return builder.build(); - } - - /** - * A vertex transformer that tracks whether the normals have been inverted and so the vertices - * should be reordered so backface culling works as expected. - */ - private static class NormalAwareTransformer extends VertexTransformer - { - private final Matrix4f positionMatrix; - private final Matrix4f normalMatrix; - - private int vertexIndex = 0, elementIndex = 0; - private final Point3f[] before = new Point3f[4]; - private final Point3f[] after = new Point3f[4]; - - NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix ) - { - super( parent ); - this.positionMatrix = positionMatrix; - this.normalMatrix = normalMatrix; - } - - @Override - public void setQuadOrientation( @Nonnull Direction orientation ) - { - super.setQuadOrientation( orientation == null ? orientation : TRSRTransformation.rotate( positionMatrix, orientation ) ); - } - - @Override - public void put( int element, @Nonnull float... data ) - { - switch( getVertexFormat().getElement( element ).getUsage() ) - { - case POSITION: - { - Point3f vec = new Point3f( data ); - Point3f newVec = new Point3f(); - positionMatrix.transform( vec, newVec ); - - float[] newData = new float[4]; - newVec.get( newData ); - super.put( element, newData ); - - - before[vertexIndex] = vec; - after[vertexIndex] = newVec; - break; - } - case NORMAL: - { - Vector3f vec = new Vector3f( data ); - normalMatrix.transform( vec ); - - float[] newData = new float[4]; - vec.get( newData ); - super.put( element, newData ); - break; - } - default: - super.put( element, data ); - break; - } - - elementIndex++; - if( elementIndex == getVertexFormat().getElementCount() ) - { - vertexIndex++; - elementIndex = 0; - } - } - - public boolean areNormalsInverted() - { - Vector3f temp1 = new Vector3f(), temp2 = new Vector3f(); - Vector3f crossBefore = new Vector3f(), crossAfter = new Vector3f(); - - // Determine what cross product we expect to have - temp1.sub( before[1], before[0] ); - temp2.sub( before[1], before[2] ); - crossBefore.cross( temp1, temp2 ); - normalMatrix.transform( crossBefore ); - - // And determine what cross product we actually have - temp1.sub( after[1], after[0] ); - temp2.sub( after[1], after[2] ); - crossAfter.cross( temp1, temp2 ); - - // If the angle between expected and actual cross product is greater than - // pi/2 radians then we will need to reorder our quads. - return Math.abs( crossBefore.angle( crossAfter ) ) >= Math.PI / 2; - } - } - - /** - * A vertex consumer which is capable of building {@link BakedQuad}s. - * - * Equivalent to {@link net.minecraftforge.client.model.pipeline.UnpackedBakedQuad.Builder} but more memory - * efficient. - * - * This also provides the ability to swap vertices through {@link #swap(int, int)} to allow reordering. - */ - private static final class BakedQuadBuilder implements IVertexConsumer - { - private final VertexFormat format; - - private final int[] vertexData; - private int vertexIndex = 0, elementIndex = 0; - - private Direction orientation; - private int quadTint; - private boolean diffuse; - private TextureAtlasSprite texture; - - private BakedQuadBuilder( VertexFormat format ) - { - this.format = format; - vertexData = new int[format.getSize()]; - } - - @Nonnull - @Override - public VertexFormat getVertexFormat() - { - return format; - } - - @Override - public void setQuadTint( int tint ) - { - quadTint = tint; - } - - @Override - public void setQuadOrientation( @Nonnull Direction orientation ) - { - this.orientation = orientation; - } - - @Override - public void setApplyDiffuseLighting( boolean diffuse ) - { - this.diffuse = diffuse; - } - - @Override - public void setTexture( @Nonnull TextureAtlasSprite texture ) - { - this.texture = texture; - } - - @Override - public void put( int element, @Nonnull float... data ) - { - LightUtil.pack( data, vertexData, format, vertexIndex, element ); - - elementIndex++; - if( elementIndex == getVertexFormat().getElementCount() ) - { - vertexIndex++; - elementIndex = 0; - } - } - - public void swap( int a, int b ) - { - int length = vertexData.length / 4; - for( int i = 0; i < length; i++ ) - { - int temp = vertexData[a * length + i]; - vertexData[a * length + i] = vertexData[b * length + i]; - vertexData[b * length + i] = temp; - } - } - - public BakedQuad build() - { - if( elementIndex != 0 || vertexIndex != 4 ) - { - throw new IllegalStateException( "Got an unexpected number of elements/vertices" ); - } - if( texture == null ) - { - throw new IllegalStateException( "Texture has not been set" ); - } - - return new BakedQuad( vertexData, quadTint, orientation, texture, diffuse, format ); - } - } -} diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 34c8e9475..b1e81a556 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -5,9 +5,9 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager.DestFactor; import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; @@ -24,7 +24,7 @@ import static dan200.computercraft.shared.media.items.ItemPrintout.LINES_PER_PAG public final class PrintoutRenderer { private static final ResourceLocation BG = new ResourceLocation( "computercraft", "textures/gui/printout.png" ); - private static final double BG_SIZE = 256.0; + private static final float BG_SIZE = 256.0f; /** * Width of a page. @@ -63,35 +63,21 @@ public final class PrintoutRenderer public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) { - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) { - fontRenderer.drawString( text[start + line], x, y + line * FONT_HEIGHT, colours[start + line], null, 0, 0, false, Palette.DEFAULT ); - } - } - - public static void drawText( int x, int y, int start, String[] text, String[] colours ) - { - GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - GlStateManager.enableBlend(); - GlStateManager.enableTexture(); - GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); - - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - - for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) - { - fontRenderer.drawString( new TextBuffer( text[start + line] ), x, y + line * FONT_HEIGHT, new TextBuffer( colours[start + line] ), null, 0, 0, false, Palette.DEFAULT ); + FixedWidthFontRenderer.drawString( + x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT, + false, 0, 0 + ); } } public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook ) { - GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - GlStateManager.enableBlend(); - GlStateManager.enableTexture(); - GlStateManager.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); + RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); + RenderSystem.enableBlend(); + RenderSystem.enableTexture(); + RenderSystem.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); Minecraft.getInstance().getTextureManager().bindTexture( BG ); @@ -123,8 +109,8 @@ public final class PrintoutRenderer while( borderX < right ) { double thisWidth = Math.min( right - borderX, X_SIZE ); - drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, thisWidth, COVER_SIZE ); - drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, thisWidth, COVER_SIZE ); + drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, (float) thisWidth, COVER_SIZE ); + drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE ); borderX += thisWidth; } } @@ -156,7 +142,7 @@ public final class PrintoutRenderer tessellator.draw(); } - private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double u, double v, double width, double height ) + private static void drawTexture( BufferBuilder buffer, double x, double y, double z, float u, float v, float width, float height ) { buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); @@ -164,7 +150,7 @@ public final class PrintoutRenderer buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); } - private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, double u, double v, double tWidth, double tHeight ) + private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, float u, float v, float tWidth, float tHeight ) { buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 47493e7cd..4562bf199 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -5,38 +5,40 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GLX; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import org.lwjgl.opengl.GL11; + +import javax.annotation.Nonnull; public class TileEntityMonitorRenderer extends TileEntityRenderer { - @Override - public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i ) + /** + * {@link TileMonitor#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between + * the monitor frame and contents. + */ + private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1); + + private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix(); + + public TileEntityMonitorRenderer( TileEntityRendererDispatcher rendererDispatcher ) { - if( tileEntity != null ) - { - renderMonitorAt( tileEntity, posX, posY, posZ, f, i ); - } + super( rendererDispatcher ); } - private static void renderMonitorAt( TileMonitor monitor, double posX, double posY, double posZ, float f, int i ) + @Override + public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer renderer, int lightmapCoord, int overlayLight ) { // Render from the origin monitor ClientMonitor originTerminal = monitor.getClientMonitor(); @@ -58,9 +60,6 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer originTerminal.lastRenderPos = monitorPos; BlockPos originPos = origin.getPos(); - posX += originPos.getX() - monitorPos.getX(); - posY += originPos.getY() - monitorPos.getY(); - posZ += originPos.getZ() - monitorPos.getZ(); // Determine orientation Direction dir = origin.getDirection(); @@ -68,224 +67,94 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer float yaw = dir.getHorizontalAngle(); float pitch = DirectionUtil.toPitchAngle( front ); - GlStateManager.pushMatrix(); - try + // Setup initial transform + transform.push(); + transform.translate( + originPos.getX() - monitorPos.getX() + 0.5, + originPos.getY() - monitorPos.getY() + 0.5, + originPos.getZ() - monitorPos.getZ() + 0.5 + ); + + transform.rotate( Vector3f.YN.rotationDegrees( yaw ) ); + transform.rotate( Vector3f.XP.rotationDegrees( pitch ) ); + transform.translate( + -0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN, + origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0, + 0.5 + ); + double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); + double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); + + // Draw the contents + Terminal terminal = originTerminal.getTerminal(); + if( terminal != null ) { - // Setup initial transform - GlStateManager.translated( posX + 0.5, posY + 0.5, posZ + 0.5 ); - GlStateManager.rotatef( -yaw, 0.0f, 1.0f, 0.0f ); - GlStateManager.rotatef( pitch, 1.0f, 0.0f, 0.0f ); - GlStateManager.translated( - -0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN, - origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0, - 0.5 - ); - double xSize = origin.getWidth() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); - double ySize = origin.getHeight() - 2.0 * (TileMonitor.RENDER_MARGIN + TileMonitor.RENDER_BORDER); - - // Get renderers - Minecraft mc = Minecraft.getInstance(); - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder renderer = tessellator.getBuffer(); - - // Get terminal boolean redraw = originTerminal.pollTerminalChanged(); - - // Draw the contents - GlStateManager.depthMask( false ); - GLX.glMultiTexCoord2f( GLX.GL_TEXTURE1, 0xFFFF, 0xFFFF ); - GlStateManager.disableLighting(); - mc.gameRenderer.disableLightmap(); - try + if( originTerminal.buffer == null ) { - Terminal terminal = originTerminal.getTerminal(); - if( terminal != null ) - { - Palette palette = terminal.getPalette(); - - // Allocate display lists - if( originTerminal.renderDisplayLists == null ) - { - originTerminal.createLists(); - redraw = true; - } - - // Draw a terminal - boolean greyscale = !originTerminal.isColour(); - int width = terminal.getWidth(); - int height = terminal.getHeight(); - int cursorX = terminal.getCursorX(); - int cursorY = terminal.getCursorY(); - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - - GlStateManager.pushMatrix(); - try - { - double xScale = xSize / (width * FixedWidthFontRenderer.FONT_WIDTH); - double yScale = ySize / (height * FixedWidthFontRenderer.FONT_HEIGHT); - GlStateManager.scaled( xScale, -yScale, 1.0 ); - - // Draw background - mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND ); - if( redraw ) - { - // Build background display list - GlStateManager.newList( originTerminal.renderDisplayLists[0], GL11.GL_COMPILE ); - try - { - double marginXSize = TileMonitor.RENDER_MARGIN / xScale; - double marginYSize = TileMonitor.RENDER_MARGIN / yScale; - double marginSquash = marginYSize / FixedWidthFontRenderer.FONT_HEIGHT; - - // Top and bottom margins - GlStateManager.pushMatrix(); - try - { - GlStateManager.scaled( 1.0, marginSquash, 1.0 ); - GlStateManager.translated( 0.0, -marginYSize / marginSquash, 0.0 ); - fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( 0 ), marginXSize, marginXSize, greyscale, palette ); - GlStateManager.translated( 0.0, (marginYSize + height * FixedWidthFontRenderer.FONT_HEIGHT) / marginSquash, 0.0 ); - fontRenderer.drawStringBackgroundPart( 0, 0, terminal.getBackgroundColourLine( height - 1 ), marginXSize, marginXSize, greyscale, palette ); - } - finally - { - GlStateManager.popMatrix(); - } - - // Backgrounds - for( int y = 0; y < height; y++ ) - { - fontRenderer.drawStringBackgroundPart( - 0, FixedWidthFontRenderer.FONT_HEIGHT * y, - terminal.getBackgroundColourLine( y ), - marginXSize, marginXSize, - greyscale, - palette - ); - } - } - finally - { - GlStateManager.endList(); - } - } - GlStateManager.callList( originTerminal.renderDisplayLists[0] ); - GlStateManager.clearCurrentColor(); - - // Draw text - fontRenderer.bindFont(); - if( redraw ) - { - // Build text display list - GlStateManager.newList( originTerminal.renderDisplayLists[1], GL11.GL_COMPILE ); - try - { - // Lines - for( int y = 0; y < height; y++ ) - { - fontRenderer.drawStringTextPart( - 0, FixedWidthFontRenderer.FONT_HEIGHT * y, - terminal.getLine( y ), - terminal.getTextColourLine( y ), - greyscale, - palette - ); - } - } - finally - { - GlStateManager.endList(); - } - } - GlStateManager.callList( originTerminal.renderDisplayLists[1] ); - GlStateManager.clearCurrentColor(); - - // Draw cursor - fontRenderer.bindFont(); - if( redraw ) - { - // Build cursor display list - GlStateManager.newList( originTerminal.renderDisplayLists[2], GL11.GL_COMPILE ); - try - { - // Cursor - if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height ) - { - TextBuffer cursor = new TextBuffer( "_" ); - TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); - fontRenderer.drawString( - cursor, - FixedWidthFontRenderer.FONT_WIDTH * cursorX, - FixedWidthFontRenderer.FONT_HEIGHT * cursorY, - cursorColour, null, - 0, 0, - greyscale, - palette - ); - } - } - finally - { - GlStateManager.endList(); - } - } - if( FrameInfo.getGlobalCursorBlink() ) - { - GlStateManager.callList( originTerminal.renderDisplayLists[2] ); - GlStateManager.clearCurrentColor(); - } - } - finally - { - GlStateManager.popMatrix(); - } - } - else - { - // Draw a big black quad - mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND ); - final Colour colour = Colour.Black; - - final float r = colour.getR(); - final float g = colour.getG(); - final float b = colour.getB(); - - renderer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR ); - renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 0.0, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 1.0, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 1.0, 1.0 ).color( r, g, b, 1.0f ).endVertex(); - tessellator.draw(); - } + originTerminal.createBuffer(); + redraw = true; } - finally + VertexBuffer vbo = originTerminal.buffer; + + // Draw a terminal + double xScale = xSize / (terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH); + double yScale = ySize / (terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT); + transform.push(); + transform.scale( (float) xScale, (float) -yScale, 1.0f ); + + float xMargin = (float) (MARGIN / xScale); + float yMargin = (float) (MARGIN / yScale); + + Matrix4f matrix = transform.getLast().getPositionMatrix(); + + if( redraw ) { - GlStateManager.depthMask( true ); - mc.gameRenderer.enableLightmap(); - GlStateManager.enableLighting(); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder builder = tessellator.getBuffer(); + builder.begin( FixedWidthFontRenderer.TYPE.getGlMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() ); + FixedWidthFontRenderer.drawTerminalWithoutCursor( + IDENTITY, builder, 0, 0, + terminal, !originTerminal.isColour(), yMargin, yMargin, xMargin, xMargin + ); + + builder.finishDrawing(); + vbo.upload( builder ); } - // Draw the depth blocker - GlStateManager.colorMask( false, false, false, false ); - try - { - mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND ); - renderer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION ); - renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - tessellator.draw(); - } - finally - { - GlStateManager.colorMask( true, true, true, true ); - } + // Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate + // render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick + // for now. + IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); + FixedWidthFontRenderer.TYPE.enable(); + + vbo.bindBuffer(); + FixedWidthFontRenderer.TYPE.getVertexFormat().setupBufferState( 0L ); + vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getGlMode() ); + VertexBuffer.unbindBuffer(); + FixedWidthFontRenderer.TYPE.getVertexFormat().clearBufferState(); + + // We don't draw the cursor with the VBO, as it's dynamic and so we'll end up refreshing far more than is + // reasonable. + FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() ); + + transform.pop(); } - finally + else { - GlStateManager.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - GlStateManager.popMatrix(); + FixedWidthFontRenderer.drawEmptyTerminal( + transform.getLast().getPositionMatrix(), renderer, + -MARGIN, MARGIN, + (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) + ); } + + FixedWidthFontRenderer.drawBlocker( + transform.getLast().getPositionMatrix(), renderer, + (float) -TileMonitor.RENDER_MARGIN, (float) TileMonitor.RENDER_MARGIN, + (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) + ); + + transform.pop(); } } diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 1616b3533..3fce878b6 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -5,7 +5,9 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -13,31 +15,26 @@ import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; -import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.Atlases; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; -import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; -import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; -import net.minecraftforge.client.model.pipeline.LightUtil; -import org.apache.commons.lang3.tuple.Pair; -import org.lwjgl.opengl.GL11; -import javax.vecmath.Matrix4f; +import javax.annotation.Nonnull; import java.util.List; import java.util.Random; @@ -48,10 +45,11 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer private static final ModelResourceLocation COLOUR_TURTLE_MODEL = new ModelResourceLocation( "computercraft:turtle_colour", "inventory" ); private static final ModelResourceLocation ELF_OVERLAY_MODEL = new ModelResourceLocation( "computercraft:turtle_elf_overlay", "inventory" ); - @Override - public void render( TileTurtle tileEntity, double posX, double posY, double posZ, float partialTicks, int breaking ) + private final Random random = new Random( 0 ); + + public TileEntityTurtleRenderer( TileEntityRendererDispatcher renderDispatcher ) { - if( tileEntity != null ) renderTurtleAt( tileEntity, posX, posY, posZ, partialTicks ); + super( renderDispatcher ); } public static ModelResourceLocation getTurtleModel( ComputerFamily family, boolean coloured ) @@ -68,169 +66,126 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer public static ModelResourceLocation getTurtleOverlayModel( ResourceLocation overlay, boolean christmas ) { - if( overlay != null ) - { - return new ModelResourceLocation( overlay, "inventory" ); - } - else if( christmas ) - { - return ELF_OVERLAY_MODEL; - } - else - { - return null; - } + if( overlay != null ) return new ModelResourceLocation( overlay, "inventory" ); + if( christmas ) return ELF_OVERLAY_MODEL; + return null; } - private void renderTurtleAt( TileTurtle turtle, double posX, double posY, double posZ, float partialTicks ) + @Override + public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer renderer, int lightmapCoord, int overlayLight ) { // Render the label String label = turtle.createProxy().getLabel(); - RayTraceResult hit = rendererDispatcher.cameraHitResult; + RayTraceResult hit = renderDispatcher.cameraHitResult; if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) ) { - setLightmapDisabled( true ); - GameRenderer.drawNameplate( - getFontRenderer(), label, - (float) posX + 0.5F, (float) posY + 1.2F, (float) posZ + 0.5F, 0, - rendererDispatcher.renderInfo.getYaw(), rendererDispatcher.renderInfo.getPitch(), false - ); - setLightmapDisabled( false ); + Minecraft mc = Minecraft.getInstance(); + FontRenderer font = renderDispatcher.fontRenderer; + + transform.push(); + transform.translate( 0.5, 1.2, 0.5 ); + transform.rotate( mc.getRenderManager().getCameraOrientation() ); + transform.scale( -0.025f, -0.025f, 0.025f ); + + Matrix4f matrix = transform.getLast().getPositionMatrix(); + int opacity = (int) (mc.gameSettings.getTextBackgroundOpacity( 0.25f ) * 255) << 24; + float width = -font.getStringWidth( label ) / 2.0f; + font.renderString( label, width, (float) 0, 0x20ffffff, false, matrix, renderer, true, opacity, lightmapCoord ); + font.renderString( label, width, (float) 0, 0xffffffff, false, matrix, renderer, false, 0, lightmapCoord ); + + transform.pop(); } - GlStateManager.pushMatrix(); - try + transform.push(); + + // Setup the transform. + Vec3d offset = turtle.getRenderOffset( partialTicks ); + float yaw = turtle.getRenderYaw( partialTicks ); + transform.translate( offset.x, offset.y, offset.z ); + + transform.translate( 0.5f, 0.5f, 0.5f ); + transform.rotate( Vector3f.YP.rotationDegrees( 180.0f - yaw ) ); + if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) ) { - BlockState state = turtle.getBlockState(); - // Setup the transform - Vec3d offset = turtle.getRenderOffset( partialTicks ); - float yaw = turtle.getRenderYaw( partialTicks ); - GlStateManager.translated( posX + offset.x, posY + offset.y, posZ + offset.z ); - // Render the turtle - GlStateManager.translatef( 0.5f, 0.5f, 0.5f ); - GlStateManager.rotatef( 180.0f - yaw, 0.0f, 1.0f, 0.0f ); - if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) ) - { - // Flip the model and swap the cull face as winding order will have changed. - GlStateManager.scalef( 1.0f, -1.0f, 1.0f ); - GlStateManager.cullFace( GlStateManager.CullFace.FRONT ); - } - GlStateManager.translatef( -0.5f, -0.5f, -0.5f ); - // Render the turtle - int colour = turtle.getColour(); - ComputerFamily family = turtle.getFamily(); - ResourceLocation overlay = turtle.getOverlay(); - - renderModel( state, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } ); - - // Render the overlay - ModelResourceLocation overlayModel = getTurtleOverlayModel( - overlay, - HolidayUtil.getCurrentHoliday() == Holiday.Christmas - ); - if( overlayModel != null ) - { - GlStateManager.disableCull(); - GlStateManager.enableBlend(); - GlStateManager.blendFunc( GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA ); - try - { - renderModel( state, overlayModel, null ); - } - finally - { - GlStateManager.disableBlend(); - GlStateManager.enableCull(); - } - } - - // Render the upgrades - renderUpgrade( state, turtle, TurtleSide.Left, partialTicks ); - renderUpgrade( state, turtle, TurtleSide.Right, partialTicks ); + // Flip the model + transform.scale( 1.0f, -1.0f, 1.0f ); } - finally + transform.translate( -0.5f, -0.5f, -0.5f ); + + // Render the turtle + int colour = turtle.getColour(); + ComputerFamily family = turtle.getFamily(); + ResourceLocation overlay = turtle.getOverlay(); + + IVertexBuilder buffer = renderer.getBuffer( Atlases.getTranslucentCullBlockType() ); + renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } ); + + // Render the overlay + ModelResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.Christmas ); + if( overlayModel != null ) { - GlStateManager.popMatrix(); - GlStateManager.cullFace( GlStateManager.CullFace.BACK ); + renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null ); } + + // Render the upgrades + renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.Left, partialTicks ); + renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.Right, partialTicks ); + + transform.pop(); } - private void renderUpgrade( BlockState state, TileTurtle turtle, TurtleSide side, float f ) + private void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, TurtleSide side, float f ) { ITurtleUpgrade upgrade = turtle.getUpgrade( side ); - if( upgrade != null ) - { - GlStateManager.pushMatrix(); - try - { - float toolAngle = turtle.getToolRenderAngle( side, f ); - GlStateManager.translatef( 0.0f, 0.5f, 0.5f ); - GlStateManager.rotatef( -toolAngle, 1.0f, 0.0f, 0.0f ); - GlStateManager.translatef( 0.0f, -0.5f, -0.5f ); + if( upgrade == null ) return; + transform.push(); - Pair pair = upgrade.getModel( turtle.getAccess(), side ); - if( pair != null ) - { - if( pair.getRight() != null ) - { - ForgeHooksClient.multiplyCurrentGlMatrix( pair.getRight() ); - } - if( pair.getLeft() != null ) - { - renderModel( state, pair.getLeft(), null ); - } - } - } - finally - { - GlStateManager.popMatrix(); - } - } + float toolAngle = turtle.getToolRenderAngle( side, f ); + transform.translate( 0.0f, 0.5f, 0.5f ); + transform.rotate( Vector3f.XN.rotationDegrees( toolAngle ) ); + transform.translate( 0.0f, -0.5f, -0.5f ); + + TransformedModel model = upgrade.getModel( turtle.getAccess(), side ); + model.getMatrix().push( transform ); + renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null ); + transform.pop(); + + transform.pop(); } - private void renderModel( BlockState state, ModelResourceLocation modelLocation, int[] tints ) + private void renderModel( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, ModelResourceLocation modelLocation, int[] tints ) { - Minecraft mc = Minecraft.getInstance(); - ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager(); - renderModel( state, modelManager.getModel( modelLocation ), tints ); + ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); + renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints ); } - private void renderModel( BlockState state, IBakedModel model, int[] tints ) + private void renderModel( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, IBakedModel model, int[] tints ) { - Random random = new Random( 0 ); - Tessellator tessellator = Tessellator.getInstance(); - rendererDispatcher.textureManager.bindTexture( AtlasTexture.LOCATION_BLOCKS_TEXTURE ); - renderQuads( tessellator, model.getQuads( state, null, random, EmptyModelData.INSTANCE ), tints ); + random.setSeed( 0 ); + renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, null, random, EmptyModelData.INSTANCE ), tints ); for( Direction facing : DirectionUtil.FACINGS ) { - renderQuads( tessellator, model.getQuads( state, facing, random, EmptyModelData.INSTANCE ), tints ); + renderQuads( transform, renderer, lightmapCoord, overlayLight, model.getQuads( null, facing, random, EmptyModelData.INSTANCE ), tints ); } } - private static void renderQuads( Tessellator tessellator, List quads, int[] tints ) + private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder buffer, int lightmapCoord, int overlayLight, List quads, int[] tints ) { - BufferBuilder buffer = tessellator.getBuffer(); - VertexFormat format = DefaultVertexFormats.ITEM; - buffer.begin( GL11.GL_QUADS, format ); - for( BakedQuad quad : quads ) + MatrixStack.Entry matrix = transform.getLast(); + + for( BakedQuad bakedquad : quads ) { - VertexFormat quadFormat = quad.getFormat(); - if( quadFormat != format ) + int tint = -1; + if( tints != null && bakedquad.hasTintIndex() ) { - tessellator.draw(); - format = quadFormat; - buffer.begin( GL11.GL_QUADS, format ); + int idx = bakedquad.getTintIndex(); + if( idx >= 0 && idx < tints.length ) tint = tints[bakedquad.getTintIndex()]; } - int colour = 0xFFFFFFFF; - if( quad.hasTintIndex() && tints != null ) - { - int index = quad.getTintIndex(); - if( index >= 0 && index < tints.length ) colour = tints[index] | 0xFF000000; - } - - LightUtil.renderQuadColor( buffer, quad, colour ); + float f = (float) (tint >> 16 & 255) / 255.0F; + float f1 = (float) (tint >> 8 & 255) / 255.0F; + float f2 = (float) (tint & 255) / 255.0F; + buffer.addVertexData( matrix, bakedquad, f, f1, f2, lightmapCoord, overlayLight, true ); } - tessellator.draw(); } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index d685ff317..41249f178 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -5,28 +5,27 @@ */ package dan200.computercraft.client.render; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Pair; import dan200.computercraft.ComputerCraft; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.IUnbakedModel; -import net.minecraft.client.renderer.model.ModelBakery; -import net.minecraft.client.renderer.texture.ISprite; +import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.resources.IResourceManager; +import net.minecraft.util.JSONUtils; import net.minecraft.util.ResourceLocation; -import net.minecraftforge.client.model.ICustomModelLoader; +import net.minecraftforge.client.model.IModelConfiguration; +import net.minecraftforge.client.model.IModelLoader; +import net.minecraftforge.client.model.geometry.IModelGeometry; import javax.annotation.Nonnull; -import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; -public final class TurtleModelLoader implements ICustomModelLoader +public final class TurtleModelLoader implements IModelLoader { - private static final ResourceLocation NORMAL_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_normal" ); - private static final ResourceLocation ADVANCED_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_advanced" ); private static final ResourceLocation COLOUR_TURTLE_MODEL = new ResourceLocation( ComputerCraft.MOD_ID, "block/turtle_colour" ); public static final TurtleModelLoader INSTANCE = new TurtleModelLoader(); @@ -40,32 +39,15 @@ public final class TurtleModelLoader implements ICustomModelLoader { } - @Override - public boolean accepts( @Nonnull ResourceLocation name ) - { - return name.getNamespace().equals( ComputerCraft.MOD_ID ) - && (name.getPath().equals( "item/turtle_normal" ) || name.getPath().equals( "item/turtle_advanced" )); - } - @Nonnull @Override - public IUnbakedModel loadModel( @Nonnull ResourceLocation name ) + public TurtleModel read( @Nonnull JsonDeserializationContext deserializationContext, @Nonnull JsonObject modelContents ) { - if( name.getNamespace().equals( ComputerCraft.MOD_ID ) ) - { - switch( name.getPath() ) - { - case "item/turtle_normal": - return new TurtleModel( NORMAL_TURTLE_MODEL ); - case "item/turtle_advanced": - return new TurtleModel( ADVANCED_TURTLE_MODEL ); - } - } - - throw new IllegalStateException( "Loader does not accept " + name ); + ResourceLocation model = new ResourceLocation( JSONUtils.getString( modelContents, "model" ) ); + return new TurtleModel( model ); } - private static final class TurtleModel implements IUnbakedModel + public static final class TurtleModel implements IModelGeometry { private final ResourceLocation family; @@ -74,29 +56,21 @@ public final class TurtleModelLoader implements ICustomModelLoader this.family = family; } - @Nonnull @Override - public Collection getDependencies() + public Collection getTextures( IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors ) { - return Arrays.asList( family, COLOUR_TURTLE_MODEL ); + Set materials = new HashSet<>(); + materials.addAll( modelGetter.apply( family ).getTextures( modelGetter, missingTextureErrors ) ); + materials.addAll( modelGetter.apply( COLOUR_TURTLE_MODEL ).getTextures( modelGetter, missingTextureErrors ) ); + return materials; } - @Nonnull @Override - public Collection getTextures( @Nonnull Function modelGetter, @Nonnull Set missingTextureErrors ) - { - return getDependencies().stream() - .flatMap( x -> modelGetter.apply( x ).getTextures( modelGetter, missingTextureErrors ).stream() ) - .collect( Collectors.toSet() ); - } - - @Nonnull - @Override - public IBakedModel bake( @Nonnull ModelBakery bakery, @Nonnull Function spriteGetter, @Nonnull ISprite sprite, @Nonnull VertexFormat format ) + public IBakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform transform, ItemOverrideList overrides, ResourceLocation modelLocation ) { return new TurtleSmartItemModel( - bakery.getBakedModel( family, sprite, spriteGetter, format ), - bakery.getBakedModel( COLOUR_TURTLE_MODEL, sprite, spriteGetter, format ) + bakery.getBakedModel( family, transform, spriteGetter ), + bakery.getBakedModel( COLOUR_TURTLE_MODEL, transform, spriteGetter ) ); } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 31b033bf6..8f9a65cfd 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -5,7 +5,9 @@ */ package dan200.computercraft.client.render; +import dan200.computercraft.api.client.TransformedModel; import net.minecraft.block.BlockState; +import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ItemOverrideList; @@ -13,32 +15,29 @@ import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.Direction; import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.IModelData; +import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; +import net.minecraftforge.client.model.pipeline.TRSRTransformer; import javax.annotation.Nonnull; -import javax.vecmath.Matrix4f; import java.util.*; public class TurtleMultiModel implements IBakedModel { private final IBakedModel m_baseModel; private final IBakedModel m_overlayModel; - private final Matrix4f m_generalTransform; - private final IBakedModel m_leftUpgradeModel; - private final Matrix4f m_leftUpgradeTransform; - private final IBakedModel m_rightUpgradeModel; - private final Matrix4f m_rightUpgradeTransform; + private final TransformationMatrix m_generalTransform; + private final TransformedModel m_leftUpgradeModel; + private final TransformedModel m_rightUpgradeModel; private List m_generalQuads = null; private Map> m_faceQuads = new EnumMap<>( Direction.class ); - public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, Matrix4f generalTransform, IBakedModel leftUpgradeModel, Matrix4f leftUpgradeTransform, IBakedModel rightUpgradeModel, Matrix4f rightUpgradeTransform ) + public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, TransformationMatrix generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel ) { // Get the models m_baseModel = baseModel; m_overlayModel = overlayModel; m_leftUpgradeModel = leftUpgradeModel; - m_leftUpgradeTransform = leftUpgradeTransform; m_rightUpgradeModel = rightUpgradeModel; - m_rightUpgradeTransform = rightUpgradeTransform; m_generalTransform = generalTransform; } @@ -69,30 +68,22 @@ public class TurtleMultiModel implements IBakedModel private List buildQuads( BlockState state, Direction side, Random rand ) { ArrayList quads = new ArrayList<>(); - ModelTransformer.transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); + + + transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); if( m_overlayModel != null ) { - ModelTransformer.transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); + transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); } if( m_leftUpgradeModel != null ) { - Matrix4f upgradeTransform = m_generalTransform; - if( m_leftUpgradeTransform != null ) - { - upgradeTransform = new Matrix4f( m_generalTransform ); - upgradeTransform.mul( m_leftUpgradeTransform ); - } - ModelTransformer.transformQuadsTo( quads, m_leftUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); + TransformationMatrix upgradeTransform = m_generalTransform.compose( m_leftUpgradeModel.getMatrix() ); + transformQuadsTo( quads, m_leftUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); } if( m_rightUpgradeModel != null ) { - Matrix4f upgradeTransform = m_generalTransform; - if( m_rightUpgradeTransform != null ) - { - upgradeTransform = new Matrix4f( m_generalTransform ); - upgradeTransform.mul( m_rightUpgradeTransform ); - } - ModelTransformer.transformQuadsTo( quads, m_rightUpgradeModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); + TransformationMatrix upgradeTransform = m_generalTransform.compose( m_rightUpgradeModel.getMatrix() ); + transformQuadsTo( quads, m_rightUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); } quads.trimToSize(); return quads; @@ -116,6 +107,12 @@ public class TurtleMultiModel implements IBakedModel return m_baseModel.isBuiltInRenderer(); } + @Override + public boolean func_230044_c_() + { + return m_baseModel.func_230044_c_(); + } + @Nonnull @Override @Deprecated @@ -138,4 +135,15 @@ public class TurtleMultiModel implements IBakedModel { return ItemOverrideList.EMPTY; } + + private void transformQuadsTo( List output, List quads, TransformationMatrix transform ) + { + for( BakedQuad quad : quads ) + { + BakedQuadBuilder builder = new BakedQuadBuilder(); + TRSRTransformer transformer = new TRSRTransformer( builder, transform ); + quad.pipe( transformer ); + output.add( builder.build() ); + } + } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index d2eb5cf71..4ea94b46f 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -6,6 +6,8 @@ package dan200.computercraft.client.render; import com.google.common.base.Objects; +import com.mojang.blaze3d.matrix.MatrixStack; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.turtle.items.ItemTurtle; @@ -13,6 +15,7 @@ import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.entity.LivingEntity; @@ -21,28 +24,25 @@ import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraftforge.client.model.data.IModelData; -import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import javax.vecmath.Matrix4f; import java.util.HashMap; import java.util.List; import java.util.Random; public class TurtleSmartItemModel implements IBakedModel { - private static final Matrix4f s_identity, s_flip; + private static final TransformationMatrix identity, flip; static { - s_identity = new Matrix4f(); - s_identity.setIdentity(); + MatrixStack stack = new MatrixStack(); + stack.scale( 0, -1, 0 ); + stack.translate( 0, 0, 1 ); - s_flip = new Matrix4f(); - s_flip.setIdentity(); - s_flip.m11 = -1; // Flip on the y axis - s_flip.m13 = 1; // Models go from (0,0,0) to (1,1,1), so push back up. + identity = TransformationMatrix.identity(); + flip = new TransformationMatrix( stack.getLast().getPositionMatrix() ); } private static class TurtleModelCombination @@ -144,25 +144,10 @@ public class TurtleSmartItemModel implements IBakedModel IBakedModel baseModel = combo.m_colour ? colourModel : familyModel; IBakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null; - Matrix4f transform = combo.m_flip ? s_flip : s_identity; - Pair leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null; - Pair rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.Right ) : null; - if( leftModel != null && rightModel != null ) - { - return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel.getLeft(), leftModel.getRight(), rightModel.getLeft(), rightModel.getRight() ); - } - else if( leftModel != null ) - { - return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel.getLeft(), leftModel.getRight(), null, null ); - } - else if( rightModel != null ) - { - return new TurtleMultiModel( baseModel, overlayModel, transform, null, null, rightModel.getLeft(), rightModel.getRight() ); - } - else - { - return new TurtleMultiModel( baseModel, overlayModel, transform, null, null, null, null ); - } + TransformationMatrix transform = combo.m_flip ? flip : identity; + TransformedModel leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null; + TransformedModel rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.Right ) : null; + return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel ); } @Nonnull @@ -199,6 +184,12 @@ public class TurtleSmartItemModel implements IBakedModel return familyModel.isBuiltInRenderer(); } + @Override + public boolean func_230044_c_() + { + return familyModel.func_230044_c_(); + } + @Nonnull @Override @Deprecated diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render_old/CableHighlightRenderer.java similarity index 71% rename from src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java rename to src/main/java/dan200/computercraft/client/render_old/CableHighlightRenderer.java index 0e7290df2..556ab1d66 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render_old/CableHighlightRenderer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; @@ -21,7 +22,7 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.DrawBlockHighlightEvent; +import net.minecraftforge.client.event.DrawHighlightEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import org.lwjgl.opengl.GL11; @@ -40,11 +41,9 @@ public final class CableHighlightRenderer * @see WorldRenderer#drawSelectionBox(ActiveRenderInfo, RayTraceResult, int) */ @SubscribeEvent - public static void drawHighlight( DrawBlockHighlightEvent event ) + public static void drawHighlight( DrawHighlightEvent.HighlightBlock event ) { - if( event.getTarget().getType() != RayTraceResult.Type.BLOCK ) return; - - BlockRayTraceResult hit = (BlockRayTraceResult) event.getTarget(); + BlockRayTraceResult hit = event.getTarget(); BlockPos pos = hit.getPos(); World world = event.getInfo().getRenderViewEntity().getEntityWorld(); ActiveRenderInfo info = event.getInfo(); @@ -61,14 +60,14 @@ public final class CableHighlightRenderer Minecraft mc = Minecraft.getInstance(); - GlStateManager.enableBlend(); - GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); - GlStateManager.lineWidth( Math.max( 2.5F, mc.mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) ); - GlStateManager.disableTexture(); - GlStateManager.depthMask( false ); - GlStateManager.matrixMode( GL11.GL_PROJECTION ); - GlStateManager.pushMatrix(); - GlStateManager.scalef( 1.0F, 1.0F, 0.999F ); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); + RenderSystem.lineWidth( Math.max( 2.5F, mc.getMainWindow().getFramebufferWidth() / 1920.0F * 2.5F ) ); + RenderSystem.disableTexture(); + RenderSystem.depthMask( false ); + RenderSystem.matrixMode( GL11.GL_PROJECTION ); + RenderSystem.pushMatrix(); + RenderSystem.scalef( 1.0F, 1.0F, 0.999F ); VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? CableShapes.getModemShape( state ) @@ -80,10 +79,10 @@ public final class CableHighlightRenderer 0.0F, 0.0F, 0.0F, 0.4F ); - GlStateManager.popMatrix(); - GlStateManager.matrixMode( GL11.GL_MODELVIEW ); - GlStateManager.depthMask( true ); - GlStateManager.enableTexture(); - GlStateManager.disableBlend(); + RenderSystem.popMatrix(); + RenderSystem.matrixMode( GL11.GL_MODELVIEW ); + RenderSystem.depthMask( true ); + RenderSystem.enableTexture(); + RenderSystem.disableBlend(); } } diff --git a/src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java new file mode 100644 index 000000000..8a5472c99 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java @@ -0,0 +1,133 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.render; + +import com.mojang.blaze3d.matrix.MatrixStack; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.AbstractClientPlayerEntity; +import net.minecraft.client.renderer.FirstPersonRenderer; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Vector3f; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.HandSide; +import net.minecraft.util.math.MathHelper; + +public abstract class ItemMapLikeRenderer +{ + /** + * The main rendering method for the item. + * + * @param transform The matrix transformation stack + * @param render The buffer to render to + * @param stack The stack to render + * @see FirstPersonRenderer#renderItemInFirstPerson(AbstractClientPlayerEntity, float, float, Hand, float, ItemStack, float, MatrixStack, IRenderTypeBuffer, int) + */ + protected abstract void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ); + + protected void renderItemFirstPerson( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, Hand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack ) + { + PlayerEntity player = Minecraft.getInstance().player; + + transform.push(); + if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() ) + { + renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack ); + } + else + { + renderItemFirstPersonSide( + transform, render, lightTexture, + hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(), + equipProgress, swingProgress, stack + ); + } + transform.pop(); + } + + /** + * Renders the item to one side of the player. + * + * @param side The side to render on + * @param equipProgress The equip progress of this item + * @param swingProgress The swing progress of this item + * @param stack The stack to render + * @see FirstPersonRenderer#renderMapFirstPersonSide(MatrixStack, IRenderTypeBuffer, int, float, HandSide, float, ItemStack) + */ + private void renderItemFirstPersonSide( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, HandSide side, float equipProgress, float swingProgress, ItemStack stack ) + { + Minecraft minecraft = Minecraft.getInstance(); + float offset = side == HandSide.RIGHT ? 1f : -1f; + transform.translate( offset * 0.125f, -0.125f, 0f ); + + // If the player is not invisible then render a single arm + if( !minecraft.player.isInvisible() ) + { + transform.push(); + transform.rotate( Vector3f.field_229183_f_.func_229187_a_( offset * 10f ) ); + minecraft.getFirstPersonRenderer().renderArmFirstPerson( transform, render, lightTexture, equipProgress, swingProgress, side ); + transform.pop(); + } + + // Setup the appropriate transformations. This is just copied from the + // corresponding method in ItemRenderer. + transform.push(); + transform.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f ); + float f1 = MathHelper.sqrt( swingProgress ); + float f2 = MathHelper.sin( f1 * (float) Math.PI ); + float f3 = -0.5f * f2; + float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); + float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); + transform.translate( offset * f3, f4 - 0.3f * f2, f5 ); + transform.rotate( Vector3f.field_229179_b_.func_229187_a_( f2 * -45f ) ); + transform.rotate( Vector3f.field_229181_d_.func_229187_a_( offset * f2 * -30f ) ); + + renderItem( transform, render, stack ); + + transform.pop(); + } + + /** + * Render an item in the middle of the screen. + * + * @param pitch The pitch of the player + * @param equipProgress The equip progress of this item + * @param swingProgress The swing progress of this item + * @param stack The stack to render + * @see FirstPersonRenderer#renderMapFirstPerson(MatrixStack, IRenderTypeBuffer, int, float, float, float) + */ + private void renderItemFirstPersonCenter( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, float pitch, float equipProgress, float swingProgress, ItemStack stack ) + { + Minecraft minecraft = Minecraft.getInstance(); + FirstPersonRenderer renderer = minecraft.getFirstPersonRenderer(); + + // Setup the appropriate transformations. This is just copied from the + // corresponding method in ItemRenderer. + float swingRt = MathHelper.sqrt( swingProgress ); + float tX = -0.2f * MathHelper.sin( swingProgress * (float) Math.PI ); + float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI ); + transform.translate( 0, -tX / 2, tZ ); + + float pitchAngle = renderer.getMapAngleFromPitch( pitch ); + transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); + transform.rotate( Vector3f.field_229179_b_.func_229187_a_( pitchAngle * -85.0f ) ); + if( !minecraft.player.isInvisible() ) + { + transform.push(); + transform.rotate( Vector3f.field_229181_d_.func_229187_a_( 90.0F ) ); + renderer.renderArm( transform, render, lightTexture, HandSide.RIGHT ); + renderer.renderArm( transform, render, lightTexture, HandSide.LEFT ); + transform.pop(); + } + + float rX = MathHelper.sin( swingRt * (float) Math.PI ); + transform.rotate( Vector3f.field_229179_b_.func_229187_a_( rX * 20.0F ) ); + transform.scale( 2.0F, 2.0F, 2.0F ); + + renderItem( transform, render, stack ); + } +} diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java similarity index 84% rename from src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java rename to src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java index ca870e66a..d3134d854 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java @@ -5,7 +5,9 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; @@ -18,6 +20,7 @@ import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; @@ -53,11 +56,16 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer if( !(stack.getItem() instanceof ItemPocketComputer) ) return; event.setCanceled( true ); - INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() ); + Minecraft minecraft = Minecraft.getInstance(); + INSTANCE.renderItemFirstPerson( + event.getMatrixStack(), minecraft.func_228019_au_().func_228487_b_(), + minecraft.getRenderManager().func_229085_a_( minecraft.player, event.getPartialTicks() ), + event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() + ); } @Override - protected void renderItem( ItemStack stack ) + protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ) { ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); Terminal terminal = computer == null ? null : computer.getTerminal(); @@ -79,18 +87,17 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer // Setup various transformations. Note that these are partially adapted from the corresponding method // in ItemRenderer - GlStateManager.pushMatrix(); + transform.push(); + // TODO: RenderSystem.disableLighting(); + // TODO: RenderSystem.disableDepthTest(); - GlStateManager.disableLighting(); - GlStateManager.disableDepthTest(); + RenderSystem.rotatef( 180f, 0f, 1f, 0f ); + RenderSystem.rotatef( 180f, 0f, 0f, 1f ); + transform.scale( 0.5f, 0.5f, 0.5f ); - GlStateManager.rotatef( 180f, 0f, 1f, 0f ); - GlStateManager.rotatef( 180f, 0f, 0f, 1f ); - GlStateManager.scalef( 0.5f, 0.5f, 0.5f ); - - double scale = 0.75 / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT ); - GlStateManager.scaled( scale, scale, 0 ); - GlStateManager.translated( -0.5 * width, -0.5 * height, 0 ); + float scale = 0.75f / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT ); + transform.scale( scale, scale, 0 ); + transform.translate( -0.5 * width, -0.5 * height, 0 ); // Render the main frame ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); @@ -106,7 +113,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer if( computer != null && terminal != null ) { // If we've a computer and terminal then attempt to render it. - renderTerminal( terminal, !computer.isColour(), width, height ); + renderTerminal( terminal, !computer.isColour() ); } else { @@ -122,9 +129,9 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer tessellator.draw(); } - GlStateManager.enableDepthTest(); - GlStateManager.enableLighting(); - GlStateManager.popMatrix(); + // TODO: RenderSystem.enableDepthTest(); + // TODO: RenderSystem.enableLighting(); + transform.pop(); } private static void renderFrame( ComputerFamily family, int colour, int width, int height ) @@ -171,8 +178,8 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer private static void renderLight( int colour, int width, int height ) { - GlStateManager.enableBlend(); - GlStateManager.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.disableTexture(); float r = ((colour >>> 16) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f; @@ -187,10 +194,10 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); tessellator.draw(); - GlStateManager.enableTexture(); + RenderSystem.enableTexture(); } - private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height ) + private static void renderTerminal( Terminal terminal, boolean greyscale ) { synchronized( terminal ) { @@ -237,12 +244,12 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer } } - private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) + private static void renderTexture( IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) { renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b ); } - private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b ) + private static void renderTexture( IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b ) { float scale = 1 / 255.0f; builder.pos( x, y + height, 0 ).tex( textureX * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex(); diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render_old/ItemPrintoutRenderer.java similarity index 80% rename from src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java rename to src/main/java/dan200/computercraft/client/render_old/ItemPrintoutRenderer.java index 611406cb9..eee8e191d 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render_old/ItemPrintoutRenderer.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemPrintout; import net.minecraft.item.ItemStack; @@ -48,16 +48,16 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { // Setup various transformations. Note that these are partially adapated from the corresponding method // in FirstPersonRenderer.renderFirstPersonMap - GlStateManager.disableLighting(); + RenderSystem.disableLighting(); - GlStateManager.rotatef( 180f, 0f, 1f, 0f ); - GlStateManager.rotatef( 180f, 0f, 0f, 1f ); - GlStateManager.scalef( 0.42f, 0.42f, -0.42f ); - GlStateManager.translatef( -0.5f, -0.48f, 0.0f ); + RenderSystem.rotatef( 180f, 0f, 1f, 0f ); + RenderSystem.rotatef( 180f, 0f, 0f, 1f ); + RenderSystem.scalef( 0.42f, 0.42f, -0.42f ); + RenderSystem.translatef( -0.5f, -0.48f, 0.0f ); drawPrintout( stack ); - GlStateManager.enableLighting(); + RenderSystem.enableLighting(); } @SubscribeEvent @@ -68,18 +68,18 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer event.setCanceled( true ); - GlStateManager.disableLighting(); + RenderSystem.disableLighting(); // Move a little bit forward to ensure we're not clipping with the frame - GlStateManager.translatef( 0.0f, 0.0f, -0.001f ); - GlStateManager.rotatef( 180f, 0f, 0f, 1f ); - GlStateManager.scalef( 0.95f, 0.95f, -0.95f ); - GlStateManager.translatef( -0.5f, -0.5f, 0.0f ); + RenderSystem.translatef( 0.0f, 0.0f, -0.001f ); + RenderSystem.rotatef( 180f, 0f, 0f, 1f ); + RenderSystem.scalef( 0.95f, 0.95f, -0.95f ); + RenderSystem.translatef( -0.5f, -0.5f, 0.0f ); drawPrintout( stack ); - GlStateManager.enableLighting(); - GlStateManager.disableBlend(); + RenderSystem.enableLighting(); + RenderSystem.disableBlend(); } private static void drawPrintout( ItemStack stack ) @@ -106,8 +106,8 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer // Scale the printout to fit correctly. double scale = 1.0 / max; - GlStateManager.scaled( scale, scale, scale ); - GlStateManager.translated( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); + RenderSystem.scaled( scale, scale, scale ); + RenderSystem.translated( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); drawBorder( 0, 0, -0.01, 0, pages, book ); drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render_old/MonitorHighlightRenderer.java similarity index 56% rename from src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java rename to src/main/java/dan200/computercraft/client/render_old/MonitorHighlightRenderer.java index 0f3a3ca2b..1eb3d4625 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render_old/MonitorHighlightRenderer.java @@ -5,25 +5,22 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.DrawBlockHighlightEvent; +import net.minecraftforge.client.event.DrawHighlightEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import org.lwjgl.opengl.GL11; import java.util.EnumSet; @@ -39,15 +36,12 @@ public final class MonitorHighlightRenderer } @SubscribeEvent - public static void drawHighlight( DrawBlockHighlightEvent event ) + public static void drawHighlight( DrawHighlightEvent.HighlightBlock event ) { - if( event.getTarget().getType() != RayTraceResult.Type.BLOCK || event.getInfo().getRenderViewEntity().isSneaking() ) - { - return; - } + if( event.getInfo().getRenderViewEntity().isCrouching() ) return; World world = event.getInfo().getRenderViewEntity().getEntityWorld(); - BlockPos pos = ((BlockRayTraceResult) event.getTarget()).getPos(); + BlockPos pos = event.getTarget().getPos(); TileEntity tile = world.getTileEntity( pos ); if( !(tile instanceof TileMonitor) ) return; @@ -64,50 +58,37 @@ public final class MonitorHighlightRenderer if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() ); if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() ); - GlStateManager.enableBlend(); - GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); - GlStateManager.lineWidth( Math.max( 2.5F, (float) Minecraft.getInstance().mainWindow.getFramebufferWidth() / 1920.0F * 2.5F ) ); - GlStateManager.disableTexture(); - GlStateManager.depthMask( false ); - GlStateManager.pushMatrix(); + IVertexBuilder buffer = Minecraft.getInstance().func_228019_au_().func_228487_b_().getBuffer( RenderType.lines() ); Vec3d cameraPos = event.getInfo().getProjectedView(); - GlStateManager.translated( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR ); + transformStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); // I wish I could think of a better way to do this - if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 0, UP ); - if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 1, UP ); - if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 0, UP ); - if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 1, UP ); - if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, EAST ); - if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 1, EAST ); - if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, EAST ); - if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 1, EAST ); - if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, SOUTH ); - if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, 1, 0, 0, SOUTH ); - if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, SOUTH ); - if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, 1, 1, 0, SOUTH ); + Matrix4f transform = transformStack.getLast().getPositionMatrix(); + if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 0, UP ); + if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 1, UP ); + if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, transform, 1, 0, 0, UP ); + if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, transform, 1, 0, 1, UP ); + if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, transform, 0, 0, 0, EAST ); + if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, transform, 0, 0, 1, EAST ); + if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 0, EAST ); + if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 1, EAST ); + if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, transform, 0, 0, 0, SOUTH ); + if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, transform, 1, 0, 0, SOUTH ); + if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 0, SOUTH ); + if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, transform, 1, 1, 0, SOUTH ); - tessellator.draw(); - - GlStateManager.popMatrix(); - GlStateManager.depthMask( true ); - GlStateManager.enableTexture(); - GlStateManager.disableBlend(); + transformStack.pop(); } - private static void line( BufferBuilder buffer, int x, int y, int z, Direction direction ) + private static void line( IVertexBuilder buffer, Matrix4f transform, float x, float y, float z, Direction direction ) { - double minX = x == 0 ? -EXPAND : 1 + EXPAND; - double minY = y == 0 ? -EXPAND : 1 + EXPAND; - double minZ = z == 0 ? -EXPAND : 1 + EXPAND; + float minX = x == 0 ? -EXPAND : 1 + EXPAND; + float minY = y == 0 ? -EXPAND : 1 + EXPAND; + float minZ = z == 0 ? -EXPAND : 1 + EXPAND; - buffer.pos( minX, minY, minZ ).color( 0, 0, 0, 0.4f ).endVertex(); - buffer.pos( + buffer.pos( transform, minX, minY, minZ ).color( 0, 0, 0, 0.4f ).endVertex(); + buffer.pos( transform, minX + direction.getXOffset() * (1 + EXPAND * 2), minY + direction.getYOffset() * (1 + EXPAND * 2), minZ + direction.getZOffset() * (1 + EXPAND * 2) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java similarity index 84% rename from src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java rename to src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java index dab6dcd3f..66120e290 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityCableRenderer.java +++ b/src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; @@ -110,17 +111,17 @@ public class TileEntityCableRenderer extends TileEntityRenderer */ private void preRenderDamagedBlocks() { - GlStateManager.disableLighting(); + RenderSystem.disableLighting(); - GlStateManager.enableBlend(); - GlStateManager.blendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); - GlStateManager.enableBlend(); - GlStateManager.color4f( 1.0F, 1.0F, 1.0F, 0.5F ); - GlStateManager.polygonOffset( -3.0F, -3.0F ); - GlStateManager.enablePolygonOffset(); - GlStateManager.alphaFunc( 516, 0.1F ); - GlStateManager.enableAlphaTest(); - GlStateManager.pushMatrix(); + RenderSystem.enableBlend(); + RenderSystem.blendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); + RenderSystem.enableBlend(); + RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 0.5F ); + RenderSystem.polygonOffset( -3.0F, -3.0F ); + RenderSystem.enablePolygonOffset(); + RenderSystem.alphaFunc( 516, 0.1F ); + RenderSystem.enableAlphaTest(); + RenderSystem.pushMatrix(); } /** @@ -130,11 +131,11 @@ public class TileEntityCableRenderer extends TileEntityRenderer */ private void postRenderDamagedBlocks() { - GlStateManager.disableAlphaTest(); - GlStateManager.polygonOffset( 0.0F, 0.0F ); - GlStateManager.disablePolygonOffset(); - GlStateManager.disablePolygonOffset(); - GlStateManager.depthMask( true ); - GlStateManager.popMatrix(); + RenderSystem.disableAlphaTest(); + RenderSystem.polygonOffset( 0.0F, 0.0F ); + RenderSystem.disablePolygonOffset(); + RenderSystem.disablePolygonOffset(); + RenderSystem.depthMask( true ); + RenderSystem.popMatrix(); } } diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 60e0e454a..864c51949 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -324,7 +324,7 @@ public final class Config } @SubscribeEvent - public static void sync( ModConfig.ConfigReloading event ) + public static void sync( ModConfig.Reloading event ) { // Ensure file configs are reloaded. Forge should probably do this, so worth checking in the future. CommentedConfig config = event.getConfig().getConfigData(); diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index 28b091e45..81a4f45f5 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -11,12 +11,14 @@ import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -45,12 +47,13 @@ public abstract class BlockGeneric extends Block if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy(); } + @Nonnull @Override @Deprecated - public final boolean onBlockActivated( BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public final ActionResultType onBlockActivated( BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { TileEntity tile = world.getTileEntity( pos ); - return tile instanceof TileGeneric && ((TileGeneric) tile).onActivate( player, hand, hit ); + return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : ActionResultType.PASS; } @Override @@ -70,7 +73,7 @@ public abstract class BlockGeneric extends Block @Override @Deprecated - public void tick( BlockState state, World world, BlockPos pos, Random rand ) + public void tick( BlockState state, ServerWorld world, BlockPos pos, Random rand ) { TileEntity te = world.getTileEntity( pos ); if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick(); diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index fb6e9c568..5d391cf8a 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -12,6 +12,7 @@ import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SUpdateTileEntityPacket; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; @@ -37,9 +38,10 @@ public abstract class TileGeneric extends TileEntity getWorld().notifyBlockUpdate( pos, state, state, 3 ); } - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + @Nonnull + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - return false; + return ActionResultType.PASS; } public void onNeighbourChange( @Nonnull BlockPos neighbour ) diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 9f4aad451..cfb798420 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -30,6 +30,7 @@ import net.minecraft.item.Items; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.INameable; @@ -102,8 +103,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT return false; } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { ItemStack currentItem = player.getHeldItem( hand ); if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasDisplayName() ) @@ -114,9 +116,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT setLabel( currentItem.getDisplayName().getString() ); currentItem.shrink( 1 ); } - return true; + return ActionResultType.SUCCESS; } - else if( !player.isSneaking() ) + else if( !player.isCrouching() ) { // Regular right click to activate computer if( !getWorld().isRemote && isUsable( player, false ) ) @@ -124,9 +126,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT createServerComputer().turnOn(); new ComputerContainerData( createServerComputer() ).open( player, this ); } - return true; + return ActionResultType.SUCCESS; } - return false; + return ActionResultType.PASS; } @Override diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 938f56812..bf50799fc 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -76,12 +76,10 @@ public final class NetworkHandler { for( ServerPlayerEntity player : ServerLifecycleHooks.getCurrentServer().getPlayerList().getPlayers() ) { - if( player.getEntityWorld() != world ) continue; - - double x = pos.x - player.posX; - double y = pos.y - player.posY; - double z = pos.z - player.posZ; - if( x * x + y * y + z * z < range * range ) sendToPlayer( player, packet ); + if( player.getEntityWorld() == world && player.getDistanceSq( pos ) < range * range ) + { + sendToPlayer( player, packet ); + } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 2dccbe460..79a8422a4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -99,26 +99,27 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - if( player.isSneaking() ) + if( player.isCrouching() ) { // Try to put a disk into the drive ItemStack disk = player.getHeldItem( hand ); - if( disk.isEmpty() ) return false; + if( disk.isEmpty() ) return ActionResultType.PASS; if( !getWorld().isRemote && getStackInSlot( 0 ).isEmpty() && MediaProviders.get( disk ) != null ) { setDiskStack( disk ); player.setHeldItem( hand, ItemStack.EMPTY ); } - return true; + return ActionResultType.SUCCESS; } else { // Open the GUI if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this ); - return true; + return ActionResultType.SUCCESS; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 0ff261143..530b81bda 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -250,11 +250,4 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable .with( WEST, false ).with( UP, false ).with( DOWN, false ); } } - - @Override - @Deprecated - public boolean hasCustomBreakingProgress( BlockState state ) - { - return true; - } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index d683cac55..bfe602ce0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -24,6 +24,7 @@ import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; @@ -238,12 +239,14 @@ public class TileCable extends TileGeneric implements IPeripheralTile } } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - if( !canAttachPeripheral() || player.isSneaking() ) return false; + if( player.isCrouching() ) return ActionResultType.PASS; + if( !canAttachPeripheral() ) return ActionResultType.FAIL; - if( getWorld().isRemote ) return true; + if( getWorld().isRemote ) return ActionResultType.SUCCESS; String oldName = m_peripheral.getConnectedName(); togglePeripheralAccess(); @@ -262,7 +265,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile } } - return true; + return ActionResultType.SUCCESS; } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 710bd8c6d..84aa21a32 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -22,6 +22,7 @@ import dan200.computercraft.shared.wired.CapabilityWiredElement; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; @@ -184,10 +185,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile } } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - if( getWorld().isRemote ) return true; + if( getWorld().isRemote ) return ActionResultType.SUCCESS; // On server, we interacted if a peripheral was found Set oldPeriphNames = getConnectedPeripheralNames(); @@ -200,7 +202,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile sendPeripheralChanges( player, "chat.computercraft.wired_modem.peripheral_connected", periphNames ); } - return true; + return ActionResultType.SUCCESS; } private static void sendPeripheralChanges( PlayerEntity player, String kind, Collection peripherals ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 6bf60083a..c1e5d0ed4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -18,12 +18,10 @@ import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.BlockRenderLayer; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockMonitor extends BlockGeneric @@ -38,28 +36,13 @@ public class BlockMonitor extends BlockGeneric public BlockMonitor( Properties settings, NamedTileEntityType type ) { super( settings, type ); + // TODO: Test underwater - do we need isSolid at all? setDefaultState( getStateContainer().getBaseState() .with( ORIENTATION, Direction.NORTH ) .with( FACING, Direction.NORTH ) .with( STATE, MonitorEdgeState.NONE ) ); } - @Nonnull - @Override - public BlockRenderLayer getRenderLayer() - { - // We use the CUTOUT layer, as otherwise monitor rendering will cause flickering. - return BlockRenderLayer.CUTOUT; - } - - @Override - @Deprecated - public boolean isSolid( BlockState state ) - { - // We override isSolid, as our overriding of getRenderLayer means that it would otherwise return false. - return true; - } - @Override protected void fillStateContainer( StateContainer.Builder builder ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 88b57cc8c..508109f2d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -5,8 +5,9 @@ */ package dan200.computercraft.shared.peripheral.monitor; -import com.mojang.blaze3d.platform.GlStateManager; +import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.shared.common.ClientTerminal; +import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.math.BlockPos; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -23,7 +24,7 @@ public class ClientMonitor extends ClientTerminal public long lastRenderFrame = -1; public BlockPos lastRenderPos = null; - public int[] renderDisplayLists = null; + public VertexBuffer buffer = null; public ClientMonitor( boolean colour, TileMonitor origin ) { @@ -37,17 +38,11 @@ public class ClientMonitor extends ClientTerminal } @OnlyIn( Dist.CLIENT ) - public void createLists() + public void createBuffer() { - if( renderDisplayLists == null ) + if( buffer == null ) { - renderDisplayLists = new int[3]; - - for( int i = 0; i < renderDisplayLists.length; i++ ) - { - renderDisplayLists[i] = GlStateManager.genLists( 1 ); - } - + buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.getVertexFormat() ); synchronized( allMonitors ) { allMonitors.add( this ); @@ -58,19 +53,15 @@ public class ClientMonitor extends ClientTerminal @OnlyIn( Dist.CLIENT ) public void destroy() { - if( renderDisplayLists != null ) + if( buffer != null ) { synchronized( allMonitors ) { allMonitors.remove( this ); } - for( int list : renderDisplayLists ) - { - GlStateManager.deleteLists( list, 1 ); - } - - renderDisplayLists = null; + buffer.close(); + buffer = null; } } @@ -82,13 +73,10 @@ public class ClientMonitor extends ClientTerminal for( Iterator iterator = allMonitors.iterator(); iterator.hasNext(); ) { ClientMonitor monitor = iterator.next(); - if( monitor.renderDisplayLists != null ) + if( monitor.buffer != null ) { - for( int list : monitor.renderDisplayLists ) - { - GlStateManager.deleteLists( list, 1 ); - } - monitor.renderDisplayLists = null; + monitor.buffer.close(); + monitor.buffer = null; } iterator.remove(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 447cb52e9..6a1f01ed1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -18,6 +18,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; @@ -104,10 +105,11 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy(); } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - if( !player.isSneaking() && getFront() == hit.getFace() ) + if( !player.isCrouching() && getFront() == hit.getFace() ) { if( !getWorld().isRemote ) { @@ -117,10 +119,10 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile (float) (hit.getHitVec().z - hit.getPos().getZ()) ); } - return true; + return ActionResultType.SUCCESS; } - return false; + return ActionResultType.PASS; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 90ec2a223..529ec7d23 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -25,8 +25,8 @@ import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.*; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.*; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.capabilities.Capability; @@ -94,13 +94,14 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { - if( player.isSneaking() ) return false; + if( player.isCrouching() ) return ActionResultType.PASS; if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this ); - return true; + return ActionResultType.SUCCESS; } @Override @@ -424,11 +425,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent setInventorySlotContents( i, ItemStack.EMPTY ); // Spawn the item in the world - BlockPos pos = getPos(); - double x = pos.getX() + 0.5; - double y = pos.getY() + 0.75; - double z = pos.getZ() + 0.5; - WorldUtil.dropItemStack( stack, getWorld(), x, y, z ); + WorldUtil.dropItemStack( stack, getWorld(), new Vec3d( getPos() ).add( 0.5, 0.75, 0.5 ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 286431e15..9d481758b 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -80,7 +80,7 @@ public class PocketAPI implements ILuaAPI stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); if( !stack.isEmpty() ) { - WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.posX, player.posY, player.posZ ); + WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() ); } } } @@ -111,7 +111,7 @@ public class PocketAPI implements ILuaAPI stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); if( stack.isEmpty() ) { - WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.posX, player.posY, player.posZ ); + WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() ); } } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 2b3261491..8f5c8536d 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -11,7 +11,6 @@ import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.tracking.Tracking; -import dan200.computercraft.shared.Config; import dan200.computercraft.shared.command.CommandComputerCraft; import dan200.computercraft.shared.command.arguments.ArgumentSerializers; import dan200.computercraft.shared.common.DefaultBundledRedstoneProvider; @@ -36,7 +35,6 @@ import net.minecraft.world.storage.loot.conditions.LootConditionManager; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.client.event.ConfigChangedEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; @@ -127,12 +125,6 @@ public final class ComputerCraftProxyCommon } } - @SubscribeEvent - public static void onConfigChanged( ConfigChangedEvent.OnConfigChangedEvent event ) - { - if( event.getModID().equals( ComputerCraft.MOD_ID ) ) Config.sync(); - } - @SubscribeEvent public static void onContainerOpen( PlayerContainerEvent.Open event ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index e4d695616..6ac5a4864 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -33,10 +33,7 @@ import net.minecraft.item.Items; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; +import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; @@ -164,8 +161,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } } + @Nonnull @Override - public boolean onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) { // Apply dye ItemStack currentItem = player.getHeldItem( hand ); @@ -186,7 +184,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } } } - return true; + return ActionResultType.SUCCESS; } else if( currentItem.getItem() == Items.WATER_BUCKET && m_brain.getColour() != -1 ) { @@ -203,7 +201,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } } } - return true; + return ActionResultType.SUCCESS; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 12df27cc4..116f314d9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -337,8 +337,7 @@ public class TurtleBrain implements ITurtleAccess { // Copy the old turtle state into the new turtle TileTurtle newTurtle = (TileTurtle) newTile; - newTurtle.setWorld( world ); - newTurtle.setPos( pos ); + newTurtle.setWorldAndPos( world, pos ); newTurtle.transferStateFrom( oldOwner ); newTurtle.createServerComputer().setWorld( world ); newTurtle.createServerComputer().setPosition( pos ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index ff828f930..d00096461 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -170,16 +170,16 @@ public class TurtlePlaceCommand implements ITurtleCommand private static void orientPlayer( ITurtleAccess turtle, TurtlePlayer turtlePlayer, BlockPos position, Direction direction ) { - turtlePlayer.posX = position.getX() + 0.5; - turtlePlayer.posY = position.getY() + 0.5; - turtlePlayer.posZ = position.getZ() + 0.5; + double posX = position.getX() + 0.5; + double posY = position.getY() + 0.5; + double posZ = position.getZ() + 0.5; // Stop intersection with the turtle itself if( turtle.getPosition().equals( position ) ) { - turtlePlayer.posX += 0.48 * direction.getXOffset(); - turtlePlayer.posY += 0.48 * direction.getYOffset(); - turtlePlayer.posZ += 0.48 * direction.getZOffset(); + posX += 0.48 * direction.getXOffset(); + posY += 0.48 * direction.getYOffset(); + posZ += 0.48 * direction.getZOffset(); } if( direction.getAxis() != Direction.Axis.Y ) @@ -193,9 +193,10 @@ public class TurtlePlaceCommand implements ITurtleCommand turtlePlayer.rotationPitch = DirectionUtil.toPitchAngle( direction ); } - turtlePlayer.prevPosX = turtlePlayer.posX; - turtlePlayer.prevPosY = turtlePlayer.posY; - turtlePlayer.prevPosZ = turtlePlayer.posZ; + turtlePlayer.setRawPosition( posX, posY, posZ ); + turtlePlayer.prevPosX = posX; + turtlePlayer.prevPosY = posY; + turtlePlayer.prevPosZ = posZ; turtlePlayer.prevRotationPitch = turtlePlayer.rotationPitch; turtlePlayer.prevRotationYaw = turtlePlayer.rotationYaw; @@ -209,7 +210,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // See if there is an entity present final World world = turtle.getWorld(); final BlockPos position = turtle.getPosition(); - Vec3d turtlePos = new Vec3d( turtlePlayer.posX, turtlePlayer.posY, turtlePlayer.posZ ); + Vec3d turtlePos = turtlePlayer.getPositionVec(); Vec3d rayDir = turtlePlayer.getLook( 1.0f ); Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); if( hit == null ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 6e5e6952e..082a5b1c0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -65,9 +65,7 @@ public final class TurtlePlayer extends FakePlayer } BlockPos position = turtle.getPosition(); - posX = position.getX() + 0.5; - posY = position.getY() + 0.5; - posZ = position.getZ() + 0.5; + setRawPosition( position.getX() + 0.5, position.getY() + 0.5, position.getZ() + 0.5 ); rotationYaw = turtle.getDirection().getHorizontalAngle(); rotationPitch = 0.0f; @@ -137,10 +135,9 @@ public final class TurtlePlayer extends FakePlayer @Override public Vec3d getPositionVector() { - return new Vec3d( posX, posY, posZ ); + return getPositionVec(); } - @Override public float getEyeHeight( @Nonnull Pose pose ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 02b4b01bf..6267dff39 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -6,22 +6,18 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.AbstractTurtleUpgrade; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; import net.minecraft.block.Blocks; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; -import javax.vecmath.Matrix4f; public class TurtleCraftingTable extends AbstractTurtleUpgrade { @@ -55,19 +51,9 @@ public class TurtleCraftingTable extends AbstractTurtleUpgrade @Nonnull @Override @OnlyIn( Dist.CLIENT ) - public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) + public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); - - Matrix4f transform = null; - ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); - if( side == TurtleSide.Left ) - { - return Pair.of( modelManager.getModel( m_leftModel ), transform ); - } - else - { - return Pair.of( modelManager.getModel( m_rightModel ), transform ); - } + return TransformedModel.of( side == TurtleSide.Left ? m_leftModel : m_rightModel ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 8c73203e5..a8bf2ca0a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -7,13 +7,11 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.AbstractTurtleUpgrade; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; @@ -23,10 +21,8 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; -import javax.vecmath.Matrix4f; public class TurtleModem extends AbstractTurtleUpgrade { @@ -129,7 +125,7 @@ public class TurtleModem extends AbstractTurtleUpgrade @Nonnull @Override @OnlyIn( Dist.CLIENT ) - public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) + public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); @@ -137,28 +133,12 @@ public class TurtleModem extends AbstractTurtleUpgrade if( turtle != null ) { CompoundNBT turtleNBT = turtle.getUpgradeNBTData( side ); - if( turtleNBT.contains( "active" ) ) - { - active = turtleNBT.getBoolean( "active" ); - } + active = turtleNBT.contains( "active" ) && turtleNBT.getBoolean( "active" ); } - Matrix4f transform = null; - ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); - if( side == TurtleSide.Left ) - { - return Pair.of( - active ? modelManager.getModel( m_leftOnModel ) : modelManager.getModel( m_leftOffModel ), - transform - ); - } - else - { - return Pair.of( - active ? modelManager.getModel( m_rightOnModel ) : modelManager.getModel( m_rightOffModel ), - transform - ); - } + return side == TurtleSide.Left + ? TransformedModel.of( active ? m_leftOnModel : m_leftOffModel ) + : TransformedModel.of( active ? m_rightOnModel : m_rightOffModel ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 122933983..581af58b5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -8,14 +8,12 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.AbstractTurtleUpgrade; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -23,10 +21,8 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; -import javax.vecmath.Matrix4f; public class TurtleSpeaker extends AbstractTurtleUpgrade { @@ -89,19 +85,10 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade @Nonnull @Override @OnlyIn( Dist.CLIENT ) - public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) + public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); - ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager(); - - if( side == TurtleSide.Left ) - { - return Pair.of( modelManager.getModel( m_leftModel ), null ); - } - else - { - return Pair.of( modelManager.getModel( m_rightModel ), null ); - } + return TransformedModel.of( side == TurtleSide.Left ? m_leftModel : m_rightModel ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 0c372da2c..57738a357 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.AbstractTurtleUpgrade; +import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.*; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; @@ -19,8 +20,8 @@ import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.entity.Entity; import net.minecraft.entity.SharedMonsterAttributes; import net.minecraft.entity.item.ArmorStandEntity; @@ -42,7 +43,6 @@ import net.minecraftforge.event.world.BlockEvent; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; -import javax.vecmath.Matrix4f; import java.util.List; import java.util.function.Function; @@ -71,20 +71,16 @@ public class TurtleTool extends AbstractTurtleUpgrade @Nonnull @Override @OnlyIn( Dist.CLIENT ) - public Pair getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) + public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { float xOffset = side == TurtleSide.Left ? -0.40625f : 0.40625f; - Matrix4f transform = new Matrix4f( + Matrix4f transform = new Matrix4f( new float[] { 0.0f, 0.0f, -1.0f, 1.0f + xOffset, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 0.0f, 1.0f - ); - Minecraft mc = Minecraft.getInstance(); - return Pair.of( - mc.getItemRenderer().getItemModelMesher().getItemModel( getCraftingItem() ), - transform - ); + 0.0f, 0.0f, 0.0f, 1.0f, + } ); + return TransformedModel.of( getCraftingItem(), new TransformationMatrix( transform ) ); } @Nonnull @@ -124,7 +120,7 @@ public class TurtleTool extends AbstractTurtleUpgrade final TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction ); // See if there is an entity present - Vec3d turtlePos = new Vec3d( turtlePlayer.posX, turtlePlayer.posY, turtlePlayer.posZ ); + Vec3d turtlePos = turtlePlayer.getPositionVec(); Vec3d rayDir = turtlePlayer.getLook( 1.0f ); Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); if( hit != null ) diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 1aab71afd..4f4b9cfba 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -20,9 +20,9 @@ public final class NBTUtil private static INBT toNBTTag( Object object ) { if( object == null ) return null; - if( object instanceof Boolean ) return new ByteNBT( (byte) ((boolean) (Boolean) object ? 1 : 0) ); - if( object instanceof Number ) return new DoubleNBT( ((Number) object).doubleValue() ); - if( object instanceof String ) return new StringNBT( object.toString() ); + if( object instanceof Boolean ) return ByteNBT.valueOf( (byte) ((boolean) (Boolean) object ? 1 : 0) ); + if( object instanceof Number ) return DoubleNBT.valueOf( ((Number) object).doubleValue() ); + if( object instanceof String ) return StringNBT.valueOf( object.toString() ); if( object instanceof Map ) { Map m = (Map) object; diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index d80c28b99..32c710dcf 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -172,17 +172,17 @@ public final class WorldUtil double xPos = pos.getX() + 0.5 + xDir * 0.4; double yPos = pos.getY() + 0.5 + yDir * 0.4; double zPos = pos.getZ() + 0.5 + zDir * 0.4; - dropItemStack( stack, world, xPos, yPos, zPos, xDir, yDir, zDir ); + dropItemStack( stack, world, new Vec3d( xPos, yPos, zPos ), xDir, yDir, zDir ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, double xPos, double yPos, double zPos ) + public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos ) { - dropItemStack( stack, world, xPos, yPos, zPos, 0.0, 0.0, 0.0 ); + dropItemStack( stack, world, pos, 0.0, 0.0, 0.0 ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, double xPos, double yPos, double zPos, double xDir, double yDir, double zDir ) + public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos, double xDir, double yDir, double zDir ) { - ItemEntity item = new ItemEntity( world, xPos, yPos, zPos, stack.copy() ); + ItemEntity item = new ItemEntity( world, pos.x, pos.y, pos.z, stack.copy() ); item.setMotion( xDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1, yDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1, diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 63fe86547..0db231ddd 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,4 +1,4 @@ # ItemPocketRenderer/ItemPrintoutRenderer -public net.minecraft.client.renderer.FirstPersonRenderer func_187466_c()V # renderArms public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch -public net.minecraft.client.renderer.FirstPersonRenderer func_187456_a(FFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson +public net.minecraft.client.renderer.FirstPersonRenderer func_228401_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;IFFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson +public net.minecraft.client.renderer.FirstPersonRenderer func_228403_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/util/HandSide;)V # renderArm diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index fed62637f..70570cf08 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[28,29)" +loaderVersion="[31,32)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[28.1.71,29)" + versionRange="[31.0.1,32)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/assets/computercraft/models/block/turtle_advanced.json b/src/main/resources/assets/computercraft/models/block/turtle_advanced.json index c232c67d3..6e7ed42a5 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_advanced.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_advanced.json @@ -1,6 +1,4 @@ { - "parent": "computercraft:block/turtle_base", - "textures": { - "texture": "computercraft:block/turtle_advanced" - } + "loader": "computercraft:turtle", + "model": "computercraft:block/turtle_advanced_base" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_advanced_base.json b/src/main/resources/assets/computercraft/models/block/turtle_advanced_base.json new file mode 100644 index 000000000..c232c67d3 --- /dev/null +++ b/src/main/resources/assets/computercraft/models/block/turtle_advanced_base.json @@ -0,0 +1,6 @@ +{ + "parent": "computercraft:block/turtle_base", + "textures": { + "texture": "computercraft:block/turtle_advanced" + } +} diff --git a/src/main/resources/assets/computercraft/models/block/turtle_elf_overlay.json b/src/main/resources/assets/computercraft/models/block/turtle_elf_overlay.json index d17e4c8ec..047576123 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_elf_overlay.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_elf_overlay.json @@ -1,5 +1,5 @@ { - "parent": "computercraft:block/turtle_normal_overlay", + "parent": "computercraft:block/turtle_overlay", "textures": { "texture": "computercraft:block/turtle_elf_overlay" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_normal.json b/src/main/resources/assets/computercraft/models/block/turtle_normal.json index 840517b05..8d58a0b14 100644 --- a/src/main/resources/assets/computercraft/models/block/turtle_normal.json +++ b/src/main/resources/assets/computercraft/models/block/turtle_normal.json @@ -1,6 +1,4 @@ { - "parent": "computercraft:block/turtle_base", - "textures": { - "texture": "computercraft:block/turtle_normal" - } + "loader": "computercraft:turtle", + "model": "computercraft:block/turtle_normal_base" } diff --git a/src/main/resources/assets/computercraft/models/block/turtle_normal_base.json b/src/main/resources/assets/computercraft/models/block/turtle_normal_base.json new file mode 100644 index 000000000..840517b05 --- /dev/null +++ b/src/main/resources/assets/computercraft/models/block/turtle_normal_base.json @@ -0,0 +1,6 @@ +{ + "parent": "computercraft:block/turtle_base", + "textures": { + "texture": "computercraft:block/turtle_normal" + } +} diff --git a/src/main/resources/assets/computercraft/models/block/turtle_normal_overlay.json b/src/main/resources/assets/computercraft/models/block/turtle_overlay.json similarity index 100% rename from src/main/resources/assets/computercraft/models/block/turtle_normal_overlay.json rename to src/main/resources/assets/computercraft/models/block/turtle_overlay.json diff --git a/src/main/resources/assets/computercraft/textures/gui/term_background.png b/src/main/resources/assets/computercraft/textures/gui/term_background.png deleted file mode 100644 index 694d2b25b96a186fffedf045db42cc4fd488de4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4kiW$h6xih%orFLI14-?iy0WWg+Z8+Vb&Z8 z1_lQ95>H=O_WL|c{Cs>yN@*z!3=C49E{-7@=ac{Z|8LK%+0fbOVz4SPDnIFfe$!`njxgN@xNAgMA!^ diff --git a/src/main/resources/assets/computercraft/textures/gui/term_font.png b/src/main/resources/assets/computercraft/textures/gui/term_font.png index ef7119bc2525bb67c86b7c11f1fbacc0f3ba2083..7bf23be2e751a8ba4dc8f408e56f0522198e6d2d 100644 GIT binary patch literal 3904 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4rT@hhU_&FAs}9Hkh>GZx^prw85kH?(j9#r z85lP9bN@+XWnf@t2=EDUWnf_V|NlS3C>RZa5g7vMWp9!}xuzt@FZln+1`NU9*;N@B z7&r?&B8wRq_zr;HW(TE$dTTWeaCAT#adW$m8#?wd7PFT_SA+r^)mamYpCz_aa& z4-&UETn=r&UOQzK!=w%Q*NprB9yQZ^m^|YeBll)jEBRY|OAP9n&RyXV-Msbngup)Y z!(YEHer@L++fa6R<9?;IfU^OH(YwVsD@86dSFL*M!M0f4;s4CWw}sQ$kD5g3O7X2$ z3cJerHh^s@!zStb=M)PIB+8GxRZ^Jt^0~Nd-1o>;Ogcuo4in}-HUG1Zfj?cG;a8L! z>jO>JZu^gi{pZH5?|*wlIs$N1BF3?Z8BGb5jV=-(H?#%s?l=GQVm{^R`Og$x#N zmK!*$2x3h`z4+lzO6 z5N^oGpLS*O{F6Us*uDFg^R4~oGtM99cX+N!whL^C-ptKVs~gl%aXYZ$)$x^SZTomF z9@zd7DwDmybKz&&KlYFNId1yRaKFAqe;Y&d#(f+0qj;8|dBtY5fhlCA^%kGfCa(M) zWd|O`Cf{Ej*U!P;HL+c+;eBbI`nSwgu{{~xHWiY8vKAx?xMW!TJ^UiRb?4;A+pb*M zBVi=J_T62rTSXm82J`+Vt}h-cOhW*p;t@U%dtI^u?Lslc7F>k`D9hZIxE_b=3 z@+frCQK3Vbiz5G=ecuqRQgQ5`K-0cyu?#;~J`&M>WPk5mcxdw}MzeF_uPmC|BTVfD z>v^+|_tsvYGI7^gk0UwF=$mTB{H7}B+~6I?cjg@3Qn_QrtasBn9BgvJ z|3A`+IwrJ|OCj$5l!^Yi$1Q{mxedBz9M!g#)^B*X;-1KCqfaZ}O1QfvAD4(WvS4nh zOJ2O}%B{Ys`|?j|tka$ONvz}9I>`wE=L{v>7vDerb<>8`VxNm|-e`edHEx`}MCt5#Pe=xH6&a2}$mKbx23Y05xt)5lRd`fu1T+@3i-}N1> zxPC)?ZtLAk>sl_&tmn{Nw^ZKrrOyM=rPc;{N6vFA#BwByIrwwRy1sJ`W-#8mI{NPH zqf8w}X^qRo4{@w^dFQOzkh-Ml+I+_Jbf+&|Jlq_6>yuWimh?!|cSxwN6d+(Py@>JO}sEbO^n{o~ayhtA94y+1=2*`4F~ zwTXv$-OerP4eva*r$)_sJ7w*=wVvU}MK@0f9dVQlZzcgeLaloH#6+fTW9WUrQN#f*U1<0EftG@ zEEL)&J!N(8^_k(>hBAe_J(z+R-Z&rK^5cN+v0rMkEOxAZsUg!8{2o7lP%r#u_Ce`R z58HRVGsA1&%5RnEvgn=PV#ipMbazF0YvYTvUDk1u%OXzLHXc)CIPzABGo)Tr?8>t9 zHCMjOV{Cc2Su^dpjbZGX<>DQ;U5zZn5~fc2Zu)NGei4QK=qU;HoKCaVBXS!~lV;NqE$5Dojd(x z3&Ve_-3;L5Vk?uyvQWOiSjcJl_4JM047PU@@`YRY9?xmH@bYWq8zzV41(S_Ke?_cK zf3e4>jB!Emj*~OBYS&ydE{RjC-_faaHcfoN{R_)YXU8(U$X>~P;r_&LVk;jrwmgn2 z6OY@ox$5WEne|gI3Ljv(n>2YHPX@of2Ip60-R~ZAc;+#@>)+k7{`WfeFUi+=6#Axj zTz>HFM(N^4nLgGHGFub{f4%YSw4N6FC)t68yVY(X0~^o%EhZ`fY`1J880JdYy?CCu z(AuD$>4Dh%#tUZr8`(t*cU9&pO#dkCLE|I=ssrOfi~vhFof z7PMuyS$w*yclX=E&+4x>@4Fl#Hjm-;Rfk2-&U`)9<1&rw!kwtSm&N91_{`7L+y9eq z$KikVXQ4%(^_n~1KJT@fb*IOf+x}MtFGG*~y2o3L_D8P&^L<&+J*JHpJtU-ipFK>z zbGvb0Kx6yz>$TH9Uw^Ph;nKzJjr%4h&v~72H|C3a!`VRnZI`N5&&?`PGf|r7{g)-i zyT#W^{N?K(Yc`6TE?ZMV?E+u6zG1rJF6gK3@?jSD+&@|8*FR^GQj|II9U95>p{5b=DYLVs!*y~f^ delta 1210 zcmX>gcb9X51Scai0|P_a9xK&}it_agoCO|{#S9F5he4R}c>anM1_lPn64!{5;QX|b z^2DN4hJwV*yb`^<)Di^~Jp(;MGndTuUl|w}*aCb)Tp1V`{{R2K^yd7#3=9m6B|(0{ z3=Yq3q%knC=y|$0hGg7(JHxR1iJM4^_6vu`gzn@fPQ8qtCO$FcGc5WUKE?GR1~S4t z?FNSv&#)XWJjf=^^*Q4I)4!~7>{iuhS8lDAd2^O6*uZB&|Mm5&S6`jfke^q9@E`D6I_s-2+mPzk+ z7_SaV*naE4%h&r#j(PF-h0gAE6RTJo`Z_FGjq}GLlg6Xj_NQKkF1oSBmO&w;agQ&r zw17h}=wVIzFFRIXz6(OG!GwIN`X!u8l06OUyqXmD&-f-P4<@pmgT?qazYF9b60- z&#V<#su0L~^NLgMJFznvwvqxrrRKVAyXf{^hg<8?omb_PLc9bIZ@V++Sy=s-jW52H zJ?Gh;DxuX764G^KgYK=fjrMYkqM3YCR_UV>RT(g_>X75RNyq=nI zdbUmq;xaT_8RWRQkgK+*H^5jcAV^7BT8A-HAUS8%fv`oFdLzUddVAbD^Bzj~*qyeW zt-+BIDDmod9#cnCYwyh)2hFB^Zd~~I`9`CQ1(*D;bSf6END+#3_3K=?o_SKp3|G}v zQHfjTNV=4s6<%2{H(hRX-JH7&4b%SW-wkHC`DWYZ?)I~ax3}n@V9S5D{n6dbTjE(t z%)7cK9@XF#Imz}}@mLJg)V3+fwH-pIZlt8K=HCo&(|C9>XMxd?@T$+UX7}R%_WoYo z{=e=y1H+yB_wUEY#>U#(*z6H0D6_5laD7ssKHr`_SHH)-9nUB z>nj{r-V*gVZ1wARyRPtauVskXRquD5d*0ujPRwt%u9ofQTVV4&AU5vGtK@7=!`mCT zURfWxQRo(PH6v5N&b+j=ZTj!trA_^w=Q-(EkeB9~TE>F%^848`$2W5Mh<@7^k;qh+ zFIN5I{-n9Sk6+!0^4gGm`pPYf`L0Hn@2My({I*TQGtJAI^U^N^WY&YW46x?FbN>{842tHG<5|5p#7ujt&&)AP@ro1L{x^Qy%*pIrOxn{G1SYMy+4YTV}^s)50) zwkAxe>3WtWctGUcQ!X3Npl5$>Y_1QUTYT=|A!BPbNoBoVFBWyfh|rhv@sAF$n16CU R#lXP8;OXk;vd$@?2>@eHEe-$x diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index c1cb9c711..94233bdfe 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,6 +1,8 @@ # New features in CC: Tweaked 1.86.2 * Fix peripheral.getMethods returning an empty table +* Update to Minecraft 1.15.2. This is currently alpha-quality and so is missing + missing features and may be unstable. # New features in CC: Tweaked 1.86.1 diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 0ded4f8d3..81c5e7ae2 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,5 +1,7 @@ New features in CC: Tweaked 1.86.2 * Fix peripheral.getMethods returning an empty table +* Update to Minecraft 1.15.2. This is currently alpha-quality and so is missing + missing features and may be unstable. Type "help changelog" to see the full version history. From 044d2b2b0641581fd662750b6a064cc5c994be66 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 28 Jan 2020 22:23:43 +0000 Subject: [PATCH 140/711] Some API cleanup - Remove *Stream methods on IMount/IWritableMount, and make the channel ones the primary. - Fix location of AbstractTurtleUpgrade - Make IComputerAccess.getAvailablePeripheral and .getMainThreadMonitor mandatory. - IComputerAccess throws a specialised NotAttachedException --- .../computercraft/api/ComputerCraftAPI.java | 25 --------- .../computercraft/api/filesystem/IMount.java | 23 ++------ .../api/filesystem/IWritableMount.java | 35 +----------- .../computercraft/api/media/IMedia.java | 2 +- .../api/peripheral/IComputerAccess.java | 44 +++++++-------- .../api/peripheral/NotAttachedException.java | 25 +++++++++ .../{ => turtle}/AbstractTurtleUpgrade.java | 4 +- .../core/apis/ComputerAccess.java | 3 +- .../core/apis/PeripheralAPI.java | 53 +++++++------------ .../core/computer/ComputerSystem.java | 18 +++++++ .../core/filesystem/ComboMount.java | 19 +------ .../core/filesystem/EmptyMount.java | 11 +--- .../core/filesystem/FileMount.java | 39 ++------------ .../core/filesystem/FileSystem.java | 8 +-- .../filesystem/FileSystemWrapperMount.java | 33 ++---------- .../core/filesystem/JarMount.java | 10 +--- .../core/filesystem/ResourceMount.java | 10 +--- .../core/filesystem/SubMount.java | 11 +--- .../modem/wired/WiredModemPeripheral.java | 2 +- .../turtle/upgrades/TurtleCraftingTable.java | 2 +- .../shared/turtle/upgrades/TurtleModem.java | 1 - .../shared/turtle/upgrades/TurtleSpeaker.java | 2 +- .../shared/turtle/upgrades/TurtleTool.java | 1 - .../core/ComputerTestDelegate.java | 2 +- .../core/filesystem/JarMountTest.java | 12 ++--- .../core/filesystem/MemoryMount.java | 25 +++++---- 26 files changed, 128 insertions(+), 292 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java rename src/main/java/dan200/computercraft/api/{ => turtle}/AbstractTurtleUpgrade.java (93%) diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 5dfd95759..4eb417e8c 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -112,31 +112,6 @@ public final class ComputerCraftAPI return getInstance().createResourceMount( domain, subPath ); } - /** - * Creates a file system mount to a resource folder, and returns it. - * - * Use in conjunction with {@link IComputerAccess#mount} or {@link IComputerAccess#mountWritable} to mount a - * resource folder onto a computer's file system. - * - * The files in this mount will be a combination of files in all mod jar, and data packs that contain - * resources with the same domain and path. - * - * @param klass The mod class to which the files belong. - * @param domain The domain under which to look for resources. eg: "mymod". - * @param subPath The subPath under which to look for resources. eg: "lua/myfiles". - * @return The mount, or {@code null} if it could be created for some reason. - * @see IComputerAccess#mount(String, IMount) - * @see IComputerAccess#mountWritable(String, IWritableMount) - * @see IMount - * @deprecated Use {@link #createResourceMount(String, String)} instead. - */ - @Nullable - @Deprecated - public static IMount createResourceMount( Class klass, @Nonnull String domain, @Nonnull String subPath ) - { - return getInstance().createResourceMount( domain, subPath ); - } - /** * Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations. * diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 41fb51b78..50682a958 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -11,8 +11,6 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import java.io.IOException; -import java.io.InputStream; -import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.List; @@ -22,10 +20,10 @@ import java.util.List; * * Ready made implementations of this interface can be created using * {@link ComputerCraftAPI#createSaveDirMount(World, String, long)} or - * {@link ComputerCraftAPI#createResourceMount(Class, String, String)}, or you're free to implement it yourselves! + * {@link ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves! * * @see ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see ComputerCraftAPI#createResourceMount(String, String) * @see IComputerAccess#mount(String, IMount) * @see IWritableMount */ @@ -67,18 +65,6 @@ public interface IMount */ long getSize( @Nonnull String path ) throws IOException; - /** - * Opens a file with a given path, and returns an {@link InputStream} representing its contents. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A stream representing the contents of the file. - * @throws IOException If the file does not exist, or could not be opened. - * @deprecated Use {@link #openChannelForRead(String)} instead - */ - @Nonnull - @Deprecated - InputStream openForRead( @Nonnull String path ) throws IOException; - /** * Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. * @@ -89,8 +75,5 @@ public interface IMount * @throws IOException If the file does not exist, or could not be opened. */ @Nonnull - default ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException - { - return Channels.newChannel( openForRead( path ) ); - } + ReadableByteChannel openForRead( @Nonnull String path ) throws IOException; } diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index a778f423d..8ec6fabc1 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -12,7 +12,6 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import java.io.IOException; import java.io.OutputStream; -import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; /** @@ -45,18 +44,6 @@ public interface IWritableMount extends IMount */ void delete( @Nonnull String path ) throws IOException; - /** - * Opens a file with a given path, and returns an {@link OutputStream} for writing to it. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A stream for writing to - * @throws IOException If the file could not be opened for writing. - * @deprecated Use {@link #openChannelForWrite(String)} instead. - */ - @Nonnull - @Deprecated - OutputStream openForWrite( @Nonnull String path ) throws IOException; - /** * Opens a file with a given path, and returns an {@link OutputStream} for writing to it. * @@ -66,22 +53,7 @@ public interface IWritableMount extends IMount * @throws IOException If the file could not be opened for writing. */ @Nonnull - default WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException - { - return Channels.newChannel( openForWrite( path ) ); - } - - /** - * Opens a file with a given path, and returns an {@link OutputStream} for appending to it. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A stream for writing to. - * @throws IOException If the file could not be opened for writing. - * @deprecated Use {@link #openChannelForAppend(String)} instead. - */ - @Nonnull - @Deprecated - OutputStream openForAppend( @Nonnull String path ) throws IOException; + WritableByteChannel openForWrite( @Nonnull String path ) throws IOException; /** * Opens a file with a given path, and returns an {@link OutputStream} for appending to it. @@ -92,10 +64,7 @@ public interface IWritableMount extends IMount * @throws IOException If the file could not be opened for writing. */ @Nonnull - default WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException - { - return Channels.newChannel( openForAppend( path ) ); - } + WritableByteChannel openForAppend( @Nonnull String path ) throws IOException; /** * Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index b841a6500..3134f5bc6 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -79,7 +79,7 @@ public interface IMedia * @see IMount * @see dan200.computercraft.api.filesystem.IWritableMount * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(String, String) */ @Nullable default IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 263f4d86b..9a6f243e9 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -14,7 +14,6 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Collections; import java.util.Map; /** @@ -31,9 +30,9 @@ public interface IComputerAccess * @param mount The mount object to mount on the computer. * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a * file in the desired location. Store this value if you wish to unmount the mount later. - * @throws RuntimeException If the peripheral has been detached. + * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount, String) * @see #mountWritable(String, IWritableMount) * @see #unmount(String) @@ -53,9 +52,9 @@ public interface IComputerAccess * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}. * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a * file in the desired location. Store this value if you wish to unmount the mount later. - * @throws RuntimeException If the peripheral has been detached. + * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount) * @see #mountWritable(String, IWritableMount) * @see #unmount(String) @@ -71,9 +70,9 @@ public interface IComputerAccess * @param mount The mount object to mount on the computer. * @return The location on the computer's file system where you the mount mounted, or null if there was already a * file in the desired location. Store this value if you wish to unmount the mount later. - * @throws RuntimeException If the peripheral has been detached. + * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount) * @see #unmount(String) * @see IMount @@ -92,9 +91,9 @@ public interface IComputerAccess * @param driveName A custom name to give for this mount location, as returned by {@code fs.getDrive()}. * @return The location on the computer's file system where you the mount mounted, or null if there was already a * file in the desired location. Store this value if you wish to unmount the mount later. - * @throws RuntimeException If the peripheral has been detached. + * @throws NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(World, String, long) - * @see ComputerCraftAPI#createResourceMount(Class, String, String) + * @see ComputerCraftAPI#createResourceMount(String, String) * @see #mount(String, IMount) * @see #unmount(String) * @see IMount @@ -114,8 +113,8 @@ public interface IComputerAccess * @param location The desired location in the computers file system of the directory to unmount. * This must be the location of a directory previously mounted by {@link #mount(String, IMount)} or * {@link #mountWritable(String, IWritableMount)}, as indicated by their return value. - * @throws RuntimeException If the peripheral has been detached. - * @throws RuntimeException If the mount does not exist, or was mounted by another peripheral. + * @throws NotAttachedException If the peripheral has been detached. + * @throws IllegalStateException If the mount does not exist, or was mounted by another peripheral. * @see #mount(String, IMount) * @see #mountWritable(String, IWritableMount) */ @@ -146,7 +145,7 @@ public interface IComputerAccess * to lua data types in the same fashion as the return values of IPeripheral.callMethod(). * * You may supply {@code null} to indicate that no arguments are to be supplied. - * @throws RuntimeException If the peripheral has been detached. + * @throws NotAttachedException If the peripheral has been detached. * @see IPeripheral#callMethod */ void queueEvent( @Nonnull String event, @Nullable Object[] arguments ); @@ -159,7 +158,7 @@ public interface IComputerAccess * which peripheral the event came. * * @return A string unique to the computer, but not globally. - * @throws RuntimeException If the peripheral has been detached. + * @throws NotAttachedException If the peripheral has been detached. */ @Nonnull String getAttachmentName(); @@ -170,14 +169,12 @@ public interface IComputerAccess * This may include other peripherals on the wired network or peripherals on other sides of the computer. * * @return All reachable peripherals + * @throws NotAttachedException If the peripheral has been detached. * @see #getAttachmentName() * @see #getAvailablePeripheral(String) */ @Nonnull - default Map getAvailablePeripherals() - { - return Collections.emptyMap(); - } + Map getAvailablePeripherals(); /** * Get a reachable peripheral with the given attachment name. This is a equivalent to @@ -188,10 +185,7 @@ public interface IComputerAccess * @see #getAvailablePeripherals() */ @Nullable - default IPeripheral getAvailablePeripheral( @Nonnull String name ) - { - return null; - } + IPeripheral getAvailablePeripheral( @Nonnull String name ); /** * Get a {@link IWorkMonitor} for tasks your peripheral might execute on the main (server) thread. @@ -205,10 +199,8 @@ public interface IComputerAccess * thread. * * @return The work monitor for the main thread, or {@code null} if this computer does not have one. + * @throws NotAttachedException If the peripheral has been detached. */ - @Nullable - default IWorkMonitor getMainThreadMonitor() - { - return null; - } + @Nonnull + IWorkMonitor getMainThreadMonitor(); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java new file mode 100644 index 000000000..08c343303 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java @@ -0,0 +1,25 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.peripheral; + +/** + * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to + * the computer. + */ +public class NotAttachedException extends IllegalStateException +{ + private static final long serialVersionUID = 1221244785535553536L; + + public NotAttachedException() + { + super( "You are not attached to this Computer" ); + } + + public NotAttachedException( String s ) + { + super( s ); + } +} diff --git a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java similarity index 93% rename from src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java rename to src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java index 94b2e701c..15bb43832 100644 --- a/src/main/java/dan200/computercraft/api/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java @@ -3,10 +3,8 @@ * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ -package dan200.computercraft.api; +package dan200.computercraft.api.turtle; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleUpgradeType; import net.minecraft.item.ItemStack; import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index ad3c24da1..019333500 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -13,7 +13,6 @@ import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.filesystem.FileSystemException; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.HashSet; import java.util.Objects; import java.util.Set; @@ -123,7 +122,7 @@ public abstract class ComputerAccess implements IComputerAccess m_environment.queueEvent( event, arguments ); } - @Nullable + @Nonnull @Override public IWorkMonitor getMainThreadMonitor() { diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index c289c85a2..81de3d594 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -11,6 +11,8 @@ import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IWorkMonitor; +import dan200.computercraft.api.peripheral.NotAttachedException; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.tracking.TrackingField; @@ -122,53 +124,35 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName ) { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } - + if( !m_attached ) throw new NotAttachedException(); return super.mount( desiredLoc, mount, driveName ); } @Override public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName ) { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } - + if( !m_attached ) throw new NotAttachedException(); return super.mountWritable( desiredLoc, mount, driveName ); } @Override public synchronized void unmount( String location ) { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } - + if( !m_attached ) throw new NotAttachedException(); super.unmount( location ); } @Override public int getID() { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } + if( !m_attached ) throw new NotAttachedException(); return super.getID(); } @Override public void queueEvent( @Nonnull final String event, final Object[] arguments ) { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } + if( !m_attached ) throw new NotAttachedException(); super.queueEvent( event, arguments ); } @@ -176,10 +160,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public String getAttachmentName() { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } + if( !m_attached ) throw new NotAttachedException(); return m_side; } @@ -187,10 +168,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public Map getAvailablePeripherals() { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } + if( !m_attached ) throw new NotAttachedException(); Map peripherals = new HashMap<>(); for( PeripheralWrapper wrapper : m_peripherals ) @@ -208,10 +186,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public IPeripheral getAvailablePeripheral( @Nonnull String name ) { - if( !m_attached ) - { - throw new RuntimeException( "You are not attached to this Computer" ); - } + if( !m_attached ) throw new NotAttachedException(); for( PeripheralWrapper wrapper : m_peripherals ) { @@ -222,6 +197,14 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange } return null; } + + @Nonnull + @Override + public IWorkMonitor getMainThreadMonitor() + { + if( !m_attached ) throw new NotAttachedException(); + return super.getMainThreadMonitor(); + } } private final IAPIEnvironment m_environment; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java index c5cb4f529..ee4917afe 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java @@ -9,12 +9,15 @@ import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.lua.IComputerSystem; import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.apis.ComputerAccess; import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.filesystem.FileSystem; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Map; /** * Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs. @@ -54,4 +57,19 @@ public class ComputerSystem extends ComputerAccess implements IComputerSystem { return environment.getLabel(); } + + @Nonnull + @Override + public Map getAvailablePeripherals() + { + // TODO: Should this return peripherals on the current computer? + return Collections.emptyMap(); + } + + @Nullable + @Override + public IPeripheral getAvailablePeripheral( @Nonnull String name ) + { + return null; + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index 53e119954..94630a90e 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -10,7 +10,6 @@ import dan200.computercraft.api.filesystem.IMount; import javax.annotation.Nonnull; import java.io.IOException; -import java.io.InputStream; import java.nio.channels.ReadableByteChannel; import java.util.ArrayList; import java.util.HashSet; @@ -115,8 +114,7 @@ public class ComboMount implements IMount @Nonnull @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { for( int i = m_parts.length - 1; i >= 0; --i ) { @@ -128,19 +126,4 @@ public class ComboMount implements IMount } throw new FileOperationException( path, "No such file" ); } - - @Nonnull - @Override - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException - { - for( int i = m_parts.length - 1; i >= 0; --i ) - { - IMount part = m_parts[i]; - if( part.exists( path ) && !part.isDirectory( path ) ) - { - return part.openChannelForRead( path ); - } - } - throw new FileOperationException( path, "No such file" ); - } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java index 15d6df7f1..3fd2dd3b9 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java @@ -10,7 +10,6 @@ import dan200.computercraft.api.filesystem.IMount; import javax.annotation.Nonnull; import java.io.IOException; -import java.io.InputStream; import java.nio.channels.ReadableByteChannel; import java.util.List; @@ -42,15 +41,7 @@ public class EmptyMount implements IMount @Nonnull @Override @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException - { - throw new FileOperationException( path, "No such file" ); - } - - @Nonnull - @Override - @Deprecated - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { throw new FileOperationException( path, "No such file" ); } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index eb0f39ff8..414fdef75 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -10,7 +10,8 @@ import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IWritableMount; import javax.annotation.Nonnull; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.file.Files; @@ -199,21 +200,7 @@ public class FileMount implements IWritableMount @Nonnull @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException - { - if( created() ) - { - File file = getRealPath( path ); - if( file.exists() && !file.isDirectory() ) return new FileInputStream( file ); - } - - throw new FileOperationException( path, "No such file" ); - } - - @Nonnull - @Override - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { if( created() ) { @@ -299,23 +286,7 @@ public class FileMount implements IWritableMount @Nonnull @Override - @Deprecated - public OutputStream openForWrite( @Nonnull String path ) throws IOException - { - return Channels.newOutputStream( openChannelForWrite( path ) ); - } - - @Nonnull - @Override - @Deprecated - public OutputStream openForAppend( @Nonnull String path ) throws IOException - { - return Channels.newOutputStream( openChannelForAppend( path ) ); - } - - @Nonnull - @Override - public WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException + public WritableByteChannel openForWrite( @Nonnull String path ) throws IOException { create(); File file = getRealPath( path ); @@ -336,7 +307,7 @@ public class FileMount implements IWritableMount @Nonnull @Override - public WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException + public WritableByteChannel openForAppend( @Nonnull String path ) throws IOException { if( !created() ) { diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 4f6f84cd3..b9819b587 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -165,7 +165,7 @@ public class FileSystem { if( m_mount.exists( path ) && !m_mount.isDirectory( path ) ) { - return m_mount.openChannelForRead( path ); + return m_mount.openForRead( path ); } else { @@ -245,7 +245,7 @@ public class FileSystem m_writableMount.makeDirectory( dir ); } } - return m_writableMount.openChannelForWrite( path ); + return m_writableMount.openForWrite( path ); } } catch( AccessDeniedException e ) @@ -275,7 +275,7 @@ public class FileSystem m_writableMount.makeDirectory( dir ); } } - return m_writableMount.openChannelForWrite( path ); + return m_writableMount.openForWrite( path ); } else if( m_mount.isDirectory( path ) ) { @@ -283,7 +283,7 @@ public class FileSystem } else { - return m_writableMount.openChannelForAppend( path ); + return m_writableMount.openForAppend( path ); } } catch( AccessDeniedException e ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java index 3b270fe1b..40e4634d8 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java @@ -9,9 +9,6 @@ import dan200.computercraft.api.filesystem.IFileSystem; import javax.annotation.Nonnull; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.Collections; @@ -55,7 +52,7 @@ public class FileSystemWrapperMount implements IFileSystem @Nonnull @Override - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { try { @@ -70,7 +67,7 @@ public class FileSystemWrapperMount implements IFileSystem @Nonnull @Override - public WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException + public WritableByteChannel openForWrite( @Nonnull String path ) throws IOException { try { @@ -84,7 +81,7 @@ public class FileSystemWrapperMount implements IFileSystem @Nonnull @Override - public WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException + public WritableByteChannel openForAppend( @Nonnull String path ) throws IOException { try { @@ -96,30 +93,6 @@ public class FileSystemWrapperMount implements IFileSystem } } - @Nonnull - @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException - { - return Channels.newInputStream( openChannelForRead( path ) ); - } - - @Nonnull - @Override - @Deprecated - public OutputStream openForWrite( @Nonnull String path ) throws IOException - { - return Channels.newOutputStream( openChannelForWrite( path ) ); - } - - @Nonnull - @Override - @Deprecated - public OutputStream openForAppend( @Nonnull String path ) throws IOException - { - return Channels.newOutputStream( openChannelForAppend( path ) ); - } - @Override public long getRemainingSpace() throws IOException { diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 336d4ddcc..874a3d536 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -181,15 +181,7 @@ public class JarMount implements IMount @Nonnull @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException - { - return Channels.newInputStream( openChannelForRead( path ) ); - } - - @Nonnull - @Override - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { FileEntry file = get( path ); if( file != null && !file.isDirectory() ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index e6116c144..fbc3a5e7d 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -223,15 +223,7 @@ public final class ResourceMount implements IMount @Nonnull @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException - { - return Channels.newInputStream( openChannelForRead( path ) ); - } - - @Nonnull - @Override - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { FileEntry file = get( path ); if( file != null && !file.isDirectory() ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java index 1cdac4a6a..e59b22878 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java @@ -9,7 +9,6 @@ import dan200.computercraft.api.filesystem.IMount; import javax.annotation.Nonnull; import java.io.IOException; -import java.io.InputStream; import java.nio.channels.ReadableByteChannel; import java.util.List; @@ -52,19 +51,11 @@ public class SubMount implements IMount @Nonnull @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) throws IOException + public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { return m_parent.openForRead( getFullPath( path ) ); } - @Nonnull - @Override - public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException - { - return m_parent.openChannelForRead( getFullPath( path ) ); - } - private String getFullPath( String path ) { if( path.isEmpty() ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 5030b9c21..88223b71d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -374,7 +374,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW m_computer.queueEvent( event, arguments ); } - @Nullable + @Nonnull @Override public IWorkMonitor getMainThreadMonitor() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 6267dff39..e5ad307b6 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -5,9 +5,9 @@ */ package dan200.computercraft.shared.turtle.upgrades; -import dan200.computercraft.api.AbstractTurtleUpgrade; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.turtle.AbstractTurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index a8bf2ca0a..ab74c7994 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.AbstractTurtleUpgrade; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 581af58b5..a06016bc0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -7,9 +7,9 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.AbstractTurtleUpgrade; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.turtle.AbstractTurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 57738a357..81d3f8e00 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.AbstractTurtleUpgrade; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.turtle.*; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 2ffc3bcd2..15b477b6a 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -86,7 +86,7 @@ public class ComputerTestDelegate for( String child : children ) mount.delete( child ); // And add our startup file - try( WritableByteChannel channel = mount.openChannelForWrite( "startup.lua" ); + try( WritableByteChannel channel = mount.openForWrite( "startup.lua" ); Writer writer = Channels.newWriter( channel, StandardCharsets.UTF_8.newEncoder(), -1 ) ) { writer.write( "loadfile('test/mcfly.lua', nil, _ENV)('test/spec') cct_test.finish()" ); diff --git a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java index 31031c96c..cf1c61529 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java @@ -13,14 +13,14 @@ import org.junit.jupiter.api.Test; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStream; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; import java.nio.charset.StandardCharsets; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.junit.jupiter.api.Assertions.*; -@SuppressWarnings( "deprecation" ) public class JarMountTest { private static final File ZIP_FILE = new File( "test-files/jar-mount.zip" ); @@ -63,9 +63,9 @@ public class JarMountTest { IMount mount = new JarMount( ZIP_FILE, "dir/file.lua" ); byte[] contents; - try( InputStream stream = mount.openForRead( "" ) ) + try( ReadableByteChannel stream = mount.openForRead( "" ) ) { - contents = ByteStreams.toByteArray( stream ); + contents = ByteStreams.toByteArray( Channels.newInputStream( stream ) ); } assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); @@ -76,9 +76,9 @@ public class JarMountTest { IMount mount = new JarMount( ZIP_FILE, "dir" ); byte[] contents; - try( InputStream stream = mount.openForRead( "file.lua" ) ) + try( ReadableByteChannel stream = mount.openForRead( "file.lua" ) ) { - contents = ByteStreams.toByteArray( stream ); + contents = ByteStreams.toByteArray( Channels.newInputStream( stream ) ); } assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); diff --git a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java index dcdc40b5e..bd16104ac 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java +++ b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java @@ -6,9 +6,15 @@ package dan200.computercraft.core.filesystem; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.core.apis.handles.ArrayByteChannel; import javax.annotation.Nonnull; -import java.io.*; +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.*; /** @@ -61,10 +67,9 @@ public class MemoryMount implements IWritableMount @Nonnull @Override - @Deprecated - public OutputStream openForWrite( @Nonnull final String path ) + public WritableByteChannel openForWrite( @Nonnull final String path ) { - return new ByteArrayOutputStream() + return Channels.newChannel( new ByteArrayOutputStream() { @Override public void close() throws IOException @@ -72,13 +77,12 @@ public class MemoryMount implements IWritableMount super.close(); files.put( path, toByteArray() ); } - }; + } ); } @Nonnull @Override - @Deprecated - public OutputStream openForAppend( @Nonnull final String path ) throws IOException + public WritableByteChannel openForAppend( @Nonnull final String path ) throws IOException { ByteArrayOutputStream stream = new ByteArrayOutputStream() { @@ -93,7 +97,7 @@ public class MemoryMount implements IWritableMount byte[] current = files.get( path ); if( current != null ) stream.write( current ); - return stream; + return Channels.newChannel( stream ); } @Override @@ -131,10 +135,9 @@ public class MemoryMount implements IWritableMount @Nonnull @Override - @Deprecated - public InputStream openForRead( @Nonnull String path ) + public ReadableByteChannel openForRead( @Nonnull String path ) { - return new ByteArrayInputStream( files.get( path ) ); + return new ArrayByteChannel( files.get( path ) ); } public MemoryMount addFile( String file, String contents ) From f3a330e33054f091ca0ef7fb2a20a392d1fcc549 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 28 Jan 2020 22:28:48 +0000 Subject: [PATCH 141/711] Normalise enums to use SHOUTY_CASE PascalCase is more .NET than Java --- .../api/turtle/TurtleAnimation.java | 34 ++++---- .../computercraft/api/turtle/TurtleSide.java | 4 +- .../api/turtle/TurtleUpgradeType.java | 10 +-- .../computercraft/api/turtle/TurtleVerb.java | 4 +- .../computercraft/client/ClientRegistry.java | 2 +- .../client/gui/FixedWidthFontRenderer.java | 4 +- .../computercraft/client/gui/GuiComputer.java | 6 +- .../computercraft/client/gui/GuiTurtle.java | 2 +- .../render/TileEntityTurtleRenderer.java | 10 +-- .../client/render/TurtleSmartItemModel.java | 10 +-- .../core/computer/ComputerExecutor.java | 4 +- .../dan200/computercraft/shared/Registry.java | 14 +-- .../shared/command/CommandComputerCraft.java | 2 +- .../computer/blocks/TileCommandComputer.java | 2 +- .../shared/computer/blocks/TileComputer.java | 4 +- .../shared/computer/core/ComputerFamily.java | 6 +- .../shared/computer/core/ServerComputer.java | 2 +- .../inventory/ContainerViewComputer.java | 2 +- .../computer/items/ComputerItemFactory.java | 6 +- .../computer/items/ItemComputerBase.java | 2 +- .../integration/jei/JEIComputerCraft.java | 4 +- .../integration/jei/RecipeResolver.java | 10 +-- .../shared/media/items/ItemDisk.java | 2 +- .../shared/media/items/ItemTreasureDisk.java | 2 +- .../shared/media/recipes/DiskRecipe.java | 4 +- .../items/PocketComputerItemFactory.java | 4 +- .../recipes/PocketComputerUpgradeRecipe.java | 2 +- .../shared/turtle/apis/TurtleAPI.java | 68 +++++++-------- .../shared/turtle/blocks/BlockTurtle.java | 2 +- .../shared/turtle/blocks/TileTurtle.java | 8 +- .../shared/turtle/core/InteractDirection.java | 12 +-- .../shared/turtle/core/MoveDirection.java | 16 ++-- .../shared/turtle/core/TurnDirection.java | 4 +- .../shared/turtle/core/TurtleBrain.java | 86 +++++++++---------- .../turtle/core/TurtleCraftCommand.java | 2 +- .../shared/turtle/core/TurtleDropCommand.java | 6 +- .../turtle/core/TurtleEquipCommand.java | 2 +- .../shared/turtle/core/TurtleMoveCommand.java | 18 ++-- .../turtle/core/TurtlePlaceCommand.java | 2 +- .../turtle/core/TurtleRefuelCommand.java | 2 +- .../shared/turtle/core/TurtleSuckCommand.java | 6 +- .../shared/turtle/core/TurtleToolCommand.java | 14 +-- .../turtle/core/TurtleTransferToCommand.java | 4 +- .../shared/turtle/core/TurtleTurnCommand.java | 8 +- .../shared/turtle/items/ItemTurtle.java | 12 +-- .../turtle/items/TurtleItemFactory.java | 8 +- .../turtle/recipes/TurtleUpgradeRecipe.java | 6 +- .../turtle/upgrades/TurtleCraftingTable.java | 4 +- .../shared/turtle/upgrades/TurtleHoe.java | 2 +- .../shared/turtle/upgrades/TurtleModem.java | 4 +- .../shared/turtle/upgrades/TurtleShovel.java | 2 +- .../shared/turtle/upgrades/TurtleSpeaker.java | 4 +- .../shared/turtle/upgrades/TurtleTool.java | 12 +-- .../computercraft/shared/util/Colour.java | 32 +++---- .../computercraft/shared/util/Holiday.java | 10 +-- .../shared/util/HolidayUtil.java | 10 +-- 56 files changed, 262 insertions(+), 262 deletions(-) diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java index 96e25074e..1e988b91c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -17,70 +17,70 @@ public enum TurtleAnimation /** * An animation which does nothing. This takes no time to complete. * - * @see #Wait - * @see #ShortWait + * @see #WAIT + * @see #SHORT_WAIT */ - None, + NONE, /** * Make the turtle move forward. Note that the animation starts from the block behind it, and * moves into this one. */ - MoveForward, + MOVE_FORWARD, /** * Make the turtle move backwards. Note that the animation starts from the block in front it, and * moves into this one. */ - MoveBack, + MOVE_BACK, /** * Make the turtle move backwards. Note that the animation starts from the block above it, and * moves into this one. */ - MoveUp, + MOVE_UP, /** * Make the turtle move backwards. Note that the animation starts from the block below it, and * moves into this one. */ - MoveDown, + MOVE_DOWN, /** * Turn the turtle to the left. Note that the animation starts with the turtle facing right, and * the turtle turns to face in the current direction. */ - TurnLeft, + TURN_LEFT, /** * Turn the turtle to the left. Note that the animation starts with the turtle facing right, and * the turtle turns to face in the current direction. */ - TurnRight, + TURN_RIGHT, /** * Swing the tool on the left. */ - SwingLeftTool, + SWING_LEFT_TOOL, /** * Swing the tool on the right. */ - SwingRightTool, + SWING_RIGHT_TOOL, /** * Wait until the animation has finished, performing no movement. * - * @see #ShortWait - * @see #None + * @see #SHORT_WAIT + * @see #NONE */ - Wait, + WAIT, /** * Wait until the animation has finished, performing no movement. This takes 4 ticks to complete. * - * @see #Wait - * @see #None + * @see #WAIT + * @see #NONE */ - ShortWait, + SHORT_WAIT, } diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java index d0a15fae1..a32f149f4 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -13,10 +13,10 @@ public enum TurtleSide /** * The turtle's left side (where the pickaxe usually is on a Wireless Mining Turtle). */ - Left, + LEFT, /** * The turtle's right side (where the modem usually is on a Wireless Mining Turtle). */ - Right, + RIGHT, } diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java index 5ba83f754..8991551aa 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -16,28 +16,28 @@ public enum TurtleUpgradeType * A tool is rendered as an item on the side of the turtle, and responds to the {@code turtle.dig()} * and {@code turtle.attack()} methods (Such as pickaxe or sword on Mining and Melee turtles). */ - Tool, + TOOL, /** * A peripheral adds a special peripheral which is attached to the side of the turtle, * and can be interacted with the {@code peripheral} API (Such as the modem on Wireless Turtles). */ - Peripheral, + PERIPHERAL, /** * An upgrade which provides both a tool and a peripheral. This can be used when you wish * your upgrade to also provide methods. For example, a pickaxe could provide methods * determining whether it can break the given block or not. */ - Both; + BOTH; public boolean isTool() { - return this == Tool || this == Both; + return this == TOOL || this == BOTH; } public boolean isPeripheral() { - return this == Peripheral || this == Both; + return this == PERIPHERAL || this == BOTH; } } diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index d3fe0af8b..7ea92e182 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -19,10 +19,10 @@ public enum TurtleVerb /** * The turtle called {@code turtle.dig()}, {@code turtle.digUp()} or {@code turtle.digDown()}. */ - Dig, + DIG, /** * The turtle called {@code turtle.attack()}, {@code turtle.attackUp()} or {@code turtle.attackDown()}. */ - Attack, + ATTACK, } diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index f1d123281..3fca61a07 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -130,7 +130,7 @@ public final class ClientRegistry case 2: // Light colour { int light = ItemPocketComputer.getLightState( stack ); - return light == -1 ? Colour.Black.getHex() : light; + return light == -1 ? Colour.BLACK.getHex() : light; } } }, ComputerCraft.Items.pocketComputerNormal, ComputerCraft.Items.pocketComputerAdvanced ); diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index b86131df3..93b8e59b9 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -270,7 +270,7 @@ public final class FixedWidthFontRenderer public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height ) { - Colour colour = Colour.Black; + Colour colour = Colour.BLACK; drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); } @@ -286,7 +286,7 @@ public final class FixedWidthFontRenderer public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height ) { - Colour colour = Colour.Black; + Colour colour = Colour.BLACK; drawQuad( transform, renderer.getBuffer( Type.BLOCKER ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 049123de7..b61cb24ff 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -137,14 +137,14 @@ public final class GuiComputer extends Containe RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); switch( m_family ) { - case Normal: + case NORMAL: default: minecraft.getTextureManager().bindTexture( BACKGROUND_NORMAL ); break; - case Advanced: + case ADVANCED: minecraft.getTextureManager().bindTexture( BACKGROUND_ADVANCED ); break; - case Command: + case COMMAND: minecraft.getTextureManager().bindTexture( BACKGROUND_COMMAND ); break; } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index a6fe9868a..7a43c7702 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -110,7 +110,7 @@ public class GuiTurtle extends ContainerScreen protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { // Draw term - boolean advanced = m_family == ComputerFamily.Advanced; + boolean advanced = m_family == ComputerFamily.ADVANCED; terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw border/inventory diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 3fce878b6..b6eb8d6a8 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -56,10 +56,10 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer { switch( family ) { - case Normal: + case NORMAL: default: return coloured ? COLOUR_TURTLE_MODEL : NORMAL_TURTLE_MODEL; - case Advanced: + case ADVANCED: return coloured ? COLOUR_TURTLE_MODEL : ADVANCED_TURTLE_MODEL; } } @@ -121,15 +121,15 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } ); // Render the overlay - ModelResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.Christmas ); + ModelResourceLocation overlayModel = getTurtleOverlayModel( overlay, HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS ); if( overlayModel != null ) { renderModel( transform, buffer, lightmapCoord, overlayLight, overlayModel, null ); } // Render the upgrades - renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.Left, partialTicks ); - renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.Right, partialTicks ); + renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks ); + renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks ); transform.pop(); } diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 4ea94b46f..14d113fbb 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -114,10 +114,10 @@ public class TurtleSmartItemModel implements IBakedModel { ItemTurtle turtle = (ItemTurtle) stack.getItem(); int colour = turtle.getColour( stack ); - ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.Left ); - ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.Right ); + ITurtleUpgrade leftUpgrade = turtle.getUpgrade( stack, TurtleSide.LEFT ); + ITurtleUpgrade rightUpgrade = turtle.getUpgrade( stack, TurtleSide.RIGHT ); ResourceLocation overlay = turtle.getOverlay( stack ); - boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.Christmas; + boolean christmas = HolidayUtil.getCurrentHoliday() == Holiday.CHRISTMAS; String label = turtle.getLabel( stack ); boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); @@ -145,8 +145,8 @@ public class TurtleSmartItemModel implements IBakedModel IBakedModel baseModel = combo.m_colour ? colourModel : familyModel; IBakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null; TransformationMatrix transform = combo.m_flip ? flip : identity; - TransformedModel leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.Left ) : null; - TransformedModel rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.Right ) : null; + TransformedModel leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.LEFT ) : null; + TransformedModel rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.RIGHT ) : null; return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel ); } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index ed182ad4c..e33089bae 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -609,7 +609,7 @@ final class ComputerExecutor terminal.reset(); // Display our primary error message - if( colour ) terminal.setTextColour( 15 - Colour.Red.ordinal() ); + if( colour ) terminal.setTextColour( 15 - Colour.RED.ordinal() ); terminal.write( message ); if( extra != null ) @@ -622,7 +622,7 @@ final class ComputerExecutor // And display our generic "CC may be installed incorrectly" message. terminal.setCursorPos( 0, terminal.getCursorY() + 1 ); - if( colour ) terminal.setTextColour( 15 - Colour.White.ordinal() ); + if( colour ) terminal.setTextColour( 15 - Colour.WHITE.ordinal() ); terminal.write( "ComputerCraft may be installed incorrectly" ); } diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index ec4cc91c6..e76c03b21 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -84,17 +84,17 @@ public final class Registry // Computers ComputerCraft.Blocks.computerNormal = new BlockComputer( Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), - ComputerFamily.Normal, TileComputer.FACTORY_NORMAL + ComputerFamily.NORMAL, TileComputer.FACTORY_NORMAL ); ComputerCraft.Blocks.computerAdvanced = new BlockComputer( Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), - ComputerFamily.Advanced, TileComputer.FACTORY_ADVANCED + ComputerFamily.ADVANCED, TileComputer.FACTORY_ADVANCED ); ComputerCraft.Blocks.computerCommand = new BlockComputer( Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ), - ComputerFamily.Command, TileCommandComputer.FACTORY + ComputerFamily.COMMAND, TileCommandComputer.FACTORY ); registry.registerAll( @@ -106,12 +106,12 @@ public final class Registry // Turtles ComputerCraft.Blocks.turtleNormal = new BlockTurtle( Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), - ComputerFamily.Normal, TileTurtle.FACTORY_NORMAL + ComputerFamily.NORMAL, TileTurtle.FACTORY_NORMAL ); ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle( Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), - ComputerFamily.Advanced, TileTurtle.FACTORY_ADVANCED + ComputerFamily.ADVANCED, TileTurtle.FACTORY_ADVANCED ); registry.registerAll( @@ -234,8 +234,8 @@ public final class Registry ); // Pocket computer - ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Normal ); - ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.Advanced ); + ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.NORMAL ); + ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.ADVANCED ); registry.registerAll( ComputerCraft.Items.pocketComputerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_normal" ) ), diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 0f6b3455f..876dcad5a 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -205,7 +205,7 @@ public final class CommandComputerCraft int queued = 0; for( ServerComputer computer : computers ) { - if( computer.getFamily() == ComputerFamily.Command && computer.isOn() ) + if( computer.getFamily() == ComputerFamily.COMMAND && computer.isOn() ) { computer.queueEvent( "computer_command", rest ); queued++; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 87f887886..8e4238627 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -32,7 +32,7 @@ public class TileCommandComputer extends TileComputer { public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ), - f -> new TileCommandComputer( ComputerFamily.Command, f ) + f -> new TileCommandComputer( ComputerFamily.COMMAND, f ) ); public class CommandReceiver implements ICommandSource diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 1a4d708b7..1ac0c94ad 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -27,12 +27,12 @@ public class TileComputer extends TileComputerBase { public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ), - f -> new TileComputer( ComputerFamily.Normal, f ) + f -> new TileComputer( ComputerFamily.NORMAL, f ) ); public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ), - f -> new TileComputer( ComputerFamily.Advanced, f ) + f -> new TileComputer( ComputerFamily.ADVANCED, f ) ); private ComputerProxy m_proxy; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java index 026a619a2..c5accf370 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java @@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.core; public enum ComputerFamily { - Normal, - Advanced, - Command + NORMAL, + ADVANCED, + COMMAND } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index a8e9c46cd..6355c1e75 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -50,7 +50,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) { - super( family != ComputerFamily.Normal, terminalWidth, terminalHeight ); + super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight ); m_instanceID = instanceID; m_world = world; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 75cceaa93..8b5132950 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -48,7 +48,7 @@ public class ContainerViewComputer extends ContainerComputerBase implements ICon } // If we're a command computer then ensure we're in creative - if( computer.getFamily() == ComputerFamily.Command ) + if( computer.getFamily() == ComputerFamily.COMMAND ) { MinecraftServer server = player.getServer(); if( server == null || !server.isCommandBlockEnabled() ) diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index aa690a58b..c3a3437c3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -29,11 +29,11 @@ public final class ComputerItemFactory { switch( family ) { - case Normal: + case NORMAL: return ComputerCraft.Items.computerNormal.create( id, label ); - case Advanced: + case ADVANCED: return ComputerCraft.Items.computerAdvanced.create( id, label ); - case Command: + case COMMAND: return ComputerCraft.Items.computerCommand.create( id, label ); default: return ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 94d539175..f93c7498a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -80,7 +80,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world ) { ComputerFamily family = getFamily(); - if( family != ComputerFamily.Command ) + if( family != ComputerFamily.COMMAND ) { int id = getComputerID( stack ); if( id >= 0 ) diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index bef51c006..d368ed7b9 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -116,8 +116,8 @@ public class JEIComputerCraft implements IModPlugin StringBuilder name = new StringBuilder(); // Add left and right upgrades to the identifier - ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.Left ); - ITurtleUpgrade right = turtle.getUpgrade( stack, TurtleSide.Right ); + ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT ); + ITurtleUpgrade right = turtle.getUpgrade( stack, TurtleSide.RIGHT ); if( left != null ) name.append( left.getUpgradeID() ); if( left != null && right != null ) name.append( '|' ); if( right != null ) name.append( right.getUpgradeID() ); diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java index b2324a8c2..31cae9c9c 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java @@ -37,7 +37,7 @@ import static net.minecraft.util.NonNullList.from; class RecipeResolver implements IRecipeManagerPlugin { - static final ComputerFamily[] MAIN_FAMILIES = new ComputerFamily[] { ComputerFamily.Normal, ComputerFamily.Advanced }; + static final ComputerFamily[] MAIN_FAMILIES = new ComputerFamily[] { ComputerFamily.NORMAL, ComputerFamily.ADVANCED }; private final Map> upgradeItemLookup = new HashMap<>(); private final List pocketUpgrades = new ArrayList<>(); @@ -150,8 +150,8 @@ class RecipeResolver implements IRecipeManagerPlugin { // Suggest possible upgrades which can be applied to this turtle ITurtleItem item = (ITurtleItem) stack.getItem(); - ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.Left ); - ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.Right ); + ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.LEFT ); + ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.RIGHT ); if( left != null && right != null ) return Collections.emptyList(); List recipes = new ArrayList<>(); @@ -231,8 +231,8 @@ class RecipeResolver implements IRecipeManagerPlugin ITurtleItem item = (ITurtleItem) stack.getItem(); List recipes = new ArrayList<>( 0 ); - ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.Left ); - ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.Right ); + ITurtleUpgrade left = item.getUpgrade( stack, TurtleSide.LEFT ); + ITurtleUpgrade right = item.getUpgrade( stack, TurtleSide.RIGHT ); // The turtle is facing towards us, so upgrades on the left are actually crafted on the right. if( left != null ) diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 0b5a203c7..0c670ed81 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -126,6 +126,6 @@ public class ItemDisk extends Item implements IMedia, IColouredItem public int getColour( @Nonnull ItemStack stack ) { int colour = IColouredItem.getColourBasic( stack ); - return colour == -1 ? Colour.White.getHex() : colour; + return colour == -1 ? Colour.WHITE.getHex() : colour; } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index e2b30ddf3..c284e7fff 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -134,6 +134,6 @@ public class ItemTreasureDisk extends Item implements IMedia public static int getColour( @Nonnull ItemStack stack ) { CompoundNBT nbt = stack.getTag(); - return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.Blue.getHex(); + return nbt != null && nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : Colour.BLUE.getHex(); } } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index d2a251910..0e5f81ab5 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -87,7 +87,7 @@ public class DiskRecipe extends SpecialRecipe } } - return ItemDisk.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.Blue.getHex() ); + return ItemDisk.createFromIDAndColour( -1, null, tracker.hasColour() ? tracker.getColour() : Colour.BLUE.getHex() ); } @Override @@ -100,7 +100,7 @@ public class DiskRecipe extends SpecialRecipe @Override public ItemStack getRecipeOutput() { - return ItemDisk.createFromIDAndColour( -1, null, Colour.Blue.getHex() ); + return ItemDisk.createFromIDAndColour( -1, null, Colour.BLUE.getHex() ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index 1bbcd4efa..5789b09c3 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -21,9 +21,9 @@ public final class PocketComputerItemFactory { switch( family ) { - case Normal: + case NORMAL: return ComputerCraft.Items.pocketComputerNormal.create( id, label, colour, upgrade ); - case Advanced: + case ADVANCED: return ComputerCraft.Items.pocketComputerAdvanced.create( id, label, colour, upgrade ); default: return ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index ed1b13b83..e2049b6f3 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -37,7 +37,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialRecipe @Override public ItemStack getRecipeOutput() { - return PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.Normal, null ); + return PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index bb43c34e1..a124d8e76 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -133,11 +133,11 @@ public class TurtleAPI implements ILuaAPI } else if( side.equalsIgnoreCase( "left" ) ) { - return TurtleSide.Left; + return TurtleSide.LEFT; } else if( side.equalsIgnoreCase( "right" ) ) { - return TurtleSide.Right; + return TurtleSide.RIGHT; } else { @@ -152,58 +152,58 @@ public class TurtleAPI implements ILuaAPI { case 0: // forward m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.Forward ) ); + return tryCommand( context, new TurtleMoveCommand( MoveDirection.FORWARD ) ); case 1: // back m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.Back ) ); + return tryCommand( context, new TurtleMoveCommand( MoveDirection.BACK ) ); case 2: // up m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.Up ) ); + return tryCommand( context, new TurtleMoveCommand( MoveDirection.UP ) ); case 3: // down m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.Down ) ); + return tryCommand( context, new TurtleMoveCommand( MoveDirection.DOWN ) ); case 4: // turnLeft m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleTurnCommand( TurnDirection.Left ) ); + return tryCommand( context, new TurtleTurnCommand( TurnDirection.LEFT ) ); case 5: // turnRight m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleTurnCommand( TurnDirection.Right ) ); + return tryCommand( context, new TurtleTurnCommand( TurnDirection.RIGHT ) ); case 6: { // dig TurtleSide side = parseSide( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.dig( InteractDirection.Forward, side ) ); + return tryCommand( context, TurtleToolCommand.dig( InteractDirection.FORWARD, side ) ); } case 7: { // digUp TurtleSide side = parseSide( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.dig( InteractDirection.Up, side ) ); + return tryCommand( context, TurtleToolCommand.dig( InteractDirection.UP, side ) ); } case 8: { // digDown TurtleSide side = parseSide( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.dig( InteractDirection.Down, side ) ); + return tryCommand( context, TurtleToolCommand.dig( InteractDirection.DOWN, side ) ); } case 9: // place m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Forward, args ) ); + return tryCommand( context, new TurtlePlaceCommand( InteractDirection.FORWARD, args ) ); case 10: // placeUp m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Up, args ) ); + return tryCommand( context, new TurtlePlaceCommand( InteractDirection.UP, args ) ); case 11: // placeDown m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtlePlaceCommand( InteractDirection.Down, args ) ); + return tryCommand( context, new TurtlePlaceCommand( InteractDirection.DOWN, args ) ); case 12: { // drop int count = parseCount( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) ); + return tryCommand( context, new TurtleDropCommand( InteractDirection.FORWARD, count ) ); } case 13: { @@ -229,72 +229,72 @@ public class TurtleAPI implements ILuaAPI return new Object[] { stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount() }; } case 16: // detect - return tryCommand( context, new TurtleDetectCommand( InteractDirection.Forward ) ); + return tryCommand( context, new TurtleDetectCommand( InteractDirection.FORWARD ) ); case 17: // detectUp - return tryCommand( context, new TurtleDetectCommand( InteractDirection.Up ) ); + return tryCommand( context, new TurtleDetectCommand( InteractDirection.UP ) ); case 18: // detectDown - return tryCommand( context, new TurtleDetectCommand( InteractDirection.Down ) ); + return tryCommand( context, new TurtleDetectCommand( InteractDirection.DOWN ) ); case 19: // compare - return tryCommand( context, new TurtleCompareCommand( InteractDirection.Forward ) ); + return tryCommand( context, new TurtleCompareCommand( InteractDirection.FORWARD ) ); case 20: // compareUp - return tryCommand( context, new TurtleCompareCommand( InteractDirection.Up ) ); + return tryCommand( context, new TurtleCompareCommand( InteractDirection.UP ) ); case 21: // compareDown - return tryCommand( context, new TurtleCompareCommand( InteractDirection.Down ) ); + return tryCommand( context, new TurtleCompareCommand( InteractDirection.DOWN ) ); case 22: { // attack TurtleSide side = parseSide( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.attack( InteractDirection.Forward, side ) ); + return tryCommand( context, TurtleToolCommand.attack( InteractDirection.FORWARD, side ) ); } case 23: { // attackUp TurtleSide side = parseSide( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.attack( InteractDirection.Up, side ) ); + return tryCommand( context, TurtleToolCommand.attack( InteractDirection.UP, side ) ); } case 24: { // attackDown TurtleSide side = parseSide( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.attack( InteractDirection.Down, side ) ); + return tryCommand( context, TurtleToolCommand.attack( InteractDirection.DOWN, side ) ); } case 25: { // dropUp int count = parseCount( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) ); + return tryCommand( context, new TurtleDropCommand( InteractDirection.UP, count ) ); } case 26: { // dropDown int count = parseCount( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) ); + return tryCommand( context, new TurtleDropCommand( InteractDirection.DOWN, count ) ); } case 27: { // suck int count = parseCount( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) ); + return tryCommand( context, new TurtleSuckCommand( InteractDirection.FORWARD, count ) ); } case 28: { // suckUp int count = parseCount( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) ); + return tryCommand( context, new TurtleSuckCommand( InteractDirection.UP, count ) ); } case 29: { // suckDown int count = parseCount( args, 0 ); m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) ); + return tryCommand( context, new TurtleSuckCommand( InteractDirection.DOWN, count ) ); } case 30: // getFuelLevel return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLevel() : "unlimited" }; @@ -324,16 +324,16 @@ public class TurtleAPI implements ILuaAPI return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLimit() : "unlimited" }; case 36: // equipLeft m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleEquipCommand( TurtleSide.Left ) ); + return tryCommand( context, new TurtleEquipCommand( TurtleSide.LEFT ) ); case 37: // equipRight m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleEquipCommand( TurtleSide.Right ) ); + return tryCommand( context, new TurtleEquipCommand( TurtleSide.RIGHT ) ); case 38: // inspect - return tryCommand( context, new TurtleInspectCommand( InteractDirection.Forward ) ); + return tryCommand( context, new TurtleInspectCommand( InteractDirection.FORWARD ) ); case 39: // inspectUp - return tryCommand( context, new TurtleInspectCommand( InteractDirection.Up ) ); + return tryCommand( context, new TurtleInspectCommand( InteractDirection.UP ) ); case 40: // inspectDown - return tryCommand( context, new TurtleInspectCommand( InteractDirection.Down ) ); + return tryCommand( context, new TurtleInspectCommand( InteractDirection.DOWN ) ); case 41: // getItemDetail { // FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...) diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index e6694d416..4db44703d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -152,7 +152,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater @Override public float getExplosionResistance( BlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion ) { - if( getFamily() == ComputerFamily.Advanced || exploder instanceof LivingEntity || exploder instanceof DamagingProjectileEntity ) + if( getFamily() == ComputerFamily.ADVANCED || exploder instanceof LivingEntity || exploder instanceof DamagingProjectileEntity ) { return 2000; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 6ac5a4864..f3a6d22e7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -57,12 +57,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), - type -> new TileTurtle( type, ComputerFamily.Normal ) + type -> new TileTurtle( type, ComputerFamily.NORMAL ) ); public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), - type -> new TileTurtle( type, ComputerFamily.Advanced ) + type -> new TileTurtle( type, ComputerFamily.ADVANCED ) ); enum MoveState @@ -526,10 +526,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default switch( side ) { case RIGHT: - upgrade = getUpgrade( TurtleSide.Right ); + upgrade = getUpgrade( TurtleSide.RIGHT ); break; case LEFT: - upgrade = getUpgrade( TurtleSide.Left ); + upgrade = getUpgrade( TurtleSide.LEFT ); break; default: return false; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java index 99cb5be31..62bf467e1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java @@ -10,20 +10,20 @@ import net.minecraft.util.Direction; public enum InteractDirection { - Forward, - Up, - Down; + FORWARD, + UP, + DOWN; public Direction toWorldDir( ITurtleAccess turtle ) { switch( this ) { - case Forward: + case FORWARD: default: return turtle.getDirection(); - case Up: + case UP: return Direction.UP; - case Down: + case DOWN: return Direction.DOWN; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java index e8d9faf65..580aacdef 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java @@ -10,23 +10,23 @@ import net.minecraft.util.Direction; public enum MoveDirection { - Forward, - Back, - Up, - Down; + FORWARD, + BACK, + UP, + DOWN; public Direction toWorldDir( ITurtleAccess turtle ) { switch( this ) { - case Forward: + case FORWARD: default: return turtle.getDirection(); - case Back: + case BACK: return turtle.getDirection().getOpposite(); - case Up: + case UP: return Direction.UP; - case Down: + case DOWN: return Direction.DOWN; } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java index 5e4085443..cebc87c2b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java @@ -7,6 +7,6 @@ package dan200.computercraft.shared.turtle.core; public enum TurnDirection { - Left, - Right, + LEFT, + RIGHT, } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 116f314d9..44ab1e5b8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -84,7 +84,7 @@ public class TurtleBrain implements ITurtleAccess private int m_colourHex = -1; private ResourceLocation m_overlay = null; - private TurtleAnimation m_animation = TurtleAnimation.None; + private TurtleAnimation m_animation = TurtleAnimation.NONE; private int m_animationProgress = 0; private int m_lastAnimationProgress = 0; @@ -166,18 +166,18 @@ public class TurtleBrain implements ITurtleAccess m_overlay = nbt.contains( NBT_OVERLAY ) ? new ResourceLocation( nbt.getString( NBT_OVERLAY ) ) : null; // Read upgrades - setUpgrade( TurtleSide.Left, nbt.contains( NBT_LEFT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_LEFT_UPGRADE ) ) : null ); - setUpgrade( TurtleSide.Right, nbt.contains( NBT_RIGHT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_RIGHT_UPGRADE ) ) : null ); + setUpgrade( TurtleSide.LEFT, nbt.contains( NBT_LEFT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_LEFT_UPGRADE ) ) : null ); + setUpgrade( TurtleSide.RIGHT, nbt.contains( NBT_RIGHT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_RIGHT_UPGRADE ) ) : null ); // NBT m_upgradeNBTData.clear(); if( nbt.contains( NBT_LEFT_UPGRADE_DATA ) ) { - m_upgradeNBTData.put( TurtleSide.Left, nbt.getCompound( NBT_LEFT_UPGRADE_DATA ).copy() ); + m_upgradeNBTData.put( TurtleSide.LEFT, nbt.getCompound( NBT_LEFT_UPGRADE_DATA ).copy() ); } if( nbt.contains( NBT_RIGHT_UPGRADE_DATA ) ) { - m_upgradeNBTData.put( TurtleSide.Right, nbt.getCompound( NBT_RIGHT_UPGRADE_DATA ).copy() ); + m_upgradeNBTData.put( TurtleSide.RIGHT, nbt.getCompound( NBT_RIGHT_UPGRADE_DATA ).copy() ); } } @@ -188,19 +188,19 @@ public class TurtleBrain implements ITurtleAccess if( m_overlay != null ) nbt.putString( NBT_OVERLAY, m_overlay.toString() ); // Write upgrades - String leftUpgradeId = getUpgradeId( getUpgrade( TurtleSide.Left ) ); + String leftUpgradeId = getUpgradeId( getUpgrade( TurtleSide.LEFT ) ); if( leftUpgradeId != null ) nbt.putString( NBT_LEFT_UPGRADE, leftUpgradeId ); - String rightUpgradeId = getUpgradeId( getUpgrade( TurtleSide.Right ) ); + String rightUpgradeId = getUpgradeId( getUpgrade( TurtleSide.RIGHT ) ); if( rightUpgradeId != null ) nbt.putString( NBT_RIGHT_UPGRADE, rightUpgradeId ); // Write upgrade NBT - if( m_upgradeNBTData.containsKey( TurtleSide.Left ) ) + if( m_upgradeNBTData.containsKey( TurtleSide.LEFT ) ) { - nbt.put( NBT_LEFT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.Left ).copy() ); + nbt.put( NBT_LEFT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.LEFT ).copy() ); } - if( m_upgradeNBTData.containsKey( TurtleSide.Right ) ) + if( m_upgradeNBTData.containsKey( TurtleSide.RIGHT ) ) { - nbt.put( NBT_RIGHT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.Right ).copy() ); + nbt.put( NBT_RIGHT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.RIGHT ).copy() ); } } @@ -259,9 +259,9 @@ public class TurtleBrain implements ITurtleAccess // Animation TurtleAnimation anim = TurtleAnimation.values()[nbt.getInt( "Animation" )]; if( anim != m_animation && - anim != TurtleAnimation.Wait && - anim != TurtleAnimation.ShortWait && - anim != TurtleAnimation.None ) + anim != TurtleAnimation.WAIT && + anim != TurtleAnimation.SHORT_WAIT && + anim != TurtleAnimation.NONE ) { m_animation = anim; m_animationProgress = 0; @@ -385,7 +385,7 @@ public class TurtleBrain implements ITurtleAccess float yaw = getDirection().getHorizontalAngle(); switch( m_animation ) { - case TurnLeft: + case TURN_LEFT: { yaw += 90.0f * (1.0f - getAnimationFraction( f )); if( yaw >= 360.0f ) @@ -394,7 +394,7 @@ public class TurtleBrain implements ITurtleAccess } break; } - case TurnRight: + case TURN_RIGHT: { yaw += -90.0f * (1.0f - getAnimationFraction( f )); if( yaw < 0.0f ) @@ -474,7 +474,7 @@ public class TurtleBrain implements ITurtleAccess @Override public int getFuelLimit() { - if( m_owner.getFamily() == ComputerFamily.Advanced ) + if( m_owner.getFamily() == ComputerFamily.ADVANCED ) { return ComputerCraft.advancedTurtleFuelLimit; } @@ -546,7 +546,7 @@ public class TurtleBrain implements ITurtleAccess if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot play animations on the client" ); m_animation = animation; - if( m_animation == TurtleAnimation.ShortWait ) + if( m_animation == TurtleAnimation.SHORT_WAIT ) { m_animationProgress = ANIM_DURATION / 2; m_lastAnimationProgress = ANIM_DURATION / 2; @@ -688,26 +688,26 @@ public class TurtleBrain implements ITurtleAccess { switch( m_animation ) { - case MoveForward: - case MoveBack: - case MoveUp: - case MoveDown: + case MOVE_FORWARD: + case MOVE_BACK: + case MOVE_UP: + case MOVE_DOWN: { // Get direction Direction dir; switch( m_animation ) { - case MoveForward: + case MOVE_FORWARD: default: dir = getDirection(); break; - case MoveBack: + case MOVE_BACK: dir = getDirection().getOpposite(); break; - case MoveUp: + case MOVE_UP: dir = Direction.UP; break; - case MoveDown: + case MOVE_DOWN: dir = Direction.DOWN; break; } @@ -728,8 +728,8 @@ public class TurtleBrain implements ITurtleAccess public float getToolRenderAngle( TurtleSide side, float f ) { - return (side == TurtleSide.Left && m_animation == TurtleAnimation.SwingLeftTool) || - (side == TurtleSide.Right && m_animation == TurtleAnimation.SwingRightTool) + return (side == TurtleSide.LEFT && m_animation == TurtleAnimation.SWING_LEFT_TOOL) || + (side == TurtleSide.RIGHT && m_animation == TurtleAnimation.SWING_RIGHT_TOOL) ? 45.0f * (float) Math.sin( getAnimationFraction( f ) * Math.PI ) : 0.0f; } @@ -738,9 +738,9 @@ public class TurtleBrain implements ITurtleAccess { switch( side ) { - case Left: + case LEFT: return ComputerSide.LEFT; - case Right: + case RIGHT: default: return ComputerSide.RIGHT; } @@ -779,7 +779,7 @@ public class TurtleBrain implements ITurtleAccess private void updateCommands() { - if( m_animation != TurtleAnimation.None || m_commandQueue.isEmpty() ) return; + if( m_animation != TurtleAnimation.NONE || m_commandQueue.isEmpty() ) return; // If we've got a computer, ensure that we're allowed to perform work. ServerComputer computer = m_owner.getServerComputer(); @@ -828,33 +828,33 @@ public class TurtleBrain implements ITurtleAccess private void updateAnimation() { - if( m_animation != TurtleAnimation.None ) + if( m_animation != TurtleAnimation.NONE ) { World world = getWorld(); if( ComputerCraft.turtlesCanPush ) { // Advance entity pushing - if( m_animation == TurtleAnimation.MoveForward || - m_animation == TurtleAnimation.MoveBack || - m_animation == TurtleAnimation.MoveUp || - m_animation == TurtleAnimation.MoveDown ) + if( m_animation == TurtleAnimation.MOVE_FORWARD || + m_animation == TurtleAnimation.MOVE_BACK || + m_animation == TurtleAnimation.MOVE_UP || + m_animation == TurtleAnimation.MOVE_DOWN ) { BlockPos pos = getPosition(); Direction moveDir; switch( m_animation ) { - case MoveForward: + case MOVE_FORWARD: default: moveDir = getDirection(); break; - case MoveBack: + case MOVE_BACK: moveDir = getDirection().getOpposite(); break; - case MoveUp: + case MOVE_UP: moveDir = Direction.UP; break; - case MoveDown: + case MOVE_DOWN: moveDir = Direction.DOWN; break; } @@ -912,11 +912,11 @@ public class TurtleBrain implements ITurtleAccess } // Advance valentines day easter egg - if( world.isRemote && m_animation == TurtleAnimation.MoveForward && m_animationProgress == 4 ) + if( world.isRemote && m_animation == TurtleAnimation.MOVE_FORWARD && m_animationProgress == 4 ) { // Spawn love pfx if valentines day Holiday currentHoliday = HolidayUtil.getCurrentHoliday(); - if( currentHoliday == Holiday.Valentines ) + if( currentHoliday == Holiday.VALENTINES ) { Vec3d position = getVisualPosition( 1.0f ); if( position != null ) @@ -938,7 +938,7 @@ public class TurtleBrain implements ITurtleAccess m_lastAnimationProgress = m_animationProgress; if( ++m_animationProgress >= ANIM_DURATION ) { - m_animation = TurtleAnimation.None; + m_animation = TurtleAnimation.NONE; m_animationProgress = 0; m_lastAnimationProgress = 0; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java index 98191656b..5d2ed6597 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -45,7 +45,7 @@ public class TurtleCraftCommand implements ITurtleCommand } } - if( !results.isEmpty() ) turtle.playAnimation( TurtleAnimation.Wait ); + if( !results.isEmpty() ) turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index 959839450..e09b6fe92 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -39,7 +39,7 @@ public class TurtleDropCommand implements ITurtleCommand // Dropping nothing is easy if( m_quantity == 0 ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } @@ -83,7 +83,7 @@ public class TurtleDropCommand implements ITurtleCommand // Return true if we stored anything if( remainder != stack ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } else @@ -96,7 +96,7 @@ public class TurtleDropCommand implements ITurtleCommand // Drop the item into the world WorldUtil.dropItemStack( stack, world, oldPosition, direction ); world.playBroadcastSound( 1000, newPosition, 0 ); - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index 0df332ff7..7c4990f35 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -92,7 +92,7 @@ public class TurtleEquipCommand implements ITurtleCommand // Animate if( newUpgrade != null || oldUpgrade != null ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); } return TurtleCommandResult.success(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 559721404..0e2d896cc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -72,7 +72,7 @@ public class TurtleMoveCommand implements ITurtleCommand if( !oldWorld.checkNoEntityCollision( null, collision ) ) { - if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.Up || m_direction == MoveDirection.Down ) + if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.UP || m_direction == MoveDirection.DOWN ) { return TurtleCommandResult.failure( "Movement obstructed" ); } @@ -114,18 +114,18 @@ public class TurtleMoveCommand implements ITurtleCommand // Animate switch( m_direction ) { - case Forward: + case FORWARD: default: - turtle.playAnimation( TurtleAnimation.MoveForward ); + turtle.playAnimation( TurtleAnimation.MOVE_FORWARD ); break; - case Back: - turtle.playAnimation( TurtleAnimation.MoveBack ); + case BACK: + turtle.playAnimation( TurtleAnimation.MOVE_BACK ); break; - case Up: - turtle.playAnimation( TurtleAnimation.MoveUp ); + case UP: + turtle.playAnimation( TurtleAnimation.MOVE_UP ); break; - case Down: - turtle.playAnimation( TurtleAnimation.MoveDown ); + case DOWN: + turtle.playAnimation( TurtleAnimation.MOVE_DOWN ); break; } return TurtleCommandResult.success(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index d00096461..84dc412fb 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -86,7 +86,7 @@ public class TurtlePlaceCommand implements ITurtleCommand turtle.getInventory().markDirty(); // Animate and return success - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } else diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index 4669f89a1..3eb9b8880 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -39,7 +39,7 @@ public class TurtleRefuelCommand implements ITurtleCommand if( limit != 0 ) { turtle.addFuel( event.getHandler().refuel( turtle, stack, slot, limit ) ); - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); } return TurtleCommandResult.success(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index 7270bac1c..d23b10e98 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -42,7 +42,7 @@ public class TurtleSuckCommand implements ITurtleCommand // Sucking nothing is easy if( m_quantity == 0 ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } @@ -82,7 +82,7 @@ public class TurtleSuckCommand implements ITurtleCommand // Return true if we consumed anything if( remainder != stack ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } else @@ -142,7 +142,7 @@ public class TurtleSuckCommand implements ITurtleCommand // Play fx world.playBroadcastSound( 1000, turtlePosition, 0 ); // BLOCK_DISPENSER_DISPENSE - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java index 5f8f9f13e..9575090e8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java @@ -41,14 +41,14 @@ public class TurtleToolCommand implements ITurtleCommand { switch( side ) { - case Left: - turtle.playAnimation( TurtleAnimation.SwingLeftTool ); + case LEFT: + turtle.playAnimation( TurtleAnimation.SWING_LEFT_TOOL ); break; - case Right: - turtle.playAnimation( TurtleAnimation.SwingRightTool ); + case RIGHT: + turtle.playAnimation( TurtleAnimation.SWING_RIGHT_TOOL ); break; default: - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); break; } return result; @@ -64,11 +64,11 @@ public class TurtleToolCommand implements ITurtleCommand public static TurtleToolCommand attack( InteractDirection direction, @Nullable TurtleSide side ) { - return new TurtleToolCommand( TurtleVerb.Attack, direction, side ); + return new TurtleToolCommand( TurtleVerb.ATTACK, direction, side ); } public static TurtleToolCommand dig( InteractDirection direction, @Nullable TurtleSide side ) { - return new TurtleToolCommand( TurtleVerb.Dig, direction, side ); + return new TurtleToolCommand( TurtleVerb.DIG, direction, side ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index 803365202..a1b7a9e7a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -33,7 +33,7 @@ public class TurtleTransferToCommand implements ITurtleCommand ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); if( stack.isEmpty() ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } @@ -48,7 +48,7 @@ public class TurtleTransferToCommand implements ITurtleCommand // Return true if we moved anything if( remainder != stack ) { - turtle.playAnimation( TurtleAnimation.Wait ); + turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } else diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java index 95cb681c2..5272af775 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -36,16 +36,16 @@ public class TurtleTurnCommand implements ITurtleCommand switch( m_direction ) { - case Left: + case LEFT: { turtle.setDirection( turtle.getDirection().rotateYCCW() ); - turtle.playAnimation( TurtleAnimation.TurnLeft ); + turtle.playAnimation( TurtleAnimation.TURN_LEFT ); return TurtleCommandResult.success(); } - case Right: + case RIGHT: { turtle.setDirection( turtle.getDirection().rotateY() ); - turtle.playAnimation( TurtleAnimation.TurnRight ); + turtle.playAnimation( TurtleAnimation.TURN_RIGHT ); return TurtleCommandResult.success(); } default: diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index 557234ed1..de0bfec1a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -76,8 +76,8 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem public ITextComponent getDisplayName( @Nonnull ItemStack stack ) { String baseString = getTranslationKey( stack ); - ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left ); - ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); + ITurtleUpgrade left = getUpgrade( stack, TurtleSide.LEFT ); + ITurtleUpgrade right = getUpgrade( stack, TurtleSide.RIGHT ); if( left != null && right != null ) { return new TranslationTextComponent( baseString + ".upgraded_twice", @@ -110,14 +110,14 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem // Determine our "creator mod" from the upgrades. We attempt to find the first non-vanilla/non-CC // upgrade (starting from the left). - ITurtleUpgrade left = getUpgrade( stack, TurtleSide.Left ); + ITurtleUpgrade left = getUpgrade( stack, TurtleSide.LEFT ); if( left != null ) { String mod = TurtleUpgrades.getOwner( left ); if( mod != null && !mod.equals( ComputerCraft.MOD_ID ) ) return mod; } - ITurtleUpgrade right = getUpgrade( stack, TurtleSide.Right ); + ITurtleUpgrade right = getUpgrade( stack, TurtleSide.RIGHT ); if( right != null ) { String mod = TurtleUpgrades.getOwner( right ); @@ -133,7 +133,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem return TurtleItemFactory.create( getComputerID( stack ), getLabel( stack ), getColour( stack ), family, - getUpgrade( stack, TurtleSide.Left ), getUpgrade( stack, TurtleSide.Right ), + getUpgrade( stack, TurtleSide.LEFT ), getUpgrade( stack, TurtleSide.RIGHT ), getFuelLevel( stack ), getOverlay( stack ) ); } @@ -144,7 +144,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem CompoundNBT tag = stack.getTag(); if( tag == null ) return null; - String key = side == TurtleSide.Left ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE; + String key = side == TurtleSide.LEFT ? NBT_LEFT_UPGRADE : NBT_RIGHT_UPGRADE; return tag.contains( key ) ? TurtleUpgrades.get( tag.getString( key ) ) : null; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index 3212a14f8..470668890 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -22,8 +22,8 @@ public final class TurtleItemFactory @Nonnull public static ItemStack create( ITurtleTile turtle ) { - ITurtleUpgrade leftUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Left ); - ITurtleUpgrade rightUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Right ); + ITurtleUpgrade leftUpgrade = turtle.getAccess().getUpgrade( TurtleSide.LEFT ); + ITurtleUpgrade rightUpgrade = turtle.getAccess().getUpgrade( TurtleSide.RIGHT ); String label = turtle.getLabel(); if( label == null ) @@ -41,9 +41,9 @@ public final class TurtleItemFactory { switch( family ) { - case Normal: + case NORMAL: return ComputerCraft.Items.turtleNormal.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); - case Advanced: + case ADVANCED: return ComputerCraft.Items.turtleAdvanced.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); default: return ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index 164c911d8..010924cb8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -38,7 +38,7 @@ public final class TurtleUpgradeRecipe extends SpecialRecipe @Override public ItemStack getRecipeOutput() { - return TurtleItemFactory.create( -1, null, -1, ComputerFamily.Normal, null, null, 0, null ); + return TurtleItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null, null, 0, null ); } @Override @@ -142,8 +142,8 @@ public final class TurtleUpgradeRecipe extends SpecialRecipe ITurtleItem itemTurtle = (ITurtleItem) turtle.getItem(); ComputerFamily family = itemTurtle.getFamily(); ITurtleUpgrade[] upgrades = new ITurtleUpgrade[] { - itemTurtle.getUpgrade( turtle, TurtleSide.Left ), - itemTurtle.getUpgrade( turtle, TurtleSide.Right ), + itemTurtle.getUpgrade( turtle, TurtleSide.LEFT ), + itemTurtle.getUpgrade( turtle, TurtleSide.RIGHT ), }; // Get the upgrades for the new items diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index e5ad307b6..5182c01ee 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -29,7 +29,7 @@ public class TurtleCraftingTable extends AbstractTurtleUpgrade public TurtleCraftingTable( ResourceLocation id ) { - super( id, TurtleUpgradeType.Peripheral, Blocks.CRAFTING_TABLE ); + super( id, TurtleUpgradeType.PERIPHERAL, Blocks.CRAFTING_TABLE ); } @Override @@ -54,6 +54,6 @@ public class TurtleCraftingTable extends AbstractTurtleUpgrade public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); - return TransformedModel.of( side == TurtleSide.Left ? m_leftModel : m_rightModel ); + return TransformedModel.of( side == TurtleSide.LEFT ? m_leftModel : m_rightModel ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index 2c9f6fb38..4c4b341e9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -57,7 +57,7 @@ public class TurtleHoe extends TurtleTool @Override public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) { - if( verb == TurtleVerb.Dig ) + if( verb == TurtleVerb.DIG ) { ItemStack hoe = item.copy(); ItemStack remainder = TurtlePlaceCommand.deploy( hoe, turtle, direction, null, null ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index ab74c7994..15aae7ceb 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -78,7 +78,7 @@ public class TurtleModem extends AbstractTurtleUpgrade public TurtleModem( boolean advanced, ResourceLocation id ) { super( - id, TurtleUpgradeType.Peripheral, + id, TurtleUpgradeType.PERIPHERAL, advanced ? ComputerCraft.Blocks.wirelessModemAdvanced : ComputerCraft.Blocks.wirelessModemNormal @@ -135,7 +135,7 @@ public class TurtleModem extends AbstractTurtleUpgrade active = turtleNBT.contains( "active" ) && turtleNBT.getBoolean( "active" ); } - return side == TurtleSide.Left + return side == TurtleSide.LEFT ? TransformedModel.of( active ? m_leftOnModel : m_leftOffModel ) : TransformedModel.of( active ? m_rightOnModel : m_rightOffModel ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index 939da778e..1cbe660f1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -61,7 +61,7 @@ public class TurtleShovel extends TurtleTool @Override public TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) { - if( verb == TurtleVerb.Dig ) + if( verb == TurtleVerb.DIG ) { ItemStack shovel = item.copy(); ItemStack remainder = TurtlePlaceCommand.deploy( shovel, turtle, direction, null, null ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index a06016bc0..35bd70886 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -63,7 +63,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade public TurtleSpeaker( ResourceLocation id ) { - super( id, TurtleUpgradeType.Peripheral, ComputerCraft.Blocks.speaker ); + super( id, TurtleUpgradeType.PERIPHERAL, ComputerCraft.Blocks.speaker ); } @Override @@ -88,7 +88,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { loadModelLocations(); - return TransformedModel.of( side == TurtleSide.Left ? m_leftModel : m_rightModel ); + return TransformedModel.of( side == TurtleSide.LEFT ? m_leftModel : m_rightModel ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 81d3f8e00..e3ddec335 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -51,19 +51,19 @@ public class TurtleTool extends AbstractTurtleUpgrade public TurtleTool( ResourceLocation id, String adjective, Item item ) { - super( id, TurtleUpgradeType.Tool, adjective, item ); + super( id, TurtleUpgradeType.TOOL, adjective, item ); this.item = new ItemStack( item ); } public TurtleTool( ResourceLocation id, Item item ) { - super( id, TurtleUpgradeType.Tool, item ); + super( id, TurtleUpgradeType.TOOL, item ); this.item = new ItemStack( item ); } public TurtleTool( ResourceLocation id, ItemStack craftItem, ItemStack toolItem ) { - super( id, TurtleUpgradeType.Tool, craftItem ); + super( id, TurtleUpgradeType.TOOL, craftItem ); this.item = toolItem; } @@ -72,7 +72,7 @@ public class TurtleTool extends AbstractTurtleUpgrade @OnlyIn( Dist.CLIENT ) public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { - float xOffset = side == TurtleSide.Left ? -0.40625f : 0.40625f; + float xOffset = side == TurtleSide.LEFT ? -0.40625f : 0.40625f; Matrix4f transform = new Matrix4f( new float[] { 0.0f, 0.0f, -1.0f, 1.0f + xOffset, 1.0f, 0.0f, 0.0f, 0.0f, @@ -88,9 +88,9 @@ public class TurtleTool extends AbstractTurtleUpgrade { switch( verb ) { - case Attack: + case ATTACK: return attack( turtle, direction, side ); - case Dig: + case DIG: return dig( turtle, direction, side ); default: return TurtleCommandResult.failure( "Unsupported action" ); diff --git a/src/main/java/dan200/computercraft/shared/util/Colour.java b/src/main/java/dan200/computercraft/shared/util/Colour.java index 010d1152b..5c9e6b86d 100644 --- a/src/main/java/dan200/computercraft/shared/util/Colour.java +++ b/src/main/java/dan200/computercraft/shared/util/Colour.java @@ -7,22 +7,22 @@ package dan200.computercraft.shared.util; public enum Colour { - Black( 0x111111 ), - Red( 0xcc4c4c ), - Green( 0x57A64E ), - Brown( 0x7f664c ), - Blue( 0x3366cc ), - Purple( 0xb266e5 ), - Cyan( 0x4c99b2 ), - LightGrey( 0x999999 ), - Grey( 0x4c4c4c ), - Pink( 0xf2b2cc ), - Lime( 0x7fcc19 ), - Yellow( 0xdede6c ), - LightBlue( 0x99b2f2 ), - Magenta( 0xe57fd8 ), - Orange( 0xf2b233 ), - White( 0xf0f0f0 ); + BLACK( 0x111111 ), + RED( 0xcc4c4c ), + GREEN( 0x57A64E ), + BROWN( 0x7f664c ), + BLUE( 0x3366cc ), + PURPLE( 0xb266e5 ), + CYAN( 0x4c99b2 ), + LIGHT_GREY( 0x999999 ), + GREY( 0x4c4c4c ), + PINK( 0xf2b2cc ), + LIME( 0x7fcc19 ), + YELLOW( 0xdede6c ), + LIGHT_BLUE( 0x99b2f2 ), + MAGENTA( 0xe57fd8 ), + ORANGE( 0xf2b233 ), + WHITE( 0xf0f0f0 ); public static final Colour[] VALUES = values(); diff --git a/src/main/java/dan200/computercraft/shared/util/Holiday.java b/src/main/java/dan200/computercraft/shared/util/Holiday.java index d50d8422b..b4728d46c 100644 --- a/src/main/java/dan200/computercraft/shared/util/Holiday.java +++ b/src/main/java/dan200/computercraft/shared/util/Holiday.java @@ -7,9 +7,9 @@ package dan200.computercraft.shared.util; public enum Holiday { - None, - Valentines, - AprilFoolsDay, - Halloween, - Christmas, + NONE, + VALENTINES, + APRIL_FOOLS_DAY, + HALLOWEEN, + CHRISTMAS, } diff --git a/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java b/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java index 7abc26976..ea9e5dd74 100644 --- a/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java @@ -20,10 +20,10 @@ public final class HolidayUtil { int month = calendar.get( Calendar.MONTH ); int day = calendar.get( Calendar.DAY_OF_MONTH ); - if( month == Calendar.FEBRUARY && day == 14 ) return Holiday.Valentines; - if( month == Calendar.APRIL && day == 1 ) return Holiday.AprilFoolsDay; - if( month == Calendar.OCTOBER && day == 31 ) return Holiday.Halloween; - if( month == Calendar.DECEMBER && day >= 24 && day <= 30 ) return Holiday.Christmas; - return Holiday.None; + if( month == Calendar.FEBRUARY && day == 14 ) return Holiday.VALENTINES; + if( month == Calendar.APRIL && day == 1 ) return Holiday.APRIL_FOOLS_DAY; + if( month == Calendar.OCTOBER && day == 31 ) return Holiday.HALLOWEEN; + if( month == Calendar.DECEMBER && day >= 24 && day <= 30 ) return Holiday.CHRISTMAS; + return Holiday.NONE; } } From d6ea3aab1c383b6f9ac8b420dcd1cf435cddb9e8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 29 Jan 2020 16:41:26 +0000 Subject: [PATCH 142/711] Switch generation of resources over to data generators See #354 - Remove Lua script to generate recipes/advancements for coloured disks, turtle upgrades and pocket upgrades. Replacing them with Lua ones. - Generate most block drops via the data generator system. Aside from cables, they all follow one of two templates. --- .gitattributes | 2 + .gitignore | 2 + build.gradle | 17 +++ .../recipes/computercraft/disk_1.json | 32 ++++ .../recipes/computercraft/disk_10.json | 32 ++++ .../recipes/computercraft/disk_11.json | 32 ++++ .../recipes/computercraft/disk_12.json | 32 ++++ .../recipes/computercraft/disk_13.json | 32 ++++ .../recipes/computercraft/disk_14.json | 32 ++++ .../recipes/computercraft/disk_15.json | 32 ++++ .../recipes/computercraft/disk_16.json | 32 ++++ .../recipes/computercraft/disk_2.json | 32 ++++ .../recipes/computercraft/disk_3.json | 32 ++++ .../recipes/computercraft/disk_4.json | 32 ++++ .../recipes/computercraft/disk_5.json | 32 ++++ .../recipes/computercraft/disk_6.json | 32 ++++ .../recipes/computercraft/disk_7.json | 32 ++++ .../recipes/computercraft/disk_8.json | 32 ++++ .../recipes/computercraft/disk_9.json | 32 ++++ .../computercraft/speaker.json | 35 +++++ .../wireless_modem_advanced.json | 35 +++++ .../computercraft/wireless_modem_normal.json | 35 +++++ .../minecraft/crafting_table.json | 35 +++++ .../minecraft/diamond_axe.json | 35 +++++ .../minecraft/diamond_hoe.json | 35 +++++ .../minecraft/diamond_pickaxe.json | 35 +++++ .../minecraft/diamond_shovel.json | 35 +++++ .../minecraft/diamond_sword.json | 35 +++++ .../pocket_normal/computercraft/speaker.json | 35 +++++ .../wireless_modem_advanced.json | 35 +++++ .../computercraft/wireless_modem_normal.json | 35 +++++ .../minecraft/crafting_table.json | 35 +++++ .../pocket_normal/minecraft/diamond_axe.json | 35 +++++ .../pocket_normal/minecraft/diamond_hoe.json | 35 +++++ .../minecraft/diamond_pickaxe.json | 35 +++++ .../minecraft/diamond_shovel.json | 35 +++++ .../minecraft/diamond_sword.json | 35 +++++ .../computercraft/speaker.json | 35 +++++ .../wireless_modem_advanced.json | 35 +++++ .../computercraft/wireless_modem_normal.json | 35 +++++ .../minecraft/crafting_table.json | 35 +++++ .../minecraft/diamond_axe.json | 35 +++++ .../minecraft/diamond_hoe.json | 35 +++++ .../minecraft/diamond_pickaxe.json | 35 +++++ .../minecraft/diamond_shovel.json | 35 +++++ .../minecraft/diamond_sword.json | 35 +++++ .../turtle_normal/computercraft/speaker.json | 35 +++++ .../wireless_modem_advanced.json | 35 +++++ .../computercraft/wireless_modem_normal.json | 35 +++++ .../minecraft/crafting_table.json | 35 +++++ .../turtle_normal/minecraft/diamond_axe.json | 35 +++++ .../turtle_normal/minecraft/diamond_hoe.json | 35 +++++ .../minecraft/diamond_pickaxe.json | 35 +++++ .../minecraft/diamond_shovel.json | 35 +++++ .../minecraft/diamond_sword.json | 35 +++++ .../loot_tables/computer_advanced.json | 30 ++++ .../loot_tables/computer_normal.json | 30 ++++ .../computercraft/loot_tables/disk_drive.json | 19 +++ .../loot_tables/monitor_advanced.json | 19 +++ .../loot_tables/monitor_normal.json | 19 +++ .../computercraft/loot_tables/printer.json | 19 +++ .../computercraft/loot_tables/speaker.json | 19 +++ .../loot_tables/turtle_advanced.json | 30 ++++ .../loot_tables/turtle_normal.json | 30 ++++ .../loot_tables/wired_modem_full.json | 19 +++ .../loot_tables/wireless_modem_advanced.json | 19 +++ .../loot_tables/wireless_modem_normal.json | 19 +++ .../data/computercraft/recipes/disk_1.json | 19 +++ .../data/computercraft/recipes/disk_10.json | 19 +++ .../data/computercraft/recipes/disk_11.json | 19 +++ .../data/computercraft/recipes/disk_12.json | 19 +++ .../data/computercraft/recipes/disk_13.json | 19 +++ .../data/computercraft/recipes/disk_14.json | 19 +++ .../data/computercraft/recipes/disk_15.json | 19 +++ .../data/computercraft/recipes/disk_16.json | 19 +++ .../data/computercraft/recipes/disk_2.json | 19 +++ .../data/computercraft/recipes/disk_3.json | 19 +++ .../data/computercraft/recipes/disk_4.json | 19 +++ .../data/computercraft/recipes/disk_5.json | 19 +++ .../data/computercraft/recipes/disk_6.json | 19 +++ .../data/computercraft/recipes/disk_7.json | 19 +++ .../data/computercraft/recipes/disk_8.json | 19 +++ .../data/computercraft/recipes/disk_9.json | 19 +++ .../computercraft/speaker.json | 19 +++ .../wireless_modem_advanced.json | 19 +++ .../computercraft/wireless_modem_normal.json | 19 +++ .../minecraft/crafting_table.json | 19 +++ .../minecraft/diamond_axe.json | 19 +++ .../minecraft/diamond_hoe.json | 19 +++ .../minecraft/diamond_pickaxe.json | 19 +++ .../minecraft/diamond_shovel.json | 19 +++ .../minecraft/diamond_sword.json | 19 +++ .../pocket_normal/computercraft/speaker.json | 19 +++ .../wireless_modem_advanced.json | 19 +++ .../computercraft/wireless_modem_normal.json | 19 +++ .../minecraft/crafting_table.json | 19 +++ .../pocket_normal/minecraft/diamond_axe.json | 19 +++ .../pocket_normal/minecraft/diamond_hoe.json | 19 +++ .../minecraft/diamond_pickaxe.json | 19 +++ .../minecraft/diamond_shovel.json | 19 +++ .../minecraft/diamond_sword.json | 19 +++ .../computercraft/speaker.json | 19 +++ .../wireless_modem_advanced.json | 19 +++ .../computercraft/wireless_modem_normal.json | 19 +++ .../minecraft/crafting_table.json | 19 +++ .../minecraft/diamond_axe.json | 19 +++ .../minecraft/diamond_hoe.json | 19 +++ .../minecraft/diamond_pickaxe.json | 19 +++ .../minecraft/diamond_shovel.json | 19 +++ .../minecraft/diamond_sword.json | 19 +++ .../turtle_normal/computercraft/speaker.json | 19 +++ .../wireless_modem_advanced.json | 19 +++ .../computercraft/wireless_modem_normal.json | 19 +++ .../minecraft/crafting_table.json | 19 +++ .../turtle_normal/minecraft/diamond_axe.json | 19 +++ .../turtle_normal/minecraft/diamond_hoe.json | 19 +++ .../minecraft/diamond_pickaxe.json | 19 +++ .../minecraft/diamond_shovel.json | 19 +++ .../minecraft/diamond_sword.json | 19 +++ .../dan200/computercraft/data/Generators.java | 27 ++++ .../computercraft/data/LootTableProvider.java | 91 +++++++++++ .../dan200/computercraft/data/LootTables.java | 72 +++++++++ .../computercraft/data/RecipeWrapper.java | 92 ++++++++++++ .../dan200/computercraft/data/Recipes.java | 141 ++++++++++++++++++ .../data/BlockNamedEntityLootCondition.java | 5 + .../data/PlayerCreativeLootCondition.java | 5 + .../proxy/ComputerCraftProxyCommon.java | 12 +- .../advancements/recipes/generated/disk.json | 116 -------------- .../computercraft_speaker.json | 22 --- ...computercraft_wireless_modem_advanced.json | 22 --- .../computercraft_wireless_modem_normal.json | 22 --- .../pocket_normal/computercraft_speaker.json | 22 --- ...computercraft_wireless_modem_advanced.json | 22 --- .../computercraft_wireless_modem_normal.json | 22 --- .../computercraft_speaker.json | 22 --- ...computercraft_wireless_modem_advanced.json | 22 --- .../computercraft_wireless_modem_normal.json | 22 --- .../minecraft_crafting_table.json | 22 --- .../minecraft_diamond_axe.json | 22 --- .../minecraft_diamond_hoe.json | 22 --- .../minecraft_diamond_pickaxe.json | 22 --- .../minecraft_diamond_shovel.json | 22 --- .../minecraft_diamond_sword.json | 22 --- .../turtle_normal/computercraft_speaker.json | 22 --- ...computercraft_wireless_modem_advanced.json | 22 --- .../computercraft_wireless_modem_normal.json | 22 --- .../minecraft_crafting_table.json | 22 --- .../turtle_normal/minecraft_diamond_axe.json | 22 --- .../turtle_normal/minecraft_diamond_hoe.json | 22 --- .../minecraft_diamond_pickaxe.json | 22 --- .../minecraft_diamond_shovel.json | 22 --- .../minecraft_diamond_sword.json | 22 --- .../loot_tables/blocks/computer_advanced.json | 19 --- .../loot_tables/blocks/computer_command.json | 19 --- .../loot_tables/blocks/computer_normal.json | 19 --- .../loot_tables/blocks/disk_drive.json | 11 -- .../loot_tables/blocks/monitor_advanced.json | 13 -- .../loot_tables/blocks/monitor_normal.json | 13 -- .../loot_tables/blocks/printer.json | 11 -- .../loot_tables/blocks/speaker.json | 13 -- .../loot_tables/blocks/turtle_advanced.json | 19 --- .../loot_tables/blocks/turtle_normal.json | 19 --- .../loot_tables/blocks/wired_modem_full.json | 13 -- .../blocks/wireless_modem_advanced.json | 13 -- .../blocks/wireless_modem_normal.json | 13 -- .../recipes/generated/disk/disk_1.json | 10 -- .../recipes/generated/disk/disk_10.json | 10 -- .../recipes/generated/disk/disk_11.json | 10 -- .../recipes/generated/disk/disk_12.json | 10 -- .../recipes/generated/disk/disk_13.json | 10 -- .../recipes/generated/disk/disk_14.json | 10 -- .../recipes/generated/disk/disk_15.json | 10 -- .../recipes/generated/disk/disk_16.json | 10 -- .../recipes/generated/disk/disk_2.json | 10 -- .../recipes/generated/disk/disk_3.json | 10 -- .../recipes/generated/disk/disk_4.json | 10 -- .../recipes/generated/disk/disk_5.json | 10 -- .../recipes/generated/disk/disk_6.json | 10 -- .../recipes/generated/disk/disk_7.json | 10 -- .../recipes/generated/disk/disk_8.json | 10 -- .../recipes/generated/disk/disk_9.json | 10 -- .../computercraft_speaker.json | 13 -- ...computercraft_wireless_modem_advanced.json | 13 -- .../computercraft_wireless_modem_normal.json | 13 -- .../pocket_normal/computercraft_speaker.json | 13 -- ...computercraft_wireless_modem_advanced.json | 13 -- .../computercraft_wireless_modem_normal.json | 13 -- .../computercraft_speaker.json | 12 -- ...computercraft_wireless_modem_advanced.json | 12 -- .../computercraft_wireless_modem_normal.json | 12 -- .../minecraft_crafting_table.json | 12 -- .../minecraft_diamond_axe.json | 12 -- .../minecraft_diamond_hoe.json | 12 -- .../minecraft_diamond_pickaxe.json | 12 -- .../minecraft_diamond_shovel.json | 12 -- .../minecraft_diamond_sword.json | 12 -- .../turtle_normal/computercraft_speaker.json | 12 -- ...computercraft_wireless_modem_advanced.json | 12 -- .../computercraft_wireless_modem_normal.json | 12 -- .../minecraft_crafting_table.json | 12 -- .../turtle_normal/minecraft_diamond_axe.json | 12 -- .../turtle_normal/minecraft_diamond_hoe.json | 12 -- .../minecraft_diamond_pickaxe.json | 12 -- .../minecraft_diamond_shovel.json | 12 -- .../minecraft_diamond_sword.json | 12 -- tools/disk_recipe.json | 10 -- tools/pocket_upgrade_advancement.json | 22 --- tools/pocket_upgrade_recipe.json | 13 -- tools/recipes.lua | 136 ----------------- tools/turtle_upgrade_advancement.json | 22 --- tools/turtle_upgrade_recipe.json | 12 -- 211 files changed, 3495 insertions(+), 1511 deletions(-) create mode 100644 .gitattributes create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/computer_advanced.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/computer_normal.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/disk_drive.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/monitor_normal.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/printer.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/speaker.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/turtle_normal.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_1.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_10.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_11.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_12.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_13.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_14.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_15.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_16.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_2.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_3.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_4.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_5.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_6.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_7.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_8.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_9.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json create mode 100644 src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json create mode 100644 src/main/java/dan200/computercraft/data/Generators.java create mode 100644 src/main/java/dan200/computercraft/data/LootTableProvider.java create mode 100644 src/main/java/dan200/computercraft/data/LootTables.java create mode 100644 src/main/java/dan200/computercraft/data/RecipeWrapper.java create mode 100644 src/main/java/dan200/computercraft/data/Recipes.java delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/disk.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/printer.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/speaker.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json delete mode 100644 src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json delete mode 100644 tools/disk_recipe.json delete mode 100644 tools/pocket_upgrade_advancement.json delete mode 100644 tools/pocket_upgrade_recipe.json delete mode 100644 tools/recipes.lua delete mode 100644 tools/turtle_upgrade_advancement.json delete mode 100644 tools/turtle_upgrade_recipe.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..e05a3a6dd --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Ignore changes in generated files +src/generated/resources/data/** linguist-generated diff --git a/.gitignore b/.gitignore index 80c50f9b8..ef694a3ef 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ .settings/ bin/ *.launch + +/src/generated/resources/.cache diff --git a/build.gradle b/build.gradle index 10b5f77f8..52840a644 100644 --- a/build.gradle +++ b/build.gradle @@ -57,6 +57,19 @@ minecraft { } } } + + data { + workingDirectory project.file('run') + property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + property 'forge.logging.console.level', 'debug' + + args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') + mods { + computercraft { + source sourceSets.main + } + } + } } mappings channel: 'snapshot', version: "${mappings_version}".toString() @@ -64,6 +77,10 @@ minecraft { accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') } +sourceSets.main.resources { + srcDir 'src/generated/resources' +} + repositories { maven { name "JEI" diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json new file mode 100644 index 000000000..4a511c507 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_1.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_1" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_1" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json new file mode 100644 index 000000000..9d97d1db1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_10.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_10" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_10" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json new file mode 100644 index 000000000..4dc510b4e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_11.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_11" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_11" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json new file mode 100644 index 000000000..f5238fae6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_12.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_12" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_12" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json new file mode 100644 index 000000000..e81b64991 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_13.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_13" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_13" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json new file mode 100644 index 000000000..a7322e1fa --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_14.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_14" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_14" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json new file mode 100644 index 000000000..6ead3487a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_15.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_15" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_15" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json new file mode 100644 index 000000000..7bc970fc6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_16.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_16" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_16" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json new file mode 100644 index 000000000..b8671733b --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_2.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_2" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_2" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json new file mode 100644 index 000000000..f646f0d05 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_3.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_3" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_3" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json new file mode 100644 index 000000000..4b348588a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_4.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_4" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_4" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json new file mode 100644 index 000000000..40f6ef7de --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_5.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_5" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_5" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json new file mode 100644 index 000000000..1b23baeec --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_6.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_6" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_6" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json new file mode 100644 index 000000000..2cf60f3ac --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_7.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_7" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_7" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json new file mode 100644 index 000000000..fac9be366 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_8.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_8" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_8" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json new file mode 100644 index 000000000..b1eb4a9b5 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_9.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_9" + ] + }, + "criteria": { + "has_drive": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:disk_drive" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_9" + } + } + }, + "requirements": [ + [ + "has_drive", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json new file mode 100644 index 000000000..043371408 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "computercraft:speaker" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..7c77d28a2 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "computercraft:wireless_modem_advanced" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..e072333c9 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "computercraft:wireless_modem_normal" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..112ba7081 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/minecraft/crafting_table" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "minecraft:crafting_table" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/minecraft/crafting_table" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..7b5c315e4 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/minecraft/diamond_axe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "minecraft:diamond_axe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/minecraft/diamond_axe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..9f5872d9f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/minecraft/diamond_hoe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "minecraft:diamond_hoe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/minecraft/diamond_hoe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..7e1930b03 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/minecraft/diamond_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "minecraft:diamond_pickaxe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/minecraft/diamond_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..05222ce97 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/minecraft/diamond_shovel" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "minecraft:diamond_shovel" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/minecraft/diamond_shovel" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..413e0375d --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_advanced/minecraft/diamond_sword" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_advanced" + }, + { + "item": "minecraft:diamond_sword" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_advanced/minecraft/diamond_sword" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json new file mode 100644 index 000000000..35ab06eea --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "computercraft:speaker" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..104f9d30e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "computercraft:wireless_modem_advanced" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..5f7431ad7 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "computercraft:wireless_modem_normal" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..c507d2563 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/minecraft/crafting_table" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "minecraft:crafting_table" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/minecraft/crafting_table" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..a14901a3e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/minecraft/diamond_axe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "minecraft:diamond_axe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/minecraft/diamond_axe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..5dba7dcd6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/minecraft/diamond_hoe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "minecraft:diamond_hoe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/minecraft/diamond_hoe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..06a10b8ec --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/minecraft/diamond_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "minecraft:diamond_pickaxe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/minecraft/diamond_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..22ccd7e60 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/minecraft/diamond_shovel" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "minecraft:diamond_shovel" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/minecraft/diamond_shovel" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..74378a20c --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_normal/minecraft/diamond_sword" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:pocket_computer_normal" + }, + { + "item": "minecraft:diamond_sword" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_normal/minecraft/diamond_sword" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json new file mode 100644 index 000000000..c5ddd2003 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "computercraft:speaker" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..b429cf9e6 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "computercraft:wireless_modem_advanced" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..6ac217096 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "computercraft:wireless_modem_normal" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..b2bb0df1a --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/crafting_table" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "minecraft:crafting_table" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/crafting_table" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..b11436e4b --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_axe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "minecraft:diamond_axe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_axe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..5808c4ed5 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_hoe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "minecraft:diamond_hoe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_hoe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..2cf9a608b --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "minecraft:diamond_pickaxe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..c36478843 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_shovel" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "minecraft:diamond_shovel" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_shovel" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..664b9f9e8 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_advanced/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_advanced/minecraft/diamond_sword" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_advanced" + }, + { + "item": "minecraft:diamond_sword" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_advanced/minecraft/diamond_sword" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json new file mode 100644 index 000000000..dfd1b4664 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/speaker.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/computercraft/speaker" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "computercraft:speaker" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/computercraft/speaker" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..74c5dac34 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/computercraft/wireless_modem_advanced" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "computercraft:wireless_modem_advanced" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/computercraft/wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..e54be71d1 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/computercraft/wireless_modem_normal" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "computercraft:wireless_modem_normal" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/computercraft/wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..fe1c547eb --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/crafting_table.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/crafting_table" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "minecraft:crafting_table" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/crafting_table" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..afd62779d --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_axe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_axe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "minecraft:diamond_axe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_axe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..a6a16729e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_hoe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_hoe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "minecraft:diamond_hoe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_hoe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..e26cd09cf --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_pickaxe" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "minecraft:diamond_pickaxe" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_pickaxe" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..3d6b54ec4 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_shovel.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_shovel" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "minecraft:diamond_shovel" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_shovel" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..ab64bae40 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/turtle_normal/minecraft/diamond_sword.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:turtle_normal/minecraft/diamond_sword" + ] + }, + "criteria": { + "has_items": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:turtle_normal" + }, + { + "item": "minecraft:diamond_sword" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:turtle_normal/minecraft/diamond_sword" + } + } + }, + "requirements": [ + [ + "has_items", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json b/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/computer_normal.json b/src/generated/resources/data/computercraft/loot_tables/computer_normal.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/computer_normal.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/disk_drive.json b/src/generated/resources/data/computercraft/loot_tables/disk_drive.json new file mode 100644 index 000000000..675f3cf78 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/disk_drive.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:disk_drive" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json b/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json new file mode 100644 index 000000000..e5c1b82b1 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:monitor_advanced" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json b/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json new file mode 100644 index 000000000..f27f7adcf --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:monitor_normal" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/printer.json b/src/generated/resources/data/computercraft/loot_tables/printer.json new file mode 100644 index 000000000..c632c9d67 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/printer.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:printer" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/speaker.json b/src/generated/resources/data/computercraft/loot_tables/speaker.json new file mode 100644 index 000000000..5b6d03f9a --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/speaker.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:speaker" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json b/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json b/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json new file mode 100644 index 000000000..09dac48f6 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json @@ -0,0 +1,30 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json b/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json new file mode 100644 index 000000000..02bd68624 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wired_modem_full" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json new file mode 100644 index 000000000..4f46d4b0f --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wireless_modem_advanced" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json new file mode 100644 index 000000000..a9fdb21e7 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "computercraft:wireless_modem_normal" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_1.json b/src/generated/resources/data/computercraft/recipes/disk_1.json new file mode 100644 index 000000000..66ce73a90 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_1.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:black_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:1118481}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_10.json b/src/generated/resources/data/computercraft/recipes/disk_10.json new file mode 100644 index 000000000..9c064f0fb --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_10.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:pink_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:15905484}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_11.json b/src/generated/resources/data/computercraft/recipes/disk_11.json new file mode 100644 index 000000000..bfd6b21dc --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_11.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:lime_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:8375321}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_12.json b/src/generated/resources/data/computercraft/recipes/disk_12.json new file mode 100644 index 000000000..7fa0ff4be --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_12.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:yellow_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:14605932}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_13.json b/src/generated/resources/data/computercraft/recipes/disk_13.json new file mode 100644 index 000000000..ab237e75c --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_13.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:light_blue_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:10072818}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_14.json b/src/generated/resources/data/computercraft/recipes/disk_14.json new file mode 100644 index 000000000..458ad2a71 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_14.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:magenta_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:15040472}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_15.json b/src/generated/resources/data/computercraft/recipes/disk_15.json new file mode 100644 index 000000000..35147838e --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_15.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:orange_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:15905331}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_16.json b/src/generated/resources/data/computercraft/recipes/disk_16.json new file mode 100644 index 000000000..1f86b573a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_16.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:white_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:15790320}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_2.json b/src/generated/resources/data/computercraft/recipes/disk_2.json new file mode 100644 index 000000000..40f55f5a4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_2.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:red_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:13388876}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_3.json b/src/generated/resources/data/computercraft/recipes/disk_3.json new file mode 100644 index 000000000..5ed4b4d72 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_3.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:green_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:5744206}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_4.json b/src/generated/resources/data/computercraft/recipes/disk_4.json new file mode 100644 index 000000000..ecc80c9e2 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_4.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:brown_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:8349260}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_5.json b/src/generated/resources/data/computercraft/recipes/disk_5.json new file mode 100644 index 000000000..94beac68a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_5.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:blue_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:3368652}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_6.json b/src/generated/resources/data/computercraft/recipes/disk_6.json new file mode 100644 index 000000000..0416fba6e --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_6.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:purple_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:11691749}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_7.json b/src/generated/resources/data/computercraft/recipes/disk_7.json new file mode 100644 index 000000000..99f64b544 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_7.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:cyan_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:5020082}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_8.json b/src/generated/resources/data/computercraft/recipes/disk_8.json new file mode 100644 index 000000000..be1b7fea9 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_8.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:light_gray_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:10066329}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_9.json b/src/generated/resources/data/computercraft/recipes/disk_9.json new file mode 100644 index 000000000..48620dbdd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_9.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shapeless", + "group": "computercraft:disk", + "ingredients": [ + { + "tag": "forge:dusts/redstone" + }, + { + "item": "minecraft:paper" + }, + { + "item": "minecraft:gray_dye" + } + ], + "result": { + "item": "computercraft:disk", + "nbt": "{color:5000268}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json new file mode 100644 index 000000000..350a5019b --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..8896bd062 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..9e007b1cd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..0cd065680 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..7b8fa8a24 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..9514a59cd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..e28008623 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..b0ddf3016 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..cea0b2a0f --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_advanced", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_advanced" + }, + "P": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json new file mode 100644 index 000000000..b5fb937a4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..d8e9518e4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..736753136 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..dc1ddd884 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..686d9d890 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..905a2640a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..200d15862 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..fcae256c7 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..564dbf7e5 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:pocket_normal", + "pattern": [ + "#", + "P" + ], + "key": { + "#": { + "item": "computercraft:pocket_computer_normal" + }, + "P": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json new file mode 100644 index 000000000..6526349af --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:speaker\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..2aea48cae --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..39c434755 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json new file mode 100644 index 000000000..f7178ff09 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json new file mode 100644 index 000000000..ab2831b56 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_axe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json new file mode 100644 index 000000000..13c2f694c --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..3f3763457 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json new file mode 100644 index 000000000..248f62209 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json new file mode 100644 index 000000000..8cab2a90b --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_advanced/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_advanced", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_advanced" + }, + "T": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:turtle_advanced", + "nbt": "{RightUpgrade:\"minecraft:diamond_sword\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json new file mode 100644 index 000000000..28f425aec --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/speaker.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "computercraft:speaker" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:speaker\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..3af190a52 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "computercraft:wireless_modem_advanced" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_advanced\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..f387a143d --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/computercraft/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "computercraft:wireless_modem_normal" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"computercraft:wireless_modem_normal\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json new file mode 100644 index 000000000..8e8a1dcc9 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/crafting_table.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "minecraft:crafting_table" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:crafting_table\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json new file mode 100644 index 000000000..85a16309d --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_axe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "minecraft:diamond_axe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_axe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json new file mode 100644 index 000000000..45491a5e8 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_hoe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "minecraft:diamond_hoe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_hoe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json new file mode 100644 index 000000000..db9ef1ae6 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_pickaxe.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "minecraft:diamond_pickaxe" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_pickaxe\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json new file mode 100644 index 000000000..66f98c2c9 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_shovel.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "minecraft:diamond_shovel" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_shovel\"}" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json new file mode 100644 index 000000000..c99c73c03 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/turtle_normal/minecraft/diamond_sword.json @@ -0,0 +1,19 @@ +{ + "type": "computercraft:impostor_shaped", + "group": "computercraft:turtle_normal", + "pattern": [ + "#T" + ], + "key": { + "#": { + "item": "computercraft:turtle_normal" + }, + "T": { + "item": "minecraft:diamond_sword" + } + }, + "result": { + "item": "computercraft:turtle_normal", + "nbt": "{RightUpgrade:\"minecraft:diamond_sword\"}" + } +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java new file mode 100644 index 000000000..1506661a1 --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -0,0 +1,27 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; +import net.minecraft.data.DataGenerator; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.GatherDataEvent; + +@Mod.EventBusSubscriber( bus = Mod.EventBusSubscriber.Bus.MOD ) +public class Generators +{ + @SubscribeEvent + public static void gather( GatherDataEvent event ) + { + ComputerCraftProxyCommon.registerLoot(); + + DataGenerator generator = event.getGenerator(); + generator.addProvider( new Recipes( generator ) ); + generator.addProvider( new LootTables( generator ) ); + } +} diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java new file mode 100644 index 000000000..54b47c42f --- /dev/null +++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -0,0 +1,91 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import com.google.common.collect.Multimap; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dan200.computercraft.ComputerCraft; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.DirectoryCache; +import net.minecraft.data.IDataProvider; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.LootTable; +import net.minecraft.world.storage.loot.LootTableManager; +import net.minecraft.world.storage.loot.ValidationResults; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; + +/** + * An alternative to {@link net.minecraft.data.LootTableProvider}, with a more flexible interface. + */ +public abstract class LootTableProvider implements IDataProvider +{ + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + + private final DataGenerator generator; + + public LootTableProvider( DataGenerator generator ) + { + this.generator = generator; + } + + @Override + public void act( @Nonnull DirectoryCache cache ) + { + + ValidationResults validation = new ValidationResults(); + Map tables = new HashMap<>(); + registerLoot( ( id, table ) -> { + if( tables.containsKey( id ) ) validation.addProblem( "Duplicate loot tables for " + id ); + tables.put( id, table ); + } ); + + tables.forEach( ( key, value ) -> LootTableManager.func_215302_a( validation, key, value, tables::get ) ); + + Multimap problems = validation.getProblems(); + if( !problems.isEmpty() ) + { + problems.forEach( ( child, problem ) -> + ComputerCraft.log.warn( "Found validation problem in " + child + ": " + problem ) ); + throw new IllegalStateException( "Failed to validate loot tables, see logs" ); + } + + tables.forEach( ( key, value ) -> { + Path path = getPath( key ); + try + { + IDataProvider.save( GSON, cache, LootTableManager.toJson( value ), path ); + } + catch( IOException e ) + { + ComputerCraft.log.error( "Couldn't save loot table {}", path, e ); + } + } ); + } + + protected abstract void registerLoot( BiConsumer add ); + + @Nonnull + @Override + public String getName() + { + return "LootTables"; + } + + private Path getPath( ResourceLocation id ) + { + return generator.getOutputFolder() + .resolve( "data" ).resolve( id.getNamespace() ).resolve( "loot_tables" ) + .resolve( id.getPath() + ".json" ); + } +} diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java new file mode 100644 index 000000000..f40295ccc --- /dev/null +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -0,0 +1,72 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; +import dan200.computercraft.shared.data.PlayerCreativeLootCondition; +import net.minecraft.block.Block; +import net.minecraft.data.DataGenerator; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.*; +import net.minecraft.world.storage.loot.conditions.Alternative; +import net.minecraft.world.storage.loot.conditions.SurvivesExplosion; + +import java.util.function.BiConsumer; + +public class LootTables extends LootTableProvider +{ + public LootTables( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerLoot( BiConsumer add ) + { + basicDrop( add, ComputerCraft.Blocks.diskDrive ); + basicDrop( add, ComputerCraft.Blocks.monitorNormal ); + basicDrop( add, ComputerCraft.Blocks.monitorAdvanced ); + basicDrop( add, ComputerCraft.Blocks.printer ); + basicDrop( add, ComputerCraft.Blocks.speaker ); + basicDrop( add, ComputerCraft.Blocks.wiredModemFull ); + basicDrop( add, ComputerCraft.Blocks.wirelessModemNormal ); + basicDrop( add, ComputerCraft.Blocks.wirelessModemAdvanced ); + + computerDrop( add, ComputerCraft.Blocks.computerNormal ); + computerDrop( add, ComputerCraft.Blocks.computerAdvanced ); + computerDrop( add, ComputerCraft.Blocks.turtleNormal ); + computerDrop( add, ComputerCraft.Blocks.turtleAdvanced ); + } + + private static void basicDrop( BiConsumer add, Block block ) + { + add.accept( block.getRegistryName(), LootTable + .builder() + .addLootPool( LootPool.builder() + .name( "main" ) + .rolls( ConstantRange.of( 1 ) ) + .addEntry( ItemLootEntry.builder( block ) ) + .acceptCondition( SurvivesExplosion.builder() ) + ).build() ); + } + + private static void computerDrop( BiConsumer add, Block block ) + { + add.accept( block.getRegistryName(), LootTable + .builder() + .addLootPool( LootPool.builder() + .name( "main" ) + .rolls( ConstantRange.of( 1 ) ) + .addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) ) + .acceptCondition( Alternative.builder( + BlockNamedEntityLootCondition.builder(), + PlayerCreativeLootCondition.builder().inverted() + ) ) + ).build() ); + } +} diff --git a/src/main/java/dan200/computercraft/data/RecipeWrapper.java b/src/main/java/dan200/computercraft/data/RecipeWrapper.java new file mode 100644 index 000000000..f3252a39a --- /dev/null +++ b/src/main/java/dan200/computercraft/data/RecipeWrapper.java @@ -0,0 +1,92 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import com.google.gson.JsonObject; +import net.minecraft.data.IFinishedRecipe; +import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.JSONUtils; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.function.Consumer; + +/** + * Adapter for recipes which overrides the serializer and adds custom item NBT. + */ +public class RecipeWrapper implements IFinishedRecipe +{ + private final IFinishedRecipe recipe; + private final CompoundNBT resultData; + private final IRecipeSerializer serializer; + + private RecipeWrapper( IFinishedRecipe recipe, CompoundNBT resultData, IRecipeSerializer serializer ) + { + this.resultData = resultData; + this.recipe = recipe; + this.serializer = serializer; + } + + public static Consumer wrap( IRecipeSerializer serializer, Consumer original ) + { + return x -> original.accept( new RecipeWrapper( x, null, serializer ) ); + } + + public static Consumer wrap( IRecipeSerializer serializer, Consumer original, CompoundNBT resultData ) + { + return x -> original.accept( new RecipeWrapper( x, resultData, serializer ) ); + } + + public static Consumer wrap( IRecipeSerializer serializer, Consumer original, Consumer resultData ) + { + CompoundNBT tag = new CompoundNBT(); + resultData.accept( tag ); + return x -> original.accept( new RecipeWrapper( x, tag, serializer ) ); + } + + @Override + public void serialize( @Nonnull JsonObject jsonObject ) + { + recipe.serialize( jsonObject ); + + if( resultData != null ) + { + JsonObject object = JSONUtils.getJsonObject( jsonObject, "result" ); + object.addProperty( "nbt", resultData.toString() ); + } + } + + @Nonnull + @Override + public ResourceLocation getID() + { + return recipe.getID(); + } + + @Nonnull + @Override + public IRecipeSerializer getSerializer() + { + return serializer; + } + + @Nullable + @Override + public JsonObject getAdvancementJson() + { + return recipe.getAdvancementJson(); + } + + @Nullable + @Override + public ResourceLocation getAdvancementID() + { + return recipe.getAdvancementID(); + } +} diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java new file mode 100644 index 000000000..7146e829d --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -0,0 +1,141 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.TurtleUpgrades; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; +import dan200.computercraft.shared.turtle.items.TurtleItemFactory; +import dan200.computercraft.shared.util.Colour; +import dan200.computercraft.shared.util.ImpostorRecipe; +import dan200.computercraft.shared.util.ImpostorShapelessRecipe; +import net.minecraft.advancements.criterion.InventoryChangeTrigger; +import net.minecraft.data.*; +import net.minecraft.item.DyeColor; +import net.minecraft.item.DyeItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.Tags; + +import javax.annotation.Nonnull; +import java.util.Locale; +import java.util.function.Consumer; + +public class Recipes extends RecipeProvider +{ + public Recipes( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerRecipes( @Nonnull Consumer add ) + { + diskColours( add ); + pocketUpgrades( add ); + turtleUpgrades( add ); + } + + /** + * Register a crafting recipe for a disk of every dye colour. + * + * @param add The callback to add recipes. + */ + private void diskColours( @Nonnull Consumer add ) + { + for( Colour colour : Colour.VALUES ) + { + ShapelessRecipeBuilder + .shapelessRecipe( ComputerCraft.Items.disk ) + .addIngredient( Tags.Items.DUSTS_REDSTONE ) + .addIngredient( Items.PAPER ) + .addIngredient( DyeItem.getItem( ofColour( colour ) ) ) + .setGroup( "computercraft:disk" ) + .addCriterion( "has_drive", InventoryChangeTrigger.Instance.forItems( ComputerCraft.Blocks.diskDrive ) ) + .build( RecipeWrapper.wrap( + ImpostorShapelessRecipe.SERIALIZER, add, + x -> x.putInt( "color", colour.getHex() ) + ), new ResourceLocation( ComputerCraft.MOD_ID, "disk_" + (colour.ordinal() + 1) ) ); + } + } + + /** + * Register a crafting recipe for each turtle upgrade. + * + * @param add The callback to add recipes. + */ + private void turtleUpgrades( @Nonnull Consumer add ) + { + for( ComputerFamily family : ComputerFamily.values() ) + { + ItemStack base = TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ); + if( base.isEmpty() ) continue; + + String nameId = family.name().toLowerCase( Locale.ROOT ); + + TurtleUpgrades.getVanillaUpgrades().forEach( upgrade -> { + ItemStack result = TurtleItemFactory.create( -1, null, -1, family, null, upgrade, -1, null ); + ShapedRecipeBuilder + .shapedRecipe( result.getItem() ) + .setGroup( String.format( "%s:turtle_%s", ComputerCraft.MOD_ID, nameId ) ) + .patternLine( "#T" ) + .key( '#', base.getItem() ) + .key( 'T', upgrade.getCraftingItem().getItem() ) + .addCriterion( "has_items", + InventoryChangeTrigger.Instance.forItems( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + .build( + RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ), + new ResourceLocation( ComputerCraft.MOD_ID, String.format( "turtle_%s/%s/%s", + nameId, upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath() + ) ) + ); + } ); + } + } + + /** + * Register a crafting recipe for each pocket upgrade. + * + * @param add The callback to add recipes. + */ + private void pocketUpgrades( @Nonnull Consumer add ) + { + for( ComputerFamily family : ComputerFamily.values() ) + { + ItemStack base = PocketComputerItemFactory.create( -1, null, -1, family, null ); + if( base.isEmpty() ) continue; + + String nameId = family.name().toLowerCase( Locale.ROOT ); + + TurtleUpgrades.getVanillaUpgrades().forEach( upgrade -> { + ItemStack result = PocketComputerItemFactory.create( -1, null, -1, family, null ); + ShapedRecipeBuilder + .shapedRecipe( result.getItem() ) + .setGroup( String.format( "%s:pocket_%s", ComputerCraft.MOD_ID, nameId ) ) + .patternLine( "#" ) + .patternLine( "P" ) + .key( '#', base.getItem() ) + .key( 'P', upgrade.getCraftingItem().getItem() ) + .addCriterion( "has_items", + InventoryChangeTrigger.Instance.forItems( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + .build( + RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ), + new ResourceLocation( ComputerCraft.MOD_ID, String.format( "pocket_%s/%s/%s", + nameId, upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath() + ) ) + ); + } ); + } + } + + private static DyeColor ofColour( Colour colour ) + { + return DyeColor.byId( 15 - colour.ordinal() ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index c2842ff28..898c321ce 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -40,4 +40,9 @@ public final class BlockNamedEntityLootCondition implements ILootCondition { return Collections.singleton( LootParameters.BLOCK_ENTITY ); } + + public static IBuilder builder() + { + return () -> INSTANCE; + } } diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 9055f3c17..6a91f90fe 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -40,4 +40,9 @@ public final class PlayerCreativeLootCondition implements ILootCondition { return Collections.singleton( LootParameters.THIS_ENTITY ); } + + public static IBuilder builder() + { + return () -> INSTANCE; + } } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 2b3261491..70ddeca32 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -47,14 +47,20 @@ import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; public final class ComputerCraftProxyCommon { @SubscribeEvent + @SuppressWarnings( "deprecation" ) public static void init( FMLCommonSetupEvent event ) { NetworkHandler.setup(); - registerProviders(); - - ArgumentSerializers.register(); + net.minecraftforge.fml.DeferredWorkQueue.runLater( () -> { + registerProviders(); + ArgumentSerializers.register(); + registerLoot(); + } ); + } + public static void registerLoot() + { LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( new ResourceLocation( ComputerCraft.MOD_ID, "block_named" ), BlockNamedEntityLootCondition.class, diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/disk.json b/src/main/resources/data/computercraft/advancements/recipes/generated/disk.json deleted file mode 100644 index 94c07e6d9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/disk.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:generated/disk/disk_1", - "computercraft:generated/disk/disk_2", - "computercraft:generated/disk/disk_3", - "computercraft:generated/disk/disk_4", - "computercraft:generated/disk/disk_5", - "computercraft:generated/disk/disk_6", - "computercraft:generated/disk/disk_7", - "computercraft:generated/disk/disk_8", - "computercraft:generated/disk/disk_9", - "computercraft:generated/disk/disk_10", - "computercraft:generated/disk/disk_11", - "computercraft:generated/disk/disk_12", - "computercraft:generated/disk/disk_13", - "computercraft:generated/disk/disk_14", - "computercraft:generated/disk/disk_15", - "computercraft:generated/disk/disk_16" - ] - }, - "criteria": { - "has_drive": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:disk_drive" } ] - } - }, - "has_recipe_1": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_1" } - }, - "has_recipe_2": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_2" } - }, - "has_recipe_3": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_3" } - }, - "has_recipe_4": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_4" } - }, - "has_recipe_5": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_5" } - }, - "has_recipe_6": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_6" } - }, - "has_recipe_7": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_7" } - }, - "has_recipe_8": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_8" } - }, - "has_recipe_9": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_9" } - }, - "has_recipe_10": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_10" } - }, - "has_recipe_11": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_11" } - }, - "has_recipe_12": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_12" } - }, - "has_recipe_13": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_13" } - }, - "has_recipe_14": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_14" } - }, - "has_recipe_15": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_15" } - }, - "has_recipe_16": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/disk/disk_16" } - } - }, - "requirements": [ - [ - "has_drive", - "has_recipe_1", - "has_recipe_2", - "has_recipe_3", - "has_recipe_4", - "has_recipe_5", - "has_recipe_6", - "has_recipe_7", - "has_recipe_8", - "has_recipe_9", - "has_recipe_10", - "has_recipe_11", - "has_recipe_12", - "has_recipe_13", - "has_recipe_14", - "has_recipe_15", - "has_recipe_16" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json deleted file mode 100644 index 3b9da6c6f..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_advanced/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_advanced" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_advanced/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index ce426a0f9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_advanced/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_advanced" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_advanced/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index d92bae7b0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_advanced/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_advanced" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_advanced/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json deleted file mode 100644 index a0fac97f9..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_normal/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_normal" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_normal/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 29c8cb86b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_normal/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_normal" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_normal/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 19fe726ee..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/pocket_normal/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_normal" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/pocket_normal/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json deleted file mode 100644 index 09942d3d5..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 23ed3111c..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index e2613b21f..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json deleted file mode 100644 index c6c86d47a..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_crafting_table.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_crafting_table" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:crafting_table" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_crafting_table" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json deleted file mode 100644 index 6c1adcd84..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_axe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_axe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_axe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_axe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json deleted file mode 100644 index d906a8317..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_hoe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_hoe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_hoe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json deleted file mode 100644 index 9d59c615e..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_pickaxe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_pickaxe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_pickaxe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json deleted file mode 100644 index efc7a3fce..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_shovel" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_shovel" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_shovel" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json deleted file mode 100644 index ad9f19c17..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_advanced/minecraft_diamond_sword.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_advanced/minecraft_diamond_sword" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_advanced" }, - { "item": "minecraft:diamond_sword" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_advanced/minecraft_diamond_sword" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json deleted file mode 100644 index 6d18d9ee2..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_speaker.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/computercraft_speaker" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "computercraft:speaker" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/computercraft_speaker" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 5fe595acc..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/computercraft_wireless_modem_advanced" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "computercraft:wireless_modem_advanced" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/computercraft_wireless_modem_advanced" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 8d43a7c65..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/computercraft_wireless_modem_normal" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "computercraft:wireless_modem_normal" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/computercraft_wireless_modem_normal" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json deleted file mode 100644 index 2bee28454..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_crafting_table.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_crafting_table" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:crafting_table" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_crafting_table" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json deleted file mode 100644 index df0b816a6..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_axe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_axe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_axe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_axe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json deleted file mode 100644 index 8df26b012..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_hoe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_hoe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_hoe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_hoe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json deleted file mode 100644 index e83d19e7b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_pickaxe" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_pickaxe" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_pickaxe" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json deleted file mode 100644 index abeddd89b..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_shovel.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_shovel" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_shovel" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_shovel" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json deleted file mode 100644 index 8930c40dd..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/generated/turtle_normal/minecraft_diamond_sword.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:generated/turtle_normal/minecraft_diamond_sword" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_normal" }, - { "item": "minecraft:diamond_sword" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:generated/turtle_normal/minecraft_diamond_sword" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json deleted file mode 100644 index 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json deleted file mode 100644 index 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_command.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json deleted file mode 100644 index 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json b/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json deleted file mode 100644 index 6575281bb..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/disk_drive.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:item", "name": "computercraft:disk_drive" } ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json deleted file mode 100644 index f6f9710c5..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:monitor_advanced" } - ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json deleted file mode 100644 index bff665f73..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/monitor_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:monitor_normal" } - ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json b/src/main/resources/data/computercraft/loot_tables/blocks/printer.json deleted file mode 100644 index fff10863c..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/printer.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:item", "name": "computercraft:printer" } ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json b/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json deleted file mode 100644 index 735c12a91..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/speaker.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:speaker" } - ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json deleted file mode 100644 index 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json deleted file mode 100644 index 26cde0f50..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ { "type": "minecraft:dynamic", "name": "computercraft:computer" } ], - "conditions": [ - { - "condition": "alternative", - "terms": [ - { "condition": "computercraft:block_named" }, - { "condition": "minecraft:inverted", "term": { "condition": "computercraft:player_creative" } } - ] - } - ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json b/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json deleted file mode 100644 index 9a8a883df..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:wired_modem_full" } - ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json deleted file mode 100644 index 00dae5bc8..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:wireless_modem_advanced" } - ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json b/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json deleted file mode 100644 index cb88adee4..000000000 --- a/src/main/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "name": "main", - "rolls": 1, - "entries": [ - { "type": "minecraft:item", "name": "computercraft:wireless_modem_normal" } - ], - "conditions": [ { "condition": "minecraft:survives_explosion" } ] - } - ] -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json deleted file mode 100644 index a27ee37c6..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_1.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:black_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 1118481 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json deleted file mode 100644 index 26b83fe6b..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_10.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:pink_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15905484 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json deleted file mode 100644 index 40d6157c0..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_11.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:lime_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 8375321 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json deleted file mode 100644 index 505066e7a..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_12.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:yellow_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 14605932 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json deleted file mode 100644 index e270135ef..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_13.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:light_blue_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 10072818 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json deleted file mode 100644 index 73794dac1..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_14.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:magenta_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15040472 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json deleted file mode 100644 index 13ff4dd71..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_15.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:orange_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15905331 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json deleted file mode 100644 index 2fa82adad..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_16.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:white_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 15790320 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json deleted file mode 100644 index 21ab48568..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_2.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:red_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 13388876 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json deleted file mode 100644 index a164af6cb..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_3.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:green_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 5744206 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json deleted file mode 100644 index 7109021e3..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_4.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:brown_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 8349260 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json deleted file mode 100644 index 538f14349..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_5.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:blue_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 3368652 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json deleted file mode 100644 index 6a9c1ed5b..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_6.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:purple_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 11691749 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json deleted file mode 100644 index 6f6a442f7..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_7.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:cyan_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 5020082 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json deleted file mode 100644 index bd8bc8f42..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_8.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:light_gray_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 10066329 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json b/src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json deleted file mode 100644 index 67ad7f58e..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/disk/disk_9.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "minecraft:gray_dye" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": 5000268 } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json deleted file mode 100644 index e60e9ea93..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_speaker.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_advanced", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:pocket_computer_advanced" } - }, - "result": { "item": "computercraft:pocket_computer_advanced", "nbt": { "Upgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 878afe1a5..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_advanced", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:pocket_computer_advanced" } - }, - "result": { "item": "computercraft:pocket_computer_advanced", "nbt": { "Upgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index 1bd86cca0..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_advanced", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:pocket_computer_advanced" } - }, - "result": { "item": "computercraft:pocket_computer_advanced", "nbt": { "Upgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json deleted file mode 100644 index ba569ec7a..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_speaker.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_normal", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:pocket_computer_normal" } - }, - "result": { "item": "computercraft:pocket_computer_normal", "nbt": { "Upgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index 3c008706d..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_normal", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:pocket_computer_normal" } - }, - "result": { "item": "computercraft:pocket_computer_normal", "nbt": { "Upgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 85e7a1d5f..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/pocket_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_normal", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:pocket_computer_normal" } - }, - "result": { "item": "computercraft:pocket_computer_normal", "nbt": { "Upgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json deleted file mode 100644 index fe43a6734..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_speaker.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json deleted file mode 100644 index a6af8052c..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json deleted file mode 100644 index 564e31980..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json deleted file mode 100644 index 3e44088ca..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_crafting_table.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:crafting_table" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:crafting_table" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json deleted file mode 100644 index 9727781b2..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_axe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_axe" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_axe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json deleted file mode 100644 index a36a0b9f5..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_hoe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_hoe" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_hoe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json deleted file mode 100644 index 27da4aabd..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_pickaxe" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_pickaxe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json deleted file mode 100644 index 72bc79f11..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_shovel.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_shovel" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_shovel" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json deleted file mode 100644 index 3035c91e0..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_advanced/minecraft_diamond_sword.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_advanced", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_sword" }, - "T": { "item": "computercraft:turtle_advanced" } - }, - "result": { "item": "computercraft:turtle_advanced", "nbt": { "RightUpgrade": "minecraft:diamond_sword" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json deleted file mode 100644 index 20788c88d..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_speaker.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:speaker" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "computercraft:speaker" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json deleted file mode 100644 index b7b7e6ef1..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_advanced.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_advanced" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "computercraft:wireless_modem_advanced" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json deleted file mode 100644 index 5722d7029..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/computercraft_wireless_modem_normal.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "computercraft:wireless_modem_normal" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "computercraft:wireless_modem_normal" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json deleted file mode 100644 index 14c8f23e3..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_crafting_table.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:crafting_table" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:crafting_table" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json deleted file mode 100644 index e0c2104d2..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_axe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_axe" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_axe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json deleted file mode 100644 index 981e41774..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_hoe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_hoe" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_hoe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json deleted file mode 100644 index 459ca8233..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_pickaxe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_pickaxe" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_pickaxe" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json deleted file mode 100644 index fc414008b..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_shovel.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_shovel" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_shovel" } } -} diff --git a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json b/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json deleted file mode 100644 index 0c2321121..000000000 --- a/src/main/resources/data/computercraft/recipes/generated/turtle_normal/minecraft_diamond_sword.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_normal", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "minecraft:diamond_sword" }, - "T": { "item": "computercraft:turtle_normal" } - }, - "result": { "item": "computercraft:turtle_normal", "nbt": { "RightUpgrade": "minecraft:diamond_sword" } } -} diff --git a/tools/disk_recipe.json b/tools/disk_recipe.json deleted file mode 100644 index c6a67ab7a..000000000 --- a/tools/disk_recipe.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "type": "computercraft:impostor_shapeless", - "group": "computercraft:disk", - "ingredients": [ - { "tag": "forge:dusts/redstone" }, - { "item": "minecraft:paper" }, - { "item": "${dye}" } - ], - "result": { "item": "computercraft:disk", "nbt": { "color": ${colour} } } -} diff --git a/tools/pocket_upgrade_advancement.json b/tools/pocket_upgrade_advancement.json deleted file mode 100644 index 2fd25329f..000000000 --- a/tools/pocket_upgrade_advancement.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:${path}" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:pocket_computer_${pocket_family}" }, - { "item": "${upgrade_item}" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:${path}" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/tools/pocket_upgrade_recipe.json b/tools/pocket_upgrade_recipe.json deleted file mode 100644 index 354015b2a..000000000 --- a/tools/pocket_upgrade_recipe.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_pocket_${pocket_family}", - "pattern": [ - "#", - "T" - ], - "key": { - "#": { "item": "${upgrade_item}" }, - "T": { "item": "computercraft:pocket_computer_${pocket_family}" } - }, - "result": { "item": "computercraft:pocket_computer_${pocket_family}", "nbt": { "Upgrade": "${upgrade_id}" } } -} diff --git a/tools/recipes.lua b/tools/recipes.lua deleted file mode 100644 index d2c007523..000000000 --- a/tools/recipes.lua +++ /dev/null @@ -1,136 +0,0 @@ ---- Generates impostor recipes and advancements for several dynamic recipes. --- --- Namely: --- - Turtle upgrades --- - Pocket upgrades --- - Disk (each colour) --- --- Note, this is largely intended for the recipe book, as that requires a fixed --- set of recipes. - ---- All turtle upgrades, and an optional item for this upgrade. -local turtle_upgrades = { - { "computercraft:wireless_modem_normal" }, - { "computercraft:wireless_modem_advanced" }, - { "computercraft:speaker" }, - { "minecraft:crafting_table" }, - { "minecraft:diamond_sword" }, - { "minecraft:diamond_shovel" }, - { "minecraft:diamond_pickaxe" }, - { "minecraft:diamond_axe" }, - { "minecraft:diamond_hoe" }, -} - ---- All pocket upgrades, and an optional item for this upgrade. -local pocket_upgrades = { - { "computercraft:wireless_modem_normal" }, - { "computercraft:wireless_modem_advanced" }, - { "computercraft:speaker" }, -} - ---- All dye/disk colours -local colours = { - { 0x111111, "minecraft:black_dye" }, - { 0xcc4c4c, "minecraft:red_dye" }, - { 0x57A64E, "minecraft:green_dye" }, - { 0x7f664c, "minecraft:brown_dye" }, - { 0x3366cc, "minecraft:blue_dye" }, - { 0xb266e5, "minecraft:purple_dye" }, - { 0x4c99b2, "minecraft:cyan_dye" }, - { 0x999999, "minecraft:light_gray_dye" }, - { 0x4c4c4c, "minecraft:gray_dye" }, - { 0xf2b2cc, "minecraft:pink_dye" }, - { 0x7fcc19, "minecraft:lime_dye" }, - { 0xdede6c, "minecraft:yellow_dye" }, - { 0x99b2f2, "minecraft:light_blue_dye" }, - { 0xe57fd8, "minecraft:magenta_dye" }, - { 0xf2b233, "minecraft:orange_dye" }, - { 0xf0f0f0, "minecraft:white_dye" }, -} - ---- Read the provided file into a string, exiting the program if not found. --- --- @tparam string file The file to read --- @treturn string The file's contents -local function read_all(file) - local h, e = io.open(file, "rb") - if not h then - io.stderr:write("Cannot open " .. file .. ": " .. tostring(e)) - os.exit(1) - end - - local c = h:read "*a" - h:close() - return c -end - ---- Write the provided string into a file, exiting on failure. --- --- @tparam string file The file to read --- @tparam string contents The new contents -local function write_all(file, contents) - local h, e = io.open(file, "wb") - if not h then - io.stderr:write("Cannot open " .. file .. ": " .. tostring(e)) - os.exit(1) - end - - h:write(contents) - h:close() -end - ---- Format template strings of the form `${key}` using the given substituion --- table. -local function template(str, subs) - return str:gsub("%$%{([^}]+)%}", function(k) - return subs[k] or error("Unknown key " .. k) - end) -end - --- Write turtle upgrades -local turtle_recipe = read_all "tools/turtle_upgrade_recipe.json" -local turtle_advance = read_all "tools/turtle_upgrade_advancement.json" -for _, turtle_family in ipairs { "normal", "advanced" } do - for _, upgrade in ipairs(turtle_upgrades) do - local upgrade_id, upgrade_item = upgrade[1], upgrade[2] or upgrade[1] - local path = ("generated/turtle_%s/%s"):format(turtle_family, (upgrade_id:gsub(":", "_"))) - local keys = { - upgrade_id = upgrade_id, upgrade_item = upgrade_item, - turtle_family = turtle_family, - path = path, - } - - write_all("src/main/resources/data/computercraft/recipes/" .. path .. ".json", template(turtle_recipe, keys)) - write_all("src/main/resources/data/computercraft/advancements/recipes/" .. path .. ".json", template(turtle_advance, keys)) - end -end - --- Write pocket upgrades -local pocket_recipe = read_all "tools/pocket_upgrade_recipe.json" -local pocket_advance = read_all "tools/pocket_upgrade_advancement.json" -for _, pocket_family in ipairs { "normal", "advanced" } do - for _, upgrade in ipairs(pocket_upgrades) do - local upgrade_id, upgrade_item = upgrade[1], upgrade[2] or upgrade[1] - local path = ("generated/pocket_%s/%s"):format(pocket_family, (upgrade_id:gsub(":", "_"))) - local keys = { - upgrade_id = upgrade_id, upgrade_item = upgrade_item, - pocket_family = pocket_family, - path = path, - } - - write_all("src/main/resources/data/computercraft/recipes/" .. path .. ".json", template(pocket_recipe, keys)) - write_all("src/main/resources/data/computercraft/advancements/recipes/" .. path .. ".json", template(pocket_advance, keys)) - end -end - --- Write disk recipe -local disk_recipe = read_all "tools/disk_recipe.json" -for i, colour in ipairs(colours) do - local path = ("generated/disk/disk_%s"):format(i) - local keys = { - dye = colour[2], colour = colour[1], - path = path, - } - - write_all("src/main/resources/data/computercraft/recipes/" .. path .. ".json", template(disk_recipe, keys)) -end diff --git a/tools/turtle_upgrade_advancement.json b/tools/turtle_upgrade_advancement.json deleted file mode 100644 index c671f4874..000000000 --- a/tools/turtle_upgrade_advancement.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:${path}" ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { "item": "computercraft:turtle_${turtle_family}" }, - { "item": "${upgrade_item}" } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:${path}" } - } - }, - "requirements": [ [ "has_items", "has_the_recipe" ] ] -} diff --git a/tools/turtle_upgrade_recipe.json b/tools/turtle_upgrade_recipe.json deleted file mode 100644 index d81b346cd..000000000 --- a/tools/turtle_upgrade_recipe.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:upgrade_turtle_${turtle_family}", - "pattern": [ - "#T" - ], - "key": { - "#": { "item": "${upgrade_item}" }, - "T": { "item": "computercraft:turtle_${turtle_family}" } - }, - "result": { "item": "computercraft:turtle_${turtle_family}", "nbt": { "RightUpgrade": "${upgrade_id}" } } -} From 03caf9d8056b8d1bf60cc9deec92408d138dfb8a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 29 Jan 2020 16:52:37 +0000 Subject: [PATCH 143/711] Fix a checkstyle warning --- build.gradle | 8 -------- .../java/dan200/computercraft/data/RecipeWrapper.java | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 52840a644..9d1f2f447 100644 --- a/build.gradle +++ b/build.gradle @@ -90,14 +90,6 @@ repositories { name "SquidDev" url "https://squiddev.cc/maven" } - ivy { - name "Charset" - artifactPattern "https://asie.pl/files/mods/Charset/LibOnly/[module]-[revision](-[classifier]).[ext]" - } - maven { - name "Amadornes" - url "https://maven.amadornes.com/" - } maven { name "CraftTweaker" url "https://maven.blamejared.com/" diff --git a/src/main/java/dan200/computercraft/data/RecipeWrapper.java b/src/main/java/dan200/computercraft/data/RecipeWrapper.java index f3252a39a..9451df12e 100644 --- a/src/main/java/dan200/computercraft/data/RecipeWrapper.java +++ b/src/main/java/dan200/computercraft/data/RecipeWrapper.java @@ -20,7 +20,7 @@ import java.util.function.Consumer; /** * Adapter for recipes which overrides the serializer and adds custom item NBT. */ -public class RecipeWrapper implements IFinishedRecipe +public final class RecipeWrapper implements IFinishedRecipe { private final IFinishedRecipe recipe; private final CompoundNBT resultData; From 05eada427bd99c34f2a9e126a7dbaa49bb2b5bb6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 30 Jan 2020 09:00:37 +0000 Subject: [PATCH 144/711] Add back custom block highlights Also bump Forge version to enable this --- gradle.properties | 2 +- .../proxy/ComputerCraftProxyClient.java | 7 ++- .../CableHighlightRenderer.java | 43 ++++++++----------- .../MonitorHighlightRenderer.java | 25 ++++++----- .../peripheral/monitor/TileMonitor.java | 5 +-- src/main/resources/META-INF/mods.toml | 2 +- 6 files changed, 36 insertions(+), 48 deletions(-) rename src/main/java/dan200/computercraft/client/{render_old => render}/CableHighlightRenderer.java (64%) rename src/main/java/dan200/computercraft/client/{render_old => render}/MonitorHighlightRenderer.java (86%) diff --git a/gradle.properties b/gradle.properties index cc2ce1680..ff2a4ac96 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.86.2 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 -forge_version=31.0.1 +forge_version=31.0.13 mappings_version=20200124-1.15.1 diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index b3cabf6cc..efdbd2e3e 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -41,10 +41,9 @@ public final class ComputerCraftProxyClient RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleNormal, RenderType.translucent() ); RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleAdvanced, RenderType.translucent() ); - // Monitors' textures have _entirely_ transparent sections which, while not translucent, requires being rendered - // as transparent. - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.translucent() ); - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.translucent() ); + // Monitors' textures have transparent fronts and so count as cutouts. + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.cutout() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.cutout() ); // Setup TESRs ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_NORMAL, TileEntityMonitorRenderer::new ); diff --git a/src/main/java/dan200/computercraft/client/render_old/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java similarity index 64% rename from src/main/java/dan200/computercraft/client/render_old/CableHighlightRenderer.java rename to src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index 556ab1d66..a780d5bdc 100644 --- a/src/main/java/dan200/computercraft/client/render_old/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -5,19 +5,20 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.BlockState; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.World; @@ -25,7 +26,6 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.DrawHighlightEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; -import org.lwjgl.opengl.GL11; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class CableHighlightRenderer @@ -38,7 +38,7 @@ public final class CableHighlightRenderer * Draw an outline for a specific part of a cable "Multipart". * * @param event The event to observe - * @see WorldRenderer#drawSelectionBox(ActiveRenderInfo, RayTraceResult, int) + * @see WorldRenderer#drawSelectionBox(MatrixStack, IVertexBuilder, Entity, double, double, double, BlockPos, BlockState) */ @SubscribeEvent public static void drawHighlight( DrawHighlightEvent.HighlightBlock event ) @@ -58,31 +58,22 @@ public final class CableHighlightRenderer event.setCanceled( true ); - Minecraft mc = Minecraft.getInstance(); - - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); - RenderSystem.lineWidth( Math.max( 2.5F, mc.getMainWindow().getFramebufferWidth() / 1920.0F * 2.5F ) ); - RenderSystem.disableTexture(); - RenderSystem.depthMask( false ); - RenderSystem.matrixMode( GL11.GL_PROJECTION ); - RenderSystem.pushMatrix(); - RenderSystem.scalef( 1.0F, 1.0F, 0.999F ); - VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); Vec3d cameraPos = info.getProjectedView(); - WorldRenderer.drawShape( - shape, pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ(), - 0.0F, 0.0F, 0.0F, 0.4F - ); + double xOffset = pos.getX() - cameraPos.getX(); + double yOffset = pos.getY() - cameraPos.getY(); + double zOffset = pos.getZ() - cameraPos.getZ(); - RenderSystem.popMatrix(); - RenderSystem.matrixMode( GL11.GL_MODELVIEW ); - RenderSystem.depthMask( true ); - RenderSystem.enableTexture(); - RenderSystem.disableBlend(); + IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.lines() ); + Matrix4f matrix4f = event.getMatrix().getLast().getPositionMatrix(); + shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> { + buffer.pos( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) ) + .color( 0, 0, 0, 0.4f ).endVertex(); + buffer.pos( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) ) + .color( 0, 0, 0, 0.4f ).endVertex(); + } ); } } diff --git a/src/main/java/dan200/computercraft/client/render_old/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java similarity index 86% rename from src/main/java/dan200/computercraft/client/render_old/MonitorHighlightRenderer.java rename to src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 1eb3d4625..7a5d7d0fd 100644 --- a/src/main/java/dan200/computercraft/client/render_old/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -9,7 +9,6 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.RenderType; import net.minecraft.tileentity.TileEntity; @@ -26,11 +25,13 @@ import java.util.EnumSet; import static net.minecraft.util.Direction.*; +/** + * Overrides monitor highlighting to only render the outline of the whole monitor, rather than the current + * block. This means you do not get an intrusive outline on top of the screen. + */ @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class MonitorHighlightRenderer { - private static final float EXPAND = 0.002f; - private MonitorHighlightRenderer() { } @@ -38,6 +39,7 @@ public final class MonitorHighlightRenderer @SubscribeEvent public static void drawHighlight( DrawHighlightEvent.HighlightBlock event ) { + // Preserve normal behaviour when crouching. if( event.getInfo().getRenderViewEntity().isCrouching() ) return; World world = event.getInfo().getRenderViewEntity().getEntityWorld(); @@ -58,12 +60,13 @@ public final class MonitorHighlightRenderer if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() ); if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() ); - IVertexBuilder buffer = Minecraft.getInstance().func_228019_au_().func_228487_b_().getBuffer( RenderType.lines() ); - + MatrixStack transformStack = event.getMatrix(); Vec3d cameraPos = event.getInfo().getProjectedView(); + transformStack.push(); transformStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); // I wish I could think of a better way to do this + IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.lines() ); Matrix4f transform = transformStack.getLast().getPositionMatrix(); if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 0, UP ); if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 1, UP ); @@ -83,15 +86,11 @@ public final class MonitorHighlightRenderer private static void line( IVertexBuilder buffer, Matrix4f transform, float x, float y, float z, Direction direction ) { - float minX = x == 0 ? -EXPAND : 1 + EXPAND; - float minY = y == 0 ? -EXPAND : 1 + EXPAND; - float minZ = z == 0 ? -EXPAND : 1 + EXPAND; - - buffer.pos( transform, minX, minY, minZ ).color( 0, 0, 0, 0.4f ).endVertex(); + buffer.pos( transform, x, y, z ).color( 0, 0, 0, 0.4f ).endVertex(); buffer.pos( transform, - minX + direction.getXOffset() * (1 + EXPAND * 2), - minY + direction.getYOffset() * (1 + EXPAND * 2), - minZ + direction.getZOffset() * (1 + EXPAND * 2) + x + direction.getXOffset(), + y + direction.getYOffset(), + z + direction.getZOffset() ).color( 0, 0, 0, 0.4f ).endVertex(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 6a1f01ed1..fa692be17 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -22,6 +22,7 @@ import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.World; @@ -653,13 +654,12 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile m_computers.remove( computer ); } - /* @Nonnull @Override public AxisAlignedBB getRenderBoundingBox() { TileMonitor start = getNeighbour( 0, 0 ); - TileMonitor end = getNeighbour( width - 1, height - 1 ); + TileMonitor end = getNeighbour( m_width - 1, m_height - 1 ); if( start != null && end != null ) { BlockPos startPos = start.getPos(); @@ -678,5 +678,4 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 ); } } - */ } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 70570cf08..94b6f2073 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[31.0.1,32)" + versionRange="[31.0.13,32)" ordering="NONE" side="BOTH" From 649acbae1c33bd5a54a7072ae000cfea9b988bec Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 30 Jan 2020 10:07:47 +0000 Subject: [PATCH 145/711] Add back item frame rendering for printouts Also fix a recipe loading issue, due to capitalisation of enums --- .../computercraft/client/gui/GuiPrintout.java | 12 +- .../ItemMapLikeRenderer.java | 28 +++-- .../ItemPrintoutRenderer.java | 65 +++++----- .../client/render/PrintoutRenderer.java | 118 ++++++++++-------- .../computercraft/shared/util/RecipeUtil.java | 22 +--- .../recipes/computer_advanced_upgrade.json | 2 +- .../pocket_computer_advanced_upgrade.json | 2 +- .../recipes/turtle_advanced.json | 2 +- .../recipes/turtle_advanced_upgrade.json | 2 +- .../computercraft/recipes/turtle_normal.json | 2 +- 10 files changed, 137 insertions(+), 118 deletions(-) rename src/main/java/dan200/computercraft/client/{render_old => render}/ItemMapLikeRenderer.java (80%) rename src/main/java/dan200/computercraft/client/{render_old => render}/ItemPrintoutRenderer.java (58%) diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 9c609be91..37927e62a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -9,7 +9,11 @@ import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.media.items.ItemPrintout; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; @@ -18,6 +22,8 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*; public class GuiPrintout extends ContainerScreen { + private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix(); + private final boolean m_book; private final int m_pages; private final TextBuffer[] m_text; @@ -91,8 +97,10 @@ public class GuiPrintout extends ContainerScreen RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.enableDepthTest(); - drawBorder( guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book ); - drawText( guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); + IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); + drawBorder( IDENTITY, renderer, guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book ); + drawText( IDENTITY, renderer, guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); + renderer.finish(); } @Override diff --git a/src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java similarity index 80% rename from src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java rename to src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index 8a5472c99..f25deea79 100644 --- a/src/main/java/dan200/computercraft/client/render_old/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -52,13 +52,16 @@ public abstract class ItemMapLikeRenderer /** * Renders the item to one side of the player. * + * @param transform The matrix transformation stack + * @param render The buffer to render to + * @param combinedLight The current light level * @param side The side to render on * @param equipProgress The equip progress of this item * @param swingProgress The swing progress of this item * @param stack The stack to render * @see FirstPersonRenderer#renderMapFirstPersonSide(MatrixStack, IRenderTypeBuffer, int, float, HandSide, float, ItemStack) */ - private void renderItemFirstPersonSide( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, HandSide side, float equipProgress, float swingProgress, ItemStack stack ) + private void renderItemFirstPersonSide( MatrixStack transform, IRenderTypeBuffer render, int combinedLight, HandSide side, float equipProgress, float swingProgress, ItemStack stack ) { Minecraft minecraft = Minecraft.getInstance(); float offset = side == HandSide.RIGHT ? 1f : -1f; @@ -68,8 +71,8 @@ public abstract class ItemMapLikeRenderer if( !minecraft.player.isInvisible() ) { transform.push(); - transform.rotate( Vector3f.field_229183_f_.func_229187_a_( offset * 10f ) ); - minecraft.getFirstPersonRenderer().renderArmFirstPerson( transform, render, lightTexture, equipProgress, swingProgress, side ); + transform.rotate( Vector3f.ZP.rotationDegrees( offset * 10f ) ); + minecraft.getFirstPersonRenderer().renderArmFirstPerson( transform, render, combinedLight, equipProgress, swingProgress, side ); transform.pop(); } @@ -83,8 +86,8 @@ public abstract class ItemMapLikeRenderer float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) ); float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI ); transform.translate( offset * f3, f4 - 0.3f * f2, f5 ); - transform.rotate( Vector3f.field_229179_b_.func_229187_a_( f2 * -45f ) ); - transform.rotate( Vector3f.field_229181_d_.func_229187_a_( offset * f2 * -30f ) ); + transform.rotate( Vector3f.XP.rotationDegrees( f2 * -45f ) ); + transform.rotate( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) ); renderItem( transform, render, stack ); @@ -94,13 +97,16 @@ public abstract class ItemMapLikeRenderer /** * Render an item in the middle of the screen. * + * @param transform The matrix transformation stack + * @param render The buffer to render to + * @param combinedLight The current light level * @param pitch The pitch of the player * @param equipProgress The equip progress of this item * @param swingProgress The swing progress of this item * @param stack The stack to render * @see FirstPersonRenderer#renderMapFirstPerson(MatrixStack, IRenderTypeBuffer, int, float, float, float) */ - private void renderItemFirstPersonCenter( MatrixStack transform, IRenderTypeBuffer render, int lightTexture, float pitch, float equipProgress, float swingProgress, ItemStack stack ) + private void renderItemFirstPersonCenter( MatrixStack transform, IRenderTypeBuffer render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack ) { Minecraft minecraft = Minecraft.getInstance(); FirstPersonRenderer renderer = minecraft.getFirstPersonRenderer(); @@ -114,18 +120,18 @@ public abstract class ItemMapLikeRenderer float pitchAngle = renderer.getMapAngleFromPitch( pitch ); transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f ); - transform.rotate( Vector3f.field_229179_b_.func_229187_a_( pitchAngle * -85.0f ) ); + transform.rotate( Vector3f.XP.rotationDegrees( pitchAngle * -85.0f ) ); if( !minecraft.player.isInvisible() ) { transform.push(); - transform.rotate( Vector3f.field_229181_d_.func_229187_a_( 90.0F ) ); - renderer.renderArm( transform, render, lightTexture, HandSide.RIGHT ); - renderer.renderArm( transform, render, lightTexture, HandSide.LEFT ); + transform.rotate( Vector3f.YP.rotationDegrees( 90.0F ) ); + renderer.renderArm( transform, render, combinedLight, HandSide.RIGHT ); + renderer.renderArm( transform, render, combinedLight, HandSide.LEFT ); transform.pop(); } float rX = MathHelper.sin( swingRt * (float) Math.PI ); - transform.rotate( Vector3f.field_229179_b_.func_229187_a_( rX * 20.0F ) ); + transform.rotate( Vector3f.XP.rotationDegrees( rX * 20.0F ) ); transform.scale( 2.0F, 2.0F, 2.0F ); renderItem( transform, render, stack ); diff --git a/src/main/java/dan200/computercraft/client/render_old/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java similarity index 58% rename from src/main/java/dan200/computercraft/client/render_old/ItemPrintoutRenderer.java rename to src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index eee8e191d..65c2c8e99 100644 --- a/src/main/java/dan200/computercraft/client/render_old/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -5,13 +5,16 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.matrix.MatrixStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemPrintout; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.Vector3f; import net.minecraft.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.client.event.RenderItemInFrameEvent; -import net.minecraftforge.client.event.RenderSpecificHandEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -33,31 +36,28 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { } - @SubscribeEvent - public static void onRenderInHand( RenderSpecificHandEvent event ) + // TODO: @SubscribeEvent + public static void onRenderInHand( RenderHandEvent event ) { ItemStack stack = event.getItemStack(); if( !(stack.getItem() instanceof ItemPrintout) ) return; event.setCanceled( true ); - INSTANCE.renderItemFirstPerson( event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() ); + INSTANCE.renderItemFirstPerson( + event.getMatrixStack(), event.getBuffers(), event.getLight(), + event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() + ); } @Override - protected void renderItem( ItemStack stack ) + protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ) { - // Setup various transformations. Note that these are partially adapated from the corresponding method - // in FirstPersonRenderer.renderFirstPersonMap - RenderSystem.disableLighting(); + transform.rotate( Vector3f.XP.rotationDegrees( 180f ) ); + transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) ); + transform.scale( 0.42f, 0.42f, -0.42f ); + transform.translate( -0.5f, -0.48f, 0.0f ); - RenderSystem.rotatef( 180f, 0f, 1f, 0f ); - RenderSystem.rotatef( 180f, 0f, 0f, 1f ); - RenderSystem.scalef( 0.42f, 0.42f, -0.42f ); - RenderSystem.translatef( -0.5f, -0.48f, 0.0f ); - - drawPrintout( stack ); - - RenderSystem.enableLighting(); + drawPrintout( transform, render, stack ); } @SubscribeEvent @@ -65,24 +65,20 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { ItemStack stack = event.getItem(); if( !(stack.getItem() instanceof ItemPrintout) ) return; - event.setCanceled( true ); - RenderSystem.disableLighting(); + MatrixStack transform = event.getMatrix(); // Move a little bit forward to ensure we're not clipping with the frame - RenderSystem.translatef( 0.0f, 0.0f, -0.001f ); - RenderSystem.rotatef( 180f, 0f, 0f, 1f ); - RenderSystem.scalef( 0.95f, 0.95f, -0.95f ); - RenderSystem.translatef( -0.5f, -0.5f, 0.0f ); + transform.translate( 0.0f, 0.0f, -0.001f ); + transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) ); + transform.scale( 0.95f, 0.95f, -0.95f ); + transform.translate( -0.5f, -0.5f, 0.0f ); - drawPrintout( stack ); - - RenderSystem.enableLighting(); - RenderSystem.disableBlend(); + drawPrintout( transform, event.getBuffers(), stack ); } - private static void drawPrintout( ItemStack stack ) + private static void drawPrintout( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ) { int pages = ItemPrintout.getPageCount( stack ); boolean book = ((ItemPrintout) stack.getItem()).getType() == ItemPrintout.Type.BOOK; @@ -105,11 +101,14 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer double max = Math.max( visualHeight, visualWidth ); // Scale the printout to fit correctly. - double scale = 1.0 / max; - RenderSystem.scaled( scale, scale, scale ); - RenderSystem.translated( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); + float scale = (float) (1.0 / max); + transform.scale( scale, scale, scale ); + transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); - drawBorder( 0, 0, -0.01, 0, pages, book ); - drawText( X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) ); + Matrix4f matrix = transform.getLast().getPositionMatrix(); + drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book ); + drawText( matrix, render, + X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) + ); } } diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index b1e81a556..bbe95c9c0 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -5,15 +5,14 @@ */ package dan200.computercraft.client.render; -import com.mojang.blaze3d.platform.GlStateManager.DestFactor; -import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; -import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.RenderState; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; @@ -61,66 +60,71 @@ public final class PrintoutRenderer private PrintoutRenderer() {} - public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) + public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) { + IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) { - FixedWidthFontRenderer.drawString( + FixedWidthFontRenderer.drawString( transform, buffer, x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT, false, 0, 0 ); } } - public static void drawBorder( double x, double y, double z, int page, int pages, boolean isBook ) + public static void drawText( Matrix4f transform, IRenderTypeBuffer renderer, int x, int y, int start, String[] text, String[] colours ) { - RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - RenderSystem.enableBlend(); - RenderSystem.enableTexture(); - RenderSystem.blendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); - - Minecraft.getInstance().getTextureManager().bindTexture( BG ); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX ); + IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); + for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) + { + FixedWidthFontRenderer.drawString( transform, buffer, + x, y + line * FONT_HEIGHT, + new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ), + null, Palette.DEFAULT, false, 0, 0 + ); + } + } + public static void drawBorder( Matrix4f transform, IRenderTypeBuffer renderer, float x, float y, float z, int page, int pages, boolean isBook ) + { int leftPages = page; int rightPages = pages - page - 1; + IVertexBuilder buffer = renderer.getBuffer( Type.TYPE ); + if( isBook ) { // Border - double offset = offsetAt( pages ); - final double left = x - 4 - offset; - final double right = x + X_SIZE + offset - 4; + float offset = offsetAt( pages ); + float left = x - 4 - offset; + float right = x + X_SIZE + offset - 4; // Left and right border - drawTexture( buffer, left - 4, y - 8, z - 0.02, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); - drawTexture( buffer, right, y - 8, z - 0.02, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); + drawTexture( transform, buffer, left - 4, y - 8, z - 0.02f, COVER_X, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); + drawTexture( transform, buffer, right, y - 8, z - 0.02f, COVER_X + COVER_SIZE, 0, COVER_SIZE, Y_SIZE + COVER_SIZE * 2 ); // Draw centre panel (just stretched texture, sorry). - drawTexture( buffer, - x - offset, y, z - 0.02, X_SIZE + offset * 2, Y_SIZE, + drawTexture( transform, buffer, + x - offset, y, z - 0.02f, X_SIZE + offset * 2, Y_SIZE, COVER_X + COVER_SIZE / 2.0f, COVER_SIZE, COVER_SIZE, Y_SIZE ); - double borderX = left; + float borderX = left; while( borderX < right ) { double thisWidth = Math.min( right - borderX, X_SIZE ); - drawTexture( buffer, borderX, y - 8, z - 0.02, 0, COVER_Y, (float) thisWidth, COVER_SIZE ); - drawTexture( buffer, borderX, y + Y_SIZE - 4, z - 0.02, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE ); + drawTexture( transform, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE ); + drawTexture( transform, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE ); borderX += thisWidth; } } // Left half - drawTexture( buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE ); + drawTexture( transform, buffer, x, y, z, X_FOLD_SIZE * 2, 0, X_SIZE / 2.0f, Y_SIZE ); for( int n = 0; n <= leftPages; n++ ) { - drawTexture( buffer, - x - offsetAt( n ), y, z - 1e-3 * n, + drawTexture( transform, buffer, + x - offsetAt( n ), y, z - 1e-3f * n, // Use the left "bold" fold for the outermost page n == leftPages ? 0 : X_FOLD_SIZE, 0, X_FOLD_SIZE, Y_SIZE @@ -128,38 +132,54 @@ public final class PrintoutRenderer } // Right half - drawTexture( buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE ); + drawTexture( transform, buffer, x + X_SIZE / 2.0f, y, z, X_FOLD_SIZE * 2 + X_SIZE / 2.0f, 0, X_SIZE / 2.0f, Y_SIZE ); for( int n = 0; n <= rightPages; n++ ) { - drawTexture( buffer, - x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3 * n, + drawTexture( transform, buffer, + x + (X_SIZE - X_FOLD_SIZE) + offsetAt( n ), y, z - 1e-3f * n, // Two folds, then the main page. Use the right "bold" fold for the outermost page. X_FOLD_SIZE * 2 + X_SIZE + (n == rightPages ? X_FOLD_SIZE : 0), 0, X_FOLD_SIZE, Y_SIZE ); } - - tessellator.draw(); } - private static void drawTexture( BufferBuilder buffer, double x, double y, double z, float u, float v, float width, float height ) + private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float u, float v, float width, float height ) { - buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); - buffer.pos( x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); - buffer.pos( x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex(); - buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); + buffer.pos( matrix, x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); + buffer.pos( matrix, x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex(); + buffer.pos( matrix, x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex(); + buffer.pos( matrix, x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); } - private static void drawTexture( BufferBuilder buffer, double x, double y, double z, double width, double height, float u, float v, float tWidth, float tHeight ) + private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight ) { - buffer.pos( x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); - buffer.pos( x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); - buffer.pos( x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex(); - buffer.pos( x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); + buffer.pos( matrix, x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); + buffer.pos( matrix, x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex(); + buffer.pos( matrix, x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex(); + buffer.pos( matrix, x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex(); } - public static double offsetAt( int page ) + public static float offsetAt( int page ) { - return 32 * (1 - Math.pow( 1.2, -page )); + return (float) (32 * (1 - Math.pow( 1.2, -page ))); + } + + private static final class Type extends RenderState + { + static final RenderType TYPE = RenderType.get( + "printout_background", DefaultVertexFormats.POSITION_TEX, GL11.GL_QUADS, 1024, + false, false, // useDelegate, needsSorting + RenderType.State.builder() + .texture( new RenderState.TextureState( BG, false, false ) ) // blur, minimap + .alpha( DEFAULT_ALPHA ) + .lightmap( LIGHTMAP_DISABLED ) + .build( false ) + ); + + private Type( String name, Runnable setup, Runnable destroy ) + { + super( name, setup, destroy ); + } } } diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index 1f4179a77..f570adaec 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -103,28 +103,14 @@ public final class RecipeUtil return new ShapedTemplate( width, height, ingredients ); } - public static NonNullList getIngredients( JsonObject json ) - { - NonNullList ingredients = NonNullList.create(); - for( JsonElement ele : JSONUtils.getJsonArray( json, "ingredients" ) ) - { - ingredients.add( Ingredient.deserialize( ele ) ); - } - - if( ingredients.isEmpty() ) throw new JsonParseException( "No ingredients for recipe" ); - return ingredients; - } - public static ComputerFamily getFamily( JsonObject json, String name ) { String familyName = JSONUtils.getString( json, name ); - try + for( ComputerFamily family : ComputerFamily.values() ) { - return ComputerFamily.valueOf( familyName ); - } - catch( IllegalArgumentException e ) - { - throw new JsonSyntaxException( "Unknown computer family '" + familyName + "' for field " + name ); + if( family.name().equalsIgnoreCase( familyName ) ) return family; } + + throw new JsonSyntaxException( "Unknown computer family '" + familyName + "' for field " + name ); } } diff --git a/src/main/resources/data/computercraft/recipes/computer_advanced_upgrade.json b/src/main/resources/data/computercraft/recipes/computer_advanced_upgrade.json index e6de6b37e..eb0b5c792 100644 --- a/src/main/resources/data/computercraft/recipes/computer_advanced_upgrade.json +++ b/src/main/resources/data/computercraft/recipes/computer_advanced_upgrade.json @@ -9,6 +9,6 @@ "#": { "tag": "forge:ingots/gold" }, "C": { "item": "computercraft:computer_normal" } }, - "family": "Advanced", + "family": "advanced", "result": { "item": "computercraft:computer_advanced" } } diff --git a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json b/src/main/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json index 79ee81b41..3409ce78f 100644 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json +++ b/src/main/resources/data/computercraft/recipes/pocket_computer_advanced_upgrade.json @@ -9,6 +9,6 @@ "#": { "tag": "forge:ingots/gold" }, "C": { "item": "computercraft:pocket_computer_normal" } }, - "family": "Advanced", + "family": "advanced", "result": { "item": "computercraft:pocket_computer_advanced" } } diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced.json b/src/main/resources/data/computercraft/recipes/turtle_advanced.json index 7da7f9017..1325043f6 100644 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced.json +++ b/src/main/resources/data/computercraft/recipes/turtle_advanced.json @@ -10,6 +10,6 @@ "C": { "item": "computercraft:computer_advanced" }, "I": { "tag": "forge:chests/wooden" } }, - "family": "Advanced", + "family": "advanced", "result": { "item": "computercraft:turtle_advanced" } } diff --git a/src/main/resources/data/computercraft/recipes/turtle_advanced_upgrade.json b/src/main/resources/data/computercraft/recipes/turtle_advanced_upgrade.json index 79f4444ea..294854de1 100644 --- a/src/main/resources/data/computercraft/recipes/turtle_advanced_upgrade.json +++ b/src/main/resources/data/computercraft/recipes/turtle_advanced_upgrade.json @@ -10,6 +10,6 @@ "B": { "tag": "forge:storage_blocks/gold" }, "C": { "item": "computercraft:turtle_normal" } }, - "family": "Advanced", + "family": "advanced", "result": { "item": "computercraft:turtle_advanced" } } diff --git a/src/main/resources/data/computercraft/recipes/turtle_normal.json b/src/main/resources/data/computercraft/recipes/turtle_normal.json index f432bdf3c..00a6cddc6 100644 --- a/src/main/resources/data/computercraft/recipes/turtle_normal.json +++ b/src/main/resources/data/computercraft/recipes/turtle_normal.json @@ -10,6 +10,6 @@ "C": { "item": "computercraft:computer_normal" }, "I": { "tag": "forge:chests/wooden" } }, - "family": "Normal", + "family": "normal", "result": { "item": "computercraft:turtle_normal" } } From bf13bac1527a696eca90c1599a59920e66103c21 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 4 Feb 2020 16:41:29 +0000 Subject: [PATCH 146/711] Update illuaminate config --- illuaminate.sexp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index d6865618c..cda3d0a85 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -13,7 +13,12 @@ ;; It's useful to name arguments for documentation, so we allow this. It'd ;; be good to find a compromise in the future, but this works for now. - -var:unused-arg)) + -var:unused-arg + + ;; Suppress a couple of documentation comments warnings for now. We'll + ;; hopefully be able to remove them in the coming weeks. + -doc:detached-comment -doc:undocumented -doc:undocumented-arg + -doc:unresolved-reference)) ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. From 930fd59298748d283b1200ed682b275db2e695dc Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 4 Feb 2020 16:53:22 +0000 Subject: [PATCH 147/711] Remove dvs1 as a maven repository This thing consistently goes down and breaks the build. For now, let's just rehost it on squiddev.cc/maven. --- build.gradle | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build.gradle b/build.gradle index 3ada5933e..f2fa11e96 100644 --- a/build.gradle +++ b/build.gradle @@ -43,10 +43,6 @@ minecraft { } repositories { - maven { - name "JEI" - url "https://dvs1.progwml6.com/files/maven" - } maven { name "SquidDev" url "https://squiddev.cc/maven" From 8eae02c03735a324afc67e955d930b6a43bcfe69 Mon Sep 17 00:00:00 2001 From: Fatboychummy <39929480+fatboychummy@users.noreply.github.com> Date: Tue, 4 Feb 2020 10:00:49 -0700 Subject: [PATCH 148/711] Fire mouse_up events in monitor.lua (#358) We schedule a mouse_up event 0.1 seconds after receiving a monitor_touch event. --- .../assets/computercraft/lua/rom/programs/monitor.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua index 16afddd29..8860d8bde 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua @@ -39,6 +39,8 @@ local function resume( ... ) return param end +local timers = {} + local ok, param = pcall( function() local sFilter = resume() while coroutine.status( co ) ~= "dead" do @@ -48,6 +50,7 @@ local ok, param = pcall( function() end if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then if tEvent[1] == "monitor_touch" and tEvent[2] == sName then + timers[os.startTimer( 0.1 )] = { tEvent[3], tEvent[4] } sFilter = resume( "mouse_click", 1, table.unpack( tEvent, 3, tEvent.n ) ) end end @@ -56,6 +59,12 @@ local ok, param = pcall( function() sFilter = resume( "term_resize" ) end end + if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then + if tEvent[1] == "timer" and timers[tEvent[2]] then + sFilter = resume( "mouse_up", 1, table.unpack( timers[tEvent[2]], 1, 2 ) ) + timers[tEvent[2]] = nil + end + end end end ) From be89fc25f9dbb80206b4d5aab4f8ea44e22d81ab Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 7 Feb 2020 14:17:09 +0000 Subject: [PATCH 149/711] Prevent copying folders inside themselves - contains now performs a case-insensitive comparison. While this is a little dubious, it's required for systems like Windows, where foo and Foo are the same folder. - Impose a depth limit on copyRecursive. If there are any other cases where we may try to copy a folder into itself, this should prevent the computer entirely crashing. --- .../filesystem/FileOperationException.java | 2 +- .../core/filesystem/FileSystem.java | 25 ++++++++++++------- .../core/computer/BasicEnvironment.java | 2 +- .../resources/test-rom/spec/apis/fs_spec.lua | 15 +++++++++++ 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index 703a95911..70a25fe5f 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -27,7 +27,7 @@ public class FileOperationException extends IOException this.filename = filename; } - public FileOperationException( String message ) + public FileOperationException( @Nonnull String message ) { super( Objects.requireNonNull( message, "message cannot be null" ) ); this.filename = null; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 4f6f84cd3..eda0361bd 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -29,6 +29,14 @@ import java.util.regex.Pattern; public class FileSystem { + /** + * Maximum depth that {@link #copyRecursive(String, MountWrapper, String, MountWrapper, int)} will descend into. + * + * This is a pretty arbitrary value, though hopefully it is large enough that it'll never be normally hit. This + * exists to prevent it overflowing if it ever gets into an infinite loop. + */ + private static final int MAX_COPY_DEPTH = 128; + private static class MountWrapper { private String m_label; @@ -611,15 +619,13 @@ public class FileSystem { throw new FileSystemException( "/" + sourcePath + ": Can't copy a directory inside itself" ); } - copyRecursive( sourcePath, getMount( sourcePath ), destPath, getMount( destPath ) ); + copyRecursive( sourcePath, getMount( sourcePath ), destPath, getMount( destPath ), 0 ); } - private synchronized void copyRecursive( String sourcePath, MountWrapper sourceMount, String destinationPath, MountWrapper destinationMount ) throws FileSystemException + private synchronized void copyRecursive( String sourcePath, MountWrapper sourceMount, String destinationPath, MountWrapper destinationMount, int depth ) throws FileSystemException { - if( !sourceMount.exists( sourcePath ) ) - { - return; - } + if( !sourceMount.exists( sourcePath ) ) return; + if( depth >= MAX_COPY_DEPTH ) throw new FileSystemException( "Too many directories to copy" ); if( sourceMount.isDirectory( sourcePath ) ) { @@ -634,7 +640,8 @@ public class FileSystem { copyRecursive( combine( sourcePath, child ), sourceMount, - combine( destinationPath, child ), destinationMount + combine( destinationPath, child ), destinationMount, + depth + 1 ); } } @@ -854,8 +861,8 @@ public class FileSystem public static boolean contains( String pathA, String pathB ) { - pathA = sanitizePath( pathA ); - pathB = sanitizePath( pathB ); + pathA = sanitizePath( pathA ).toLowerCase( Locale.ROOT ); + pathB = sanitizePath( pathB ).toLowerCase( Locale.ROOT ); if( pathB.equals( ".." ) ) { diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index cc6cebd3f..f3caa0856 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -116,7 +116,7 @@ public class BasicEnvironment implements IComputerEnvironment while( baseFile != null && !wholeFile.exists() ) { baseFile = baseFile.getParentFile(); - wholeFile = new File( baseFile, "resources/" + fallback + "/" + path ); + wholeFile = new File( baseFile, "src/" + fallback + "/resources/" + path ); } if( !wholeFile.exists() ) throw new IllegalStateException( "Cannot find ROM mount at " + file ); diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index ad1bfb41c..f6ccac6bc 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -125,6 +125,21 @@ describe("The fs library", function() it("fails on read-only mounts", function() expect.error(fs.copy, "rom", "rom/startup"):eq("/rom/startup: Access denied") end) + + it("fails to copy a folder inside itself", function() + fs.makeDir("some-folder") + expect.error(fs.copy, "some-folder", "some-folder/x"):eq("/some-folder: Can't copy a directory inside itself") + expect.error(fs.copy, "some-folder", "Some-Folder/x"):eq("/some-folder: Can't copy a directory inside itself") + end) + + it("copies folders", function() + fs.delete("some-folder") + fs.delete("another-folder") + + fs.makeDir("some-folder") + fs.copy("some-folder", "another-folder") + expect(fs.isDir("another-folder")):eq(true) + end) end) describe("fs.move", function() From 79f42e35ce8b60f16b77082f6dab63ecf365f188 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 7 Feb 2020 14:50:51 +0000 Subject: [PATCH 150/711] Add a timeout to websocket.receive - Move timer handling to IAPIEnvironment, rather than OSAPI. This means the environment is reset on startup/shutdown, much like normal APIs. - Websocket.receive now accepts an optional timetout (much like rednet.receive). This starts a timer, and waits for it to complete. Closes #201 --- .../core/apis/IAPIEnvironment.java | 6 ++ .../dan200/computercraft/core/apis/OSAPI.java | 70 +++--------------- .../apis/http/websocket/WebsocketHandle.java | 24 +++++++ .../computercraft/core/computer/Computer.java | 2 +- .../core/computer/ComputerExecutor.java | 2 + .../core/computer/Environment.java | 72 ++++++++++++++++++- 6 files changed, 111 insertions(+), 65 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 00b5ebf8d..0a4315960 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -18,6 +18,8 @@ import javax.annotation.Nullable; public interface IAPIEnvironment { + String TIMER_EVENT = "timer"; + @FunctionalInterface interface IPeripheralChangeListener { @@ -64,6 +66,10 @@ public interface IAPIEnvironment void setLabel( @Nullable String label ); + int startTimer( long ticks ); + + void cancelTimer( int id ); + void addTrackingChange( @Nonnull TrackingField field, long change ); default void addTrackingChange( @Nonnull TrackingField field ) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index e1bc5c1ab..71577a127 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -9,6 +9,8 @@ import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.shared.util.StringUtil; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import javax.annotation.Nonnull; import java.time.Instant; @@ -24,24 +26,12 @@ public class OSAPI implements ILuaAPI { private IAPIEnvironment m_apiEnvironment; - private final Map m_timers; - private final Map m_alarms; + private final Int2ObjectMap m_alarms = new Int2ObjectOpenHashMap<>(); private int m_clock; private double m_time; private int m_day; - private int m_nextTimerToken; - private int m_nextAlarmToken; - - private static class Timer - { - int m_ticksLeft; - - Timer( int ticksLeft ) - { - m_ticksLeft = ticksLeft; - } - } + private int m_nextAlarmToken = 0; private static class Alarm implements Comparable { @@ -66,10 +56,6 @@ public class OSAPI implements ILuaAPI public OSAPI( IAPIEnvironment environment ) { m_apiEnvironment = environment; - m_nextTimerToken = 0; - m_nextAlarmToken = 0; - m_timers = new HashMap<>(); - m_alarms = new HashMap<>(); } // ILuaAPI implementation @@ -87,11 +73,6 @@ public class OSAPI implements ILuaAPI m_day = m_apiEnvironment.getComputerEnvironment().getDay(); m_clock = 0; - synchronized( m_timers ) - { - m_timers.clear(); - } - synchronized( m_alarms ) { m_alarms.clear(); @@ -101,26 +82,7 @@ public class OSAPI implements ILuaAPI @Override public void update() { - synchronized( m_timers ) - { - // Update the clock - m_clock++; - - // Countdown all of our active timers - Iterator> it = m_timers.entrySet().iterator(); - while( it.hasNext() ) - { - Map.Entry entry = it.next(); - Timer timer = entry.getValue(); - timer.m_ticksLeft--; - if( timer.m_ticksLeft <= 0 ) - { - // Queue the "timer" event - queueLuaEvent( "timer", new Object[] { entry.getKey() } ); - it.remove(); - } - } - } + m_clock++; // Wait for all of our alarms synchronized( m_alarms ) @@ -155,11 +117,6 @@ public class OSAPI implements ILuaAPI @Override public void shutdown() { - synchronized( m_timers ) - { - m_timers.clear(); - } - synchronized( m_alarms ) { m_alarms.clear(); @@ -229,11 +186,8 @@ public class OSAPI implements ILuaAPI { // startTimer double timer = getFiniteDouble( args, 0 ); - synchronized( m_timers ) - { - m_timers.put( m_nextTimerToken, new Timer( (int) Math.round( timer / 0.05 ) ) ); - return new Object[] { m_nextTimerToken++ }; - } + int id = m_apiEnvironment.startTimer( Math.round( timer / 0.05 ) ); + return new Object[] { id }; } case 2: { @@ -278,10 +232,7 @@ public class OSAPI implements ILuaAPI return null; } case 10: // clock - synchronized( m_timers ) - { - return new Object[] { m_clock * 0.05 }; - } + return new Object[] { m_clock * 0.05 }; case 11: { // time @@ -345,10 +296,7 @@ public class OSAPI implements ILuaAPI { // cancelTimer int token = getInt( args, 0 ); - synchronized( m_timers ) - { - m_timers.remove( token ); - } + m_apiEnvironment.cancelTimer( token ); return null; } case 14: diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index 976b526c2..8433d30c3 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.http.websocket; import com.google.common.base.Objects; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaObject; import dan200.computercraft.api.lua.LuaException; @@ -23,6 +24,7 @@ import java.io.Closeable; import java.util.Arrays; import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; +import static dan200.computercraft.core.apis.IAPIEnvironment.TIMER_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT; @@ -53,7 +55,21 @@ public class WebsocketHandle implements ILuaObject, Closeable switch( method ) { case 0: // receive + { checkOpen(); + int timeoutId; + if( arguments.length <= 0 || arguments[0] == null ) + { + // We do this rather odd argument validation to ensure we can tell the difference between a + // negative timeout and an absent one. + timeoutId = -1; + } + else + { + double timeout = ArgumentHelper.getFiniteDouble( arguments, 0 ); + timeoutId = websocket.environment().startTimer( Math.round( timeout / 0.05 ) ); + } + while( true ) { Object[] event = context.pullEvent( null ); @@ -63,9 +79,17 @@ public class WebsocketHandle implements ILuaObject, Closeable } else if( event.length >= 2 && Objects.equal( event[0], CLOSE_EVENT ) && Objects.equal( event[1], websocket.address() ) && closed ) { + // If the socket is closed abort. + return null; + } + else if( event.length >= 2 && timeoutId != -1 && Objects.equal( event[0], TIMER_EVENT ) + && event[1] instanceof Number && ((Number) event[1]).intValue() == timeoutId ) + { + // If we received a matching timer event then abort. return null; } } + } case 1: // send { diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index cacb755d1..316917535 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -183,7 +183,7 @@ public class Computer executor.tick(); // Update the environment's internal state. - internalEnvironment.update(); + internalEnvironment.tick(); // Propagate the environment's output to the world. if( internalEnvironment.updateOutput() ) externalOutputChanged.set( true ); diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index 0da3b2d65..a50b390e4 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -435,6 +435,7 @@ final class ComputerExecutor } // Init APIs + computer.getEnvironment().reset(); for( ILuaAPI api : apis ) api.startup(); // Init lua @@ -478,6 +479,7 @@ final class ComputerExecutor // Shutdown our APIs for( ILuaAPI api : apis ) api.shutdown(); + computer.getEnvironment().reset(); // Unload filesystem if( fileSystem != null ) diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index 35a79ee4d..819997c92 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.core.computer; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.core.apis.IAPIEnvironment; @@ -12,9 +13,12 @@ import dan200.computercraft.core.filesystem.FileSystem; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.core.tracking.TrackingField; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import javax.annotation.Nonnull; import java.util.Arrays; +import java.util.Iterator; /** * Represents the "environment" that a {@link Computer} exists in. @@ -53,6 +57,9 @@ public final class Environment implements IAPIEnvironment private final IPeripheral[] peripherals = new IPeripheral[ComputerSide.COUNT]; private IPeripheralChangeListener peripheralListener = null; + private final Int2ObjectMap timers = new Int2ObjectOpenHashMap<>(); + private int nextTimerToken = 0; + Environment( Computer computer ) { this.computer = computer; @@ -198,17 +205,47 @@ public final class Environment implements IAPIEnvironment } /** - * Called on the main thread to update the internal state of the computer. + * Called when the computer starts up or shuts down, to reset any internal state. * - * This just queues a {@code redstone} event if the input has changed. + * @see ILuaAPI#startup() + * @see ILuaAPI#shutdown() */ - void update() + void reset() + { + synchronized( timers ) + { + timers.clear(); + } + } + + /** + * Called on the main thread to update the internal state of the computer. + */ + void tick() { if( inputChanged ) { inputChanged = false; queueEvent( "redstone", null ); } + + synchronized( timers ) + { + // Countdown all of our active timers + Iterator> it = timers.int2ObjectEntrySet().iterator(); + while( it.hasNext() ) + { + Int2ObjectMap.Entry entry = it.next(); + Timer timer = entry.getValue(); + timer.ticksLeft--; + if( timer.ticksLeft <= 0 ) + { + // Queue the "timer" event + queueEvent( TIMER_EVENT, new Object[] { entry.getIntKey() } ); + it.remove(); + } + } + } } /** @@ -303,9 +340,38 @@ public final class Environment implements IAPIEnvironment computer.setLabel( label ); } + @Override + public int startTimer( long ticks ) + { + synchronized( timers ) + { + timers.put( nextTimerToken, new Timer( ticks ) ); + return nextTimerToken++; + } + } + + @Override + public void cancelTimer( int id ) + { + synchronized( timers ) + { + timers.remove( id ); + } + } + @Override public void addTrackingChange( @Nonnull TrackingField field, long change ) { Tracking.addValue( computer, field, change ); } + + private static class Timer + { + long ticksLeft; + + Timer( long ticksLeft ) + { + this.ticksLeft = ticksLeft; + } + } } From b4e0e9984f2b7c8e44c7c12959eaec2bcf7ff79e Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 8 Feb 2020 11:02:09 +0000 Subject: [PATCH 151/711] Try to get CI working again - Mirror all dependencies, like we've done on master - Run gradle build twice. Apparently the first time the dependencies aren't always available. --- .github/workflows/main-ci.yml | 4 ++-- build.gradle | 14 +++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index d0caedbf2..dd66a8bcb 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up JDK 1.8 uses: actions/setup-java@v1 @@ -16,7 +16,7 @@ jobs: java-version: 1.8 - name: Build with Gradle - run: ./gradlew build --no-daemon + run: ./gradlew build --no-daemon || ./gradlew build --no-daemon - name: Upload Jar uses: actions/upload-artifact@v1 diff --git a/build.gradle b/build.gradle index 9d1f2f447..f3b3c7693 100644 --- a/build.gradle +++ b/build.gradle @@ -82,18 +82,10 @@ sourceSets.main.resources { } repositories { - maven { - name "JEI" - url "https://dvs1.progwml6.com/files/maven" - } maven { name "SquidDev" url "https://squiddev.cc/maven" } - maven { - name "CraftTweaker" - url "https://maven.blamejared.com/" - } } configurations { @@ -107,10 +99,10 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.25:api") - compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.14.4:5.0.1.150") + compileOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.27:api") + compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.14.4:5.0.1.162") - runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.25") + runtimeOnly fg.deobf("mezz.jei:jei-1.14.4:6.0.0.27") shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' From 239bd769df2bb5b29b97ccccc512f761e08ad6b4 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 8 Feb 2020 11:17:45 +0000 Subject: [PATCH 152/711] Cache the gradle dependency cache This'll preserve the FG and general module cache. Note, this doesn't include gradle wrappers, but that's normally pretty fast to download. --- .github/workflows/main-ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index d499cd33f..924abb37a 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -15,6 +15,14 @@ jobs: with: java-version: 1.8 + - name: Cache gradle dependencies + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + - name: Build with Gradle run: ./gradlew build --no-daemon From 95fee95006b33bb9e798219d903bae4b1b8d6b46 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 8 Feb 2020 20:26:16 +0000 Subject: [PATCH 153/711] Fix spelling of Ctrl --- src/main/resources/data/computercraft/lua/rom/apis/keys.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua index 06dc1c6d1..47c581f2c 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua @@ -126,7 +126,7 @@ tKeys[341] = 'leftCtrl' tKeys[342] = 'leftAlt' -- tKeys[343] = 'leftSuper' tKeys[344] = 'rightShift' -tKeys[345] = 'rightControl' +tKeys[345] = 'rightCtrl' tKeys[346] = 'rightAlt' -- tKeys[347] = 'rightSuper' -- tKeys[348] = 'menu' From 0ffd5fcf85c58cf4508ab2c69cd1339cd4c5f89d Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 8 Feb 2020 21:04:58 +0000 Subject: [PATCH 154/711] Add fs.getCapacity and fs.attributes (#365) - fs.getCapacity just returns the capacity of the current drive, if available. This will be nil on rom mounts. - fs.attributes returns an lfs like table of various file attributes. Currently, this contains: - access, modification, created: When this file was last accessed, modified and created. Time is measured in milliseconds since the epoch, same as os.epoch("utc") and what is accepted by os.date. - size: Same as fs.getSize - isDir: same as fs.isDir Closes #262 --- .../api/filesystem/FileAttributes.java | 81 ++++ .../computercraft/api/filesystem/IMount.java | 15 + .../api/filesystem/IWritableMount.java | 13 + .../dan200/computercraft/core/apis/FSAPI.java | 43 ++- .../core/filesystem/ComboMount.java | 16 + .../core/filesystem/FileMount.java | 22 ++ .../core/filesystem/FileSystem.java | 350 ++---------------- .../core/filesystem/JarMount.java | 80 ++++ .../core/filesystem/MountWrapper.java | 312 ++++++++++++++++ .../core/filesystem/SubMount.java | 39 +- .../core/ComputerTestDelegate.java | 2 +- .../resources/test-rom/spec/apis/fs_spec.lua | 40 ++ 12 files changed, 664 insertions(+), 349 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java create mode 100644 src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java new file mode 100644 index 000000000..5dcf3e964 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java @@ -0,0 +1,81 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.filesystem; + +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.time.Instant; + +/** + * A simple version of {@link BasicFileAttributes}, which provides what information a {@link IMount} already exposes. + */ +final class FileAttributes implements BasicFileAttributes +{ + private static final FileTime EPOCH = FileTime.from( Instant.EPOCH ); + + private final boolean isDirectory; + private final long size; + + FileAttributes( boolean isDirectory, long size ) + { + this.isDirectory = isDirectory; + this.size = size; + } + + @Override + public FileTime lastModifiedTime() + { + return EPOCH; + } + + @Override + public FileTime lastAccessTime() + { + return EPOCH; + } + + @Override + public FileTime creationTime() + { + return EPOCH; + } + + @Override + public boolean isRegularFile() + { + return !isDirectory; + } + + @Override + public boolean isDirectory() + { + return isDirectory; + } + + @Override + public boolean isSymbolicLink() + { + return false; + } + + @Override + public boolean isOther() + { + return false; + } + + @Override + public long size() + { + return size; + } + + @Override + public Object fileKey() + { + return null; + } +} diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 41fb51b78..a0aa661b7 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; import java.util.List; /** @@ -93,4 +94,18 @@ public interface IMount { return Channels.newChannel( openForRead( path ) ); } + + /** + * Get attributes about the given file. + * + * @param path The path to query. + * @return File attributes for the given file. + * @throws IOException If the file does not exist, or attributes could not be fetched. + */ + @Nonnull + default BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + if( !exists( path ) ) throw new FileOperationException( path, "No such file" ); + return new FileAttributes( isDirectory( path ), getSize( path ) ); + } } diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index a778f423d..43bf5ae30 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; +import java.util.OptionalLong; /** * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} @@ -105,4 +106,16 @@ public interface IWritableMount extends IMount * @throws IOException If the remaining space could not be computed. */ long getRemainingSpace() throws IOException; + + /** + * Get the capacity of this mount. This should be equal to the size of all files/directories on this mount, minus + * the {@link #getRemainingSpace()}. + * + * @return The capacity of this mount, in bytes. + */ + @Nonnull + default OptionalLong getCapacity() + { + return OptionalLong.empty(); + } } diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index c99273763..74f786f23 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -22,6 +22,10 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.Map; +import java.util.OptionalLong; import java.util.function.Function; import static dan200.computercraft.api.lua.ArgumentHelper.getString; @@ -76,6 +80,8 @@ public class FSAPI implements ILuaAPI "getFreeSpace", "find", "getDir", + "getCapacity", + "attributes", }; } @@ -315,9 +321,8 @@ public class FSAPI implements ILuaAPI throw new LuaException( e.getMessage() ); } } - case 14: + case 14: // find { - // find String path = getString( args, 0 ); try { @@ -329,12 +334,42 @@ public class FSAPI implements ILuaAPI throw new LuaException( e.getMessage() ); } } - case 15: + case 15: // getDir { - // getDir String path = getString( args, 0 ); return new Object[] { FileSystem.getDirectory( path ) }; } + case 16: // getCapacity + { + String path = getString( args, 0 ); + try + { + OptionalLong capacity = m_fileSystem.getCapacity( path ); + return new Object[] { capacity.isPresent() ? capacity.getAsLong() : null }; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + case 17: // attributes + { + String path = getString( args, 0 ); + try + { + BasicFileAttributes attributes = m_fileSystem.getAttributes( path ); + Map result = new HashMap<>(); + result.put( "modification", attributes.lastModifiedTime().toMillis() ); + result.put( "created", attributes.creationTime().toMillis() ); + result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); + result.put( "isDir", attributes.isDirectory() ); + return new Object[] { result }; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } default: assert false; return null; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index 53e119954..9114c3522 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -12,6 +12,7 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -143,4 +144,19 @@ public class ComboMount implements IMount } throw new FileOperationException( path, "No such file" ); } + + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + for( int i = m_parts.length - 1; i >= 0; --i ) + { + IMount part = m_parts[i]; + if( part.exists( path ) && !part.isDirectory( path ) ) + { + return part.getAttributes( path ); + } + } + throw new FileOperationException( path, "No such file" ); + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index eb0f39ff8..13cf9b062 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -16,8 +16,10 @@ import java.nio.channels.*; import java.nio.file.Files; import java.nio.file.OpenOption; import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; import java.util.List; +import java.util.OptionalLong; import java.util.Set; public class FileMount implements IWritableMount @@ -224,6 +226,19 @@ public class FileMount implements IWritableMount throw new FileOperationException( path, "No such file" ); } + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + if( created() ) + { + File file = getRealPath( path ); + if( file.exists() ) return Files.readAttributes( file.toPath(), BasicFileAttributes.class ); + } + + throw new FileOperationException( path, "No such file" ); + } + // IWritableMount implementation @Override @@ -360,6 +375,13 @@ public class FileMount implements IWritableMount return Math.max( m_capacity - m_usedSpace, 0 ); } + @Nonnull + @Override + public OptionalLong getCapacity() + { + return OptionalLong.of( m_capacity - MINIMUM_FILE_SIZE ); + } + private File getRealPath( String path ) { return new File( m_rootPath, path ); diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index eda0361bd..0403f98ac 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -7,7 +7,6 @@ package dan200.computercraft.core.filesystem; import com.google.common.io.ByteStreams; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -23,6 +22,7 @@ import java.nio.channels.Channel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.nio.file.AccessDeniedException; +import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; @@ -37,303 +37,8 @@ public class FileSystem */ private static final int MAX_COPY_DEPTH = 128; - private static class MountWrapper - { - private String m_label; - private String m_location; - - private IMount m_mount; - private IWritableMount m_writableMount; - - MountWrapper( String label, String location, IMount mount ) - { - m_label = label; - m_location = location; - m_mount = mount; - m_writableMount = null; - } - - MountWrapper( String label, String location, IWritableMount mount ) - { - this( label, location, (IMount) mount ); - m_writableMount = mount; - } - - public String getLabel() - { - return m_label; - } - - public String getLocation() - { - return m_location; - } - - public long getFreeSpace() - { - if( m_writableMount == null ) - { - return 0; - } - - try - { - return m_writableMount.getRemainingSpace(); - } - catch( IOException e ) - { - return 0; - } - } - - public boolean isReadOnly( String path ) - { - return m_writableMount == null; - } - - // IMount forwarders: - - public boolean exists( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - return m_mount.exists( path ); - } - catch( IOException e ) - { - throw new FileSystemException( e.getMessage() ); - } - } - - public boolean isDirectory( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - return m_mount.exists( path ) && m_mount.isDirectory( path ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public void list( String path, List contents ) throws FileSystemException - { - path = toLocal( path ); - try - { - if( m_mount.exists( path ) && m_mount.isDirectory( path ) ) - { - m_mount.list( path, contents ); - } - else - { - throw localExceptionOf( path, "Not a directory" ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public long getSize( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - if( m_mount.exists( path ) ) - { - if( m_mount.isDirectory( path ) ) - { - return 0; - } - else - { - return m_mount.getSize( path ); - } - } - else - { - throw localExceptionOf( path, "No such file" ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public ReadableByteChannel openForRead( String path ) throws FileSystemException - { - path = toLocal( path ); - try - { - if( m_mount.exists( path ) && !m_mount.isDirectory( path ) ) - { - return m_mount.openChannelForRead( path ); - } - else - { - throw localExceptionOf( path, "No such file" ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - // IWritableMount forwarders: - - public void makeDirectory( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - path = toLocal( path ); - try - { - if( m_mount.exists( path ) ) - { - if( !m_mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" ); - } - else - { - m_writableMount.makeDirectory( path ); - } - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public void delete( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - try - { - path = toLocal( path ); - if( m_mount.exists( path ) ) - { - m_writableMount.delete( path ); - } - } - catch( AccessDeniedException e ) - { - throw new FileSystemException( "Access denied" ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public WritableByteChannel openForWrite( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - path = toLocal( path ); - try - { - if( m_mount.exists( path ) && m_mount.isDirectory( path ) ) - { - throw localExceptionOf( path, "Cannot write to directory" ); - } - else - { - if( !path.isEmpty() ) - { - String dir = getDirectory( path ); - if( !dir.isEmpty() && !m_mount.exists( path ) ) - { - m_writableMount.makeDirectory( dir ); - } - } - return m_writableMount.openChannelForWrite( path ); - } - } - catch( AccessDeniedException e ) - { - throw new FileSystemException( "Access denied" ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - public WritableByteChannel openForAppend( String path ) throws FileSystemException - { - if( m_writableMount == null ) throw exceptionOf( path, "Access denied" ); - - path = toLocal( path ); - try - { - if( !m_mount.exists( path ) ) - { - if( !path.isEmpty() ) - { - String dir = getDirectory( path ); - if( !dir.isEmpty() && !m_mount.exists( path ) ) - { - m_writableMount.makeDirectory( dir ); - } - } - return m_writableMount.openChannelForWrite( path ); - } - else if( m_mount.isDirectory( path ) ) - { - throw localExceptionOf( path, "Cannot write to directory" ); - } - else - { - return m_writableMount.openChannelForAppend( path ); - } - } - catch( AccessDeniedException e ) - { - throw new FileSystemException( "Access denied" ); - } - catch( IOException e ) - { - throw localExceptionOf( e ); - } - } - - private String toLocal( String path ) - { - return FileSystem.toLocal( path, m_location ); - } - - private FileSystemException localExceptionOf( IOException e ) - { - if( !m_location.isEmpty() && e instanceof FileOperationException ) - { - FileOperationException ex = (FileOperationException) e; - if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); - } - - return new FileSystemException( e.getMessage() ); - } - - private FileSystemException localExceptionOf( String path, String message ) - { - if( !m_location.isEmpty() ) path = path.isEmpty() ? m_location : m_location + "/" + path; - return exceptionOf( path, message ); - } - - private static FileSystemException exceptionOf( String path, String message ) - { - return new FileSystemException( "/" + path + ": " + message ); - } - } - private final FileSystemWrapperMount m_wrapper = new FileSystemWrapperMount( this ); - private final Map m_mounts = new HashMap<>(); + private final Map mounts = new HashMap<>(); private final HashMap>, ChannelWrapper> m_openFiles = new HashMap<>(); private final ReferenceQueue> m_openFileQueue = new ReferenceQueue<>(); @@ -363,10 +68,7 @@ public class FileSystem { if( mount == null ) throw new NullPointerException(); location = sanitizePath( location ); - if( location.contains( ".." ) ) - { - throw new FileSystemException( "Cannot mount below the root" ); - } + if( location.contains( ".." ) ) throw new FileSystemException( "Cannot mount below the root" ); mount( new MountWrapper( label, location, mount ) ); } @@ -387,14 +89,13 @@ public class FileSystem private synchronized void mount( MountWrapper wrapper ) { String location = wrapper.getLocation(); - m_mounts.remove( location ); - m_mounts.put( location, wrapper ); + mounts.remove( location ); + mounts.put( location, wrapper ); } public synchronized void unmount( String path ) { - path = sanitizePath( path ); - m_mounts.remove( path ); + mounts.remove( sanitizePath( path ) ); } public synchronized String combine( String path, String childPath ) @@ -438,27 +139,20 @@ public class FileSystem public static String getName( String path ) { path = sanitizePath( path, true ); - if( path.isEmpty() ) - { - return "root"; - } + if( path.isEmpty() ) return "root"; int lastSlash = path.lastIndexOf( '/' ); - if( lastSlash >= 0 ) - { - return path.substring( lastSlash + 1 ); - } - else - { - return path; - } + return lastSlash >= 0 ? path.substring( lastSlash + 1 ) : path; } public synchronized long getSize( String path ) throws FileSystemException { - path = sanitizePath( path ); - MountWrapper mount = getMount( path ); - return mount.getSize( path ); + return getMount( sanitizePath( path ) ).getSize( sanitizePath( path ) ); + } + + public synchronized BasicFileAttributes getAttributes( String path ) throws FileSystemException + { + return getMount( sanitizePath( path ) ).getAttributes( sanitizePath( path ) ); } public synchronized String[] list( String path ) throws FileSystemException @@ -471,7 +165,7 @@ public class FileSystem mount.list( path, list ); // Add any mounts that are mounted at this location - for( MountWrapper otherMount : m_mounts.values() ) + for( MountWrapper otherMount : mounts.values() ) { if( getDirectory( otherMount.getLocation() ).equals( path ) ) { @@ -733,17 +427,25 @@ public class FileSystem return null; } - public long getFreeSpace( String path ) throws FileSystemException + public synchronized long getFreeSpace( String path ) throws FileSystemException { path = sanitizePath( path ); MountWrapper mount = getMount( path ); return mount.getFreeSpace(); } - private MountWrapper getMount( String path ) throws FileSystemException + @Nonnull + public synchronized OptionalLong getCapacity( String path ) throws FileSystemException + { + path = sanitizePath( path ); + MountWrapper mount = getMount( path ); + return mount.getCapacity(); + } + + private synchronized MountWrapper getMount( String path ) throws FileSystemException { // Return the deepest mount that contains a given path - Iterator it = m_mounts.values().iterator(); + Iterator it = mounts.values().iterator(); MountWrapper match = null; int matchLength = 999; while( it.hasNext() ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 336d4ddcc..2cf55a747 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -23,6 +23,8 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; import java.util.Enumeration; import java.util.HashMap; import java.util.List; @@ -221,6 +223,20 @@ public class JarMount implements IMount throw new FileOperationException( path, "No such file" ); } + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + FileEntry file = get( path ); + if( file != null ) + { + ZipEntry entry = zip.getEntry( file.path ); + if( entry != null ) return new ZipEntryAttributes( entry ); + } + + throw new FileOperationException( path, "No such file" ); + } + private static class FileEntry { String path; @@ -261,4 +277,68 @@ public class JarMount implements IMount Reference next; while( (next = MOUNT_QUEUE.poll()) != null ) IoUtil.closeQuietly( ((MountReference) next).file ); } + + private static class ZipEntryAttributes implements BasicFileAttributes + { + private final ZipEntry entry; + + ZipEntryAttributes( ZipEntry entry ) + { + this.entry = entry; + } + + @Override + public FileTime lastModifiedTime() + { + return entry.getLastModifiedTime(); + } + + @Override + public FileTime lastAccessTime() + { + return entry.getLastAccessTime(); + } + + @Override + public FileTime creationTime() + { + return entry.getCreationTime(); + } + + @Override + public boolean isRegularFile() + { + return !entry.isDirectory(); + } + + @Override + public boolean isDirectory() + { + return entry.isDirectory(); + } + + @Override + public boolean isSymbolicLink() + { + return false; + } + + @Override + public boolean isOther() + { + return false; + } + + @Override + public long size() + { + return entry.getSize(); + } + + @Override + public Object fileKey() + { + return null; + } + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java new file mode 100644 index 000000000..5cc4ee958 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java @@ -0,0 +1,312 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.filesystem; + +import dan200.computercraft.api.filesystem.FileOperationException; +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.file.AccessDeniedException; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.List; +import java.util.OptionalLong; + +class MountWrapper +{ + private String label; + private String location; + + private IMount mount; + private IWritableMount writableMount; + + MountWrapper( String label, String location, IMount mount ) + { + this.label = label; + this.location = location; + this.mount = mount; + writableMount = null; + } + + MountWrapper( String label, String location, IWritableMount mount ) + { + this( label, location, (IMount) mount ); + writableMount = mount; + } + + public String getLabel() + { + return label; + } + + public String getLocation() + { + return location; + } + + public long getFreeSpace() + { + if( writableMount == null ) return 0; + + try + { + return writableMount.getRemainingSpace(); + } + catch( IOException e ) + { + return 0; + } + } + + public OptionalLong getCapacity() + { + return writableMount == null ? OptionalLong.empty() : writableMount.getCapacity(); + } + + public boolean isReadOnly( String path ) + { + return writableMount == null; + } + + public boolean exists( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + return mount.exists( path ); + } + catch( IOException e ) + { + throw new FileSystemException( e.getMessage() ); + } + } + + public boolean isDirectory( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + return mount.exists( path ) && mount.isDirectory( path ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public void list( String path, List contents ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( !mount.exists( path ) || !mount.isDirectory( path ) ) + { + throw localExceptionOf( path, "Not a directory" ); + } + + mount.list( path, contents ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public long getSize( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( !mount.exists( path ) ) throw localExceptionOf( path, "No such file" ); + return mount.isDirectory( path ) ? 0 : mount.getSize( path ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + @Nonnull + public BasicFileAttributes getAttributes( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( !mount.exists( path ) ) throw localExceptionOf( path, "No such file" ); + return mount.getAttributes( path ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public ReadableByteChannel openForRead( String path ) throws FileSystemException + { + path = toLocal( path ); + try + { + if( mount.exists( path ) && !mount.isDirectory( path ) ) + { + return mount.openChannelForRead( path ); + } + else + { + throw localExceptionOf( path, "No such file" ); + } + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public void makeDirectory( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); + try + { + if( mount.exists( path ) ) + { + if( !mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" ); + } + else + { + writableMount.makeDirectory( path ); + } + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public void delete( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + try + { + path = toLocal( path ); + if( mount.exists( path ) ) + { + writableMount.delete( path ); + } + } + catch( AccessDeniedException e ) + { + throw new FileSystemException( "Access denied" ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public WritableByteChannel openForWrite( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); + try + { + if( mount.exists( path ) && mount.isDirectory( path ) ) + { + throw localExceptionOf( path, "Cannot write to directory" ); + } + else + { + if( !path.isEmpty() ) + { + String dir = FileSystem.getDirectory( path ); + if( !dir.isEmpty() && !mount.exists( path ) ) + { + writableMount.makeDirectory( dir ); + } + } + return writableMount.openChannelForWrite( path ); + } + } + catch( AccessDeniedException e ) + { + throw new FileSystemException( "Access denied" ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + public WritableByteChannel openForAppend( String path ) throws FileSystemException + { + if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + + path = toLocal( path ); + try + { + if( !mount.exists( path ) ) + { + if( !path.isEmpty() ) + { + String dir = FileSystem.getDirectory( path ); + if( !dir.isEmpty() && !mount.exists( path ) ) + { + writableMount.makeDirectory( dir ); + } + } + return writableMount.openChannelForWrite( path ); + } + else if( mount.isDirectory( path ) ) + { + throw localExceptionOf( path, "Cannot write to directory" ); + } + else + { + return writableMount.openChannelForAppend( path ); + } + } + catch( AccessDeniedException e ) + { + throw new FileSystemException( "Access denied" ); + } + catch( IOException e ) + { + throw localExceptionOf( e ); + } + } + + private String toLocal( String path ) + { + return FileSystem.toLocal( path, location ); + } + + private FileSystemException localExceptionOf( IOException e ) + { + if( !location.isEmpty() && e instanceof FileOperationException ) + { + FileOperationException ex = (FileOperationException) e; + if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); + } + + return new FileSystemException( e.getMessage() ); + } + + private FileSystemException localExceptionOf( String path, String message ) + { + if( !location.isEmpty() ) path = path.isEmpty() ? location : location + "/" + path; + return exceptionOf( path, message ); + } + + private static FileSystemException exceptionOf( String path, String message ) + { + return new FileSystemException( "/" + path + ": " + message ); + } +} diff --git a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java index 1cdac4a6a..d59aeab36 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java @@ -11,43 +11,42 @@ import javax.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; import java.nio.channels.ReadableByteChannel; +import java.nio.file.attribute.BasicFileAttributes; import java.util.List; public class SubMount implements IMount { - private IMount m_parent; - private String m_subPath; + private IMount parent; + private String subPath; public SubMount( IMount parent, String subPath ) { - m_parent = parent; - m_subPath = subPath; + this.parent = parent; + this.subPath = subPath; } - // IMount implementation - @Override public boolean exists( @Nonnull String path ) throws IOException { - return m_parent.exists( getFullPath( path ) ); + return parent.exists( getFullPath( path ) ); } @Override public boolean isDirectory( @Nonnull String path ) throws IOException { - return m_parent.isDirectory( getFullPath( path ) ); + return parent.isDirectory( getFullPath( path ) ); } @Override public void list( @Nonnull String path, @Nonnull List contents ) throws IOException { - m_parent.list( getFullPath( path ), contents ); + parent.list( getFullPath( path ), contents ); } @Override public long getSize( @Nonnull String path ) throws IOException { - return m_parent.getSize( getFullPath( path ) ); + return parent.getSize( getFullPath( path ) ); } @Nonnull @@ -55,25 +54,25 @@ public class SubMount implements IMount @Deprecated public InputStream openForRead( @Nonnull String path ) throws IOException { - return m_parent.openForRead( getFullPath( path ) ); + return parent.openForRead( getFullPath( path ) ); } @Nonnull @Override public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException { - return m_parent.openChannelForRead( getFullPath( path ) ); + return parent.openChannelForRead( getFullPath( path ) ); + } + + @Nonnull + @Override + public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException + { + return parent.getAttributes( getFullPath( path ) ); } private String getFullPath( String path ) { - if( path.isEmpty() ) - { - return m_subPath; - } - else - { - return m_subPath + "/" + path; - } + return path.isEmpty() ? subPath : subPath + "/" + path; } } diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index c5d9e02ef..6413d5ef0 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -79,7 +79,7 @@ public class ComputerTestDelegate ComputerCraft.log = LogManager.getLogger( ComputerCraft.MOD_ID ); Terminal term = new Terminal( 78, 20 ); - IWritableMount mount = new FileMount( new File( "test-files/mount" ), Long.MAX_VALUE ); + IWritableMount mount = new FileMount( new File( "test-files/mount" ), 10_000_000 ); // Remove any existing files List children = new ArrayList<>(); diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index f6ccac6bc..5288aa9c8 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -149,4 +149,44 @@ describe("The fs library", function() expect.error(fs.move, "rom", "test-files"):eq("Access denied") end) end) + + describe("fs.getCapacity", function() + it("returns nil on read-only mounts", function() + expect(fs.getCapacity("rom")):eq(nil) + end) + + it("returns the capacity on the root mount", function() + expect(fs.getCapacity("")):eq(10000000) + end) + end) + + describe("fs.attributes", function() + it("errors on non-existent files", function() + expect.error(fs.attributes, "xuxu_nao_existe"):eq("/xuxu_nao_existe: No such file") + end) + + it("returns information about read-only mounts", function() + expect(fs.attributes("rom")):matches { isDir = true, size = 0 } + end) + + it("returns information about files", function() + local now = os.epoch("utc") + + fs.delete("/tmp/basic-file") + local h = fs.open("/tmp/basic-file", "w") + h.write("A reasonably sized string") + h.close() + + local attributes = fs.attributes("tmp/basic-file") + expect(attributes):matches { isDir = false, size = 25 } + + if attributes.created - now >= 1000 then + fail(("Expected created time (%d) to be within 1000ms of now (%d"):format(attributes.created, now)) + end + + if attributes.modification - now >= 1000 then + fail(("Expected modification time (%d) to be within 1000ms of now (%d"):format(attributes.modification, now)) + end + end) + end) end) From 00b41d29c1b1d07835e858aa28fd1a52e83333ee Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 7 Feb 2020 23:05:39 +0000 Subject: [PATCH 155/711] Update README to mention fg.deobf --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d75213c02..cef7bd631 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ dependencies { } dependencies { - implementation "org.squiddev:cc-tweaked-${mc_version}:${cct_version}" + implementation fg.deobf("org.squiddev:cc-tweaked-${mc_version}:${cct_version}") } ``` From 419f29321adbc1bb5370788cf5e83b23f1827656 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 8 Feb 2020 23:26:05 +0000 Subject: [PATCH 156/711] Port most recipes to use generators Closes #354 --- .../recipes/computercraft/cable.json | 43 ++++ .../computercraft/computer_advanced.json | 35 ++++ .../computercraft/computer_command.json | 32 +++ .../computercraft/computer_normal.json | 32 +++ .../recipes/computercraft/disk_drive.json | 32 +++ .../computercraft/monitor_advanced.json | 32 +++ .../recipes/computercraft/monitor_normal.json | 32 +++ .../pocket_computer_advanced.json | 43 ++++ .../computercraft/pocket_computer_normal.json | 43 ++++ .../recipes/computercraft/printer.json | 32 +++ .../recipes/computercraft/speaker.json | 32 +++ .../recipes/computercraft/wired_modem.json | 43 ++++ .../computercraft/wired_modem_full_from.json | 32 +++ .../computercraft/wired_modem_full_to.json | 32 +++ .../wireless_modem_advanced.json | 43 ++++ .../computercraft/wireless_modem_normal.json | 32 +++ .../data/computercraft/recipes/cable.json | 20 ++ .../recipes/computer_advanced.json | 22 ++ .../recipes/computer_command.json | 22 ++ .../recipes/computer_normal.json | 22 ++ .../computercraft/recipes/disk_drive.json | 19 ++ .../recipes/monitor_advanced.json | 20 ++ .../computercraft/recipes/monitor_normal.json | 19 ++ .../recipes/pocket_computer_advanced.json | 22 ++ .../recipes/pocket_computer_normal.json | 22 ++ .../data/computercraft/recipes/printer.json | 22 ++ .../data/computercraft/recipes/speaker.json | 22 ++ .../computercraft/recipes/wired_modem.json | 19 ++ .../recipes/wired_modem_full_from.json | 11 + .../recipes/wired_modem_full_to.json | 11 + .../recipes/wireless_modem_advanced.json | 19 ++ .../recipes/wireless_modem_normal.json | 19 ++ .../computercraft/tags/items/computer.json | 8 + .../computercraft/tags/items/monitor.json | 7 + .../data/computercraft/tags/items/turtle.json | 7 + .../computercraft/tags/items/wired_modem.json | 7 + .../dan200/computercraft/data/Generators.java | 1 + .../dan200/computercraft/data/Recipes.java | 193 +++++++++++++++++- .../java/dan200/computercraft/data/Tags.java | 52 +++++ .../advancements/recipes/cable.json | 38 ---- .../recipes/command_computer.json | 24 --- .../recipes/computer_advanced.json | 24 --- .../advancements/recipes/computer_normal.json | 24 --- .../advancements/recipes/disk_drive.json | 31 --- .../recipes/monitor_advanced.json | 31 --- .../advancements/recipes/monitor_normal.json | 31 --- .../recipes/pocket_computer_advanced.json | 38 ---- .../recipes/pocket_computer_normal.json | 38 ---- .../advancements/recipes/printer.json | 31 --- .../advancements/recipes/speaker.json | 38 ---- .../recipes/wireless_modem_advanced.json | 38 ---- .../recipes/wireless_modem_normal.json | 31 --- .../data/computercraft/recipes/cable.json | 13 -- .../recipes/computer_advanced.json | 14 -- .../recipes/computer_command.json | 14 -- .../recipes/computer_normal.json | 14 -- .../computercraft/recipes/disk_drive.json | 13 -- .../recipes/monitor_advanced.json | 13 -- .../computercraft/recipes/monitor_normal.json | 13 -- .../recipes/pocket_computer_advanced.json | 14 -- .../recipes/pocket_computer_normal.json | 14 -- .../data/computercraft/recipes/printer.json | 14 -- .../data/computercraft/recipes/speaker.json | 14 -- .../computercraft/recipes/wired_modem.json | 13 -- .../recipes/wired_modem_full_from.json | 7 - .../recipes/wired_modem_full_to.json | 7 - .../recipes/wireless_modem_advanced.json | 13 -- .../recipes/wireless_modem_normal.json | 13 -- 68 files changed, 1149 insertions(+), 627 deletions(-) create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/cable.json create mode 100644 src/generated/resources/data/computercraft/recipes/computer_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/computer_command.json create mode 100644 src/generated/resources/data/computercraft/recipes/computer_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/disk_drive.json create mode 100644 src/generated/resources/data/computercraft/recipes/monitor_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/monitor_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json create mode 100644 src/generated/resources/data/computercraft/recipes/printer.json create mode 100644 src/generated/resources/data/computercraft/recipes/speaker.json create mode 100644 src/generated/resources/data/computercraft/recipes/wired_modem.json create mode 100644 src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json create mode 100644 src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json create mode 100644 src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json create mode 100644 src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json create mode 100644 src/generated/resources/data/computercraft/tags/items/computer.json create mode 100644 src/generated/resources/data/computercraft/tags/items/monitor.json create mode 100644 src/generated/resources/data/computercraft/tags/items/turtle.json create mode 100644 src/generated/resources/data/computercraft/tags/items/wired_modem.json create mode 100644 src/main/java/dan200/computercraft/data/Tags.java delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/cable.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/command_computer.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/computer_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/disk_drive.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/printer.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/speaker.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/cable.json delete mode 100644 src/main/resources/data/computercraft/recipes/computer_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/computer_command.json delete mode 100644 src/main/resources/data/computercraft/recipes/computer_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/disk_drive.json delete mode 100644 src/main/resources/data/computercraft/recipes/monitor_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/monitor_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/pocket_computer_normal.json delete mode 100644 src/main/resources/data/computercraft/recipes/printer.json delete mode 100644 src/main/resources/data/computercraft/recipes/speaker.json delete mode 100644 src/main/resources/data/computercraft/recipes/wired_modem.json delete mode 100644 src/main/resources/data/computercraft/recipes/wired_modem_full_from.json delete mode 100644 src/main/resources/data/computercraft/recipes/wired_modem_full_to.json delete mode 100644 src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json delete mode 100644 src/main/resources/data/computercraft/recipes/wireless_modem_normal.json diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json new file mode 100644 index 000000000..69ed2c857 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/cable.json @@ -0,0 +1,43 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:cable" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_modem": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:cable" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_modem", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json new file mode 100644 index 000000000..2f4cebec8 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_advanced.json @@ -0,0 +1,35 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:computer_advanced" + ] + }, + "criteria": { + "has_components": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:redstone" + }, + { + "item": "minecraft:gold_ingot" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:computer_advanced" + } + } + }, + "requirements": [ + [ + "has_components", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json new file mode 100644 index 000000000..82a335701 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_command.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:computer_command" + ] + }, + "criteria": { + "has_components": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:command_block" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:computer_command" + } + } + }, + "requirements": [ + [ + "has_components", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json new file mode 100644 index 000000000..df587895f --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/computer_normal.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:computer_normal" + ] + }, + "criteria": { + "has_redstone": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "forge:dusts/redstone" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:computer_normal" + } + } + }, + "requirements": [ + [ + "has_redstone", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json new file mode 100644 index 000000000..7fb18766e --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/disk_drive.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:disk_drive" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:disk_drive" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json new file mode 100644 index 000000000..dab4faad3 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_advanced.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:monitor_advanced" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:monitor_advanced" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json new file mode 100644 index 000000000..fdd3c274c --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/monitor_normal.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:monitor_normal" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:monitor_normal" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json new file mode 100644 index 000000000..468d54cc9 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_advanced.json @@ -0,0 +1,43 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_computer_advanced" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_apple": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:golden_apple" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_computer_advanced" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_apple", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json new file mode 100644 index 000000000..4d40913a7 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_computer_normal.json @@ -0,0 +1,43 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:pocket_computer_normal" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_apple": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "minecraft:golden_apple" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:pocket_computer_normal" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_apple", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json new file mode 100644 index 000000000..08a2ffeba --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/printer.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:printer" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:printer" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json new file mode 100644 index 000000000..194f7caec --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/speaker.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:speaker" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:speaker" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json new file mode 100644 index 000000000..f78501816 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem.json @@ -0,0 +1,43 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wired_modem" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_cable": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:cable" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wired_modem" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_cable", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json new file mode 100644 index 000000000..a54c82034 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_from.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wired_modem_full_from" + ] + }, + "criteria": { + "has_modem": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:wired_modem" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wired_modem_full_from" + } + } + }, + "requirements": [ + [ + "has_modem", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json new file mode 100644 index 000000000..c0eaec110 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wired_modem_full_to.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wired_modem_full_to" + ] + }, + "criteria": { + "has_modem": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:wired_modem" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wired_modem_full_to" + } + } + }, + "requirements": [ + [ + "has_modem", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json new file mode 100644 index 000000000..5941483e3 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_advanced.json @@ -0,0 +1,43 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wireless_modem_advanced" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_wireless": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "item": "computercraft:wireless_modem_normal" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wireless_modem_advanced" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_wireless", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json new file mode 100644 index 000000000..b0ce1c994 --- /dev/null +++ b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/wireless_modem_normal.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "rewards": { + "recipes": [ + "computercraft:wireless_modem_normal" + ] + }, + "criteria": { + "has_computer": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "tag": "computercraft:computer" + } + ] + } + }, + "has_the_recipe": { + "trigger": "minecraft:recipe_unlocked", + "conditions": { + "recipe": "computercraft:wireless_modem_normal" + } + } + }, + "requirements": [ + [ + "has_computer", + "has_the_recipe" + ] + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/cable.json b/src/generated/resources/data/computercraft/recipes/cable.json new file mode 100644 index 000000000..357212509 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/cable.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " # ", + "#R#", + " # " + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "result": { + "item": "computercraft:cable", + "count": 6 + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/computer_advanced.json b/src/generated/resources/data/computercraft/recipes/computer_advanced.json new file mode 100644 index 000000000..d004a6c78 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/computer_advanced.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#G#" + ], + "key": { + "#": { + "tag": "forge:ingots/gold" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/computer_command.json b/src/generated/resources/data/computercraft/recipes/computer_command.json new file mode 100644 index 000000000..c3f71b49b --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/computer_command.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#G#" + ], + "key": { + "#": { + "tag": "forge:ingots/gold" + }, + "R": { + "item": "minecraft:command_block" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_command" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/computer_normal.json b/src/generated/resources/data/computercraft/recipes/computer_normal.json new file mode 100644 index 000000000..661f4945f --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/computer_normal.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#G#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/disk_drive.json b/src/generated/resources/data/computercraft/recipes/disk_drive.json new file mode 100644 index 000000000..a217fc712 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/disk_drive.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#R#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "result": { + "item": "computercraft:disk_drive" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/monitor_advanced.json b/src/generated/resources/data/computercraft/recipes/monitor_advanced.json new file mode 100644 index 000000000..7588676cd --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/monitor_advanced.json @@ -0,0 +1,20 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#G#", + "###" + ], + "key": { + "#": { + "tag": "forge:ingots/gold" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:monitor_advanced", + "count": 4 + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/monitor_normal.json b/src/generated/resources/data/computercraft/recipes/monitor_normal.json new file mode 100644 index 000000000..2ded57d08 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/monitor_normal.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#G#", + "###" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:monitor_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json b/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json new file mode 100644 index 000000000..b8c65358d --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_computer_advanced.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#A#", + "#G#" + ], + "key": { + "#": { + "tag": "forge:ingots/gold" + }, + "A": { + "item": "minecraft:golden_apple" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:pocket_computer_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json b/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json new file mode 100644 index 000000000..c18f0252a --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/pocket_computer_normal.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#A#", + "#G#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "A": { + "item": "minecraft:golden_apple" + }, + "G": { + "tag": "forge:glass_panes" + } + }, + "result": { + "item": "computercraft:pocket_computer_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/printer.json b/src/generated/resources/data/computercraft/recipes/printer.json new file mode 100644 index 000000000..5f0072676 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/printer.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "#D#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + }, + "D": { + "tag": "forge:dyes" + } + }, + "result": { + "item": "computercraft:printer" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/speaker.json b/src/generated/resources/data/computercraft/recipes/speaker.json new file mode 100644 index 000000000..c1ede5db7 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/speaker.json @@ -0,0 +1,22 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#N#", + "#R#" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "N": { + "item": "minecraft:note_block" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "result": { + "item": "computercraft:speaker" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wired_modem.json b/src/generated/resources/data/computercraft/recipes/wired_modem.json new file mode 100644 index 000000000..7494043b4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#R#", + "###" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "R": { + "tag": "forge:dusts/redstone" + } + }, + "result": { + "item": "computercraft:wired_modem" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json b/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json new file mode 100644 index 000000000..7865f45de --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem_full_from.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "computercraft:wired_modem" + } + ], + "result": { + "item": "computercraft:wired_modem_full" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json b/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json new file mode 100644 index 000000000..8c303ebb4 --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wired_modem_full_to.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "computercraft:wired_modem_full" + } + ], + "result": { + "item": "computercraft:wired_modem" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json new file mode 100644 index 000000000..a274aa73d --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wireless_modem_advanced.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#E#", + "###" + ], + "key": { + "#": { + "tag": "forge:ingots/gold" + }, + "E": { + "item": "minecraft:ender_eye" + } + }, + "result": { + "item": "computercraft:wireless_modem_advanced" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json b/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json new file mode 100644 index 000000000..e2041f59e --- /dev/null +++ b/src/generated/resources/data/computercraft/recipes/wireless_modem_normal.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "###", + "#E#", + "###" + ], + "key": { + "#": { + "tag": "forge:stone" + }, + "E": { + "tag": "forge:ender_pearls" + } + }, + "result": { + "item": "computercraft:wireless_modem_normal" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/computer.json b/src/generated/resources/data/computercraft/tags/items/computer.json new file mode 100644 index 000000000..bcd0e8037 --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/computer.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + "computercraft:computer_normal", + "computercraft:computer_advanced", + "computercraft:computer_command" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/monitor.json b/src/generated/resources/data/computercraft/tags/items/monitor.json new file mode 100644 index 000000000..babaefa8b --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/monitor.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:monitor_normal", + "computercraft:monitor_advanced" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/turtle.json b/src/generated/resources/data/computercraft/tags/items/turtle.json new file mode 100644 index 000000000..e4277edfe --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/turtle.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:turtle_normal", + "computercraft:turtle_advanced" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/tags/items/wired_modem.json b/src/generated/resources/data/computercraft/tags/items/wired_modem.json new file mode 100644 index 000000000..57db1557f --- /dev/null +++ b/src/generated/resources/data/computercraft/tags/items/wired_modem.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "computercraft:wired_modem", + "computercraft:wired_modem_full" + ] +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java index 1506661a1..69ef83b78 100644 --- a/src/main/java/dan200/computercraft/data/Generators.java +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -23,5 +23,6 @@ public class Generators DataGenerator generator = event.getGenerator(); generator.addProvider( new Recipes( generator ) ); generator.addProvider( new LootTables( generator ) ); + generator.addProvider( new Tags( generator ) ); } } diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java index 7146e829d..9523d80ac 100644 --- a/src/main/java/dan200/computercraft/data/Recipes.java +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -7,6 +7,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.data.Tags.CCTags; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; @@ -15,11 +16,12 @@ import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import net.minecraft.advancements.criterion.InventoryChangeTrigger; +import net.minecraft.advancements.criterion.ItemPredicate; +import net.minecraft.block.Blocks; import net.minecraft.data.*; -import net.minecraft.item.DyeColor; -import net.minecraft.item.DyeItem; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; +import net.minecraft.item.*; +import net.minecraft.tags.Tag; +import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.Tags; @@ -37,6 +39,7 @@ public class Recipes extends RecipeProvider @Override protected void registerRecipes( @Nonnull Consumer add ) { + basicRecipes( add ); diskColours( add ); pocketUpgrades( add ); turtleUpgrades( add ); @@ -57,7 +60,7 @@ public class Recipes extends RecipeProvider .addIngredient( Items.PAPER ) .addIngredient( DyeItem.getItem( ofColour( colour ) ) ) .setGroup( "computercraft:disk" ) - .addCriterion( "has_drive", InventoryChangeTrigger.Instance.forItems( ComputerCraft.Blocks.diskDrive ) ) + .addCriterion( "has_drive", inventoryChange( ComputerCraft.Blocks.diskDrive ) ) .build( RecipeWrapper.wrap( ImpostorShapelessRecipe.SERIALIZER, add, x -> x.putInt( "color", colour.getHex() ) @@ -88,7 +91,7 @@ public class Recipes extends RecipeProvider .key( '#', base.getItem() ) .key( 'T', upgrade.getCraftingItem().getItem() ) .addCriterion( "has_items", - InventoryChangeTrigger.Instance.forItems( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) ) .build( RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ), new ResourceLocation( ComputerCraft.MOD_ID, String.format( "turtle_%s/%s/%s", @@ -123,7 +126,7 @@ public class Recipes extends RecipeProvider .key( '#', base.getItem() ) .key( 'P', upgrade.getCraftingItem().getItem() ) .addCriterion( "has_items", - InventoryChangeTrigger.Instance.forItems( base.getItem(), upgrade.getCraftingItem().getItem() ) ) + inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) ) .build( RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ), new ResourceLocation( ComputerCraft.MOD_ID, String.format( "pocket_%s/%s/%s", @@ -134,8 +137,184 @@ public class Recipes extends RecipeProvider } } + private void basicRecipes( @Nonnull Consumer add ) + { + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.cable, 6 ) + .patternLine( " # " ) + .patternLine( "#R#" ) + .patternLine( " # " ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_modem", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.computerNormal ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_redstone", inventoryChange( Tags.Items.DUSTS_REDSTONE ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.computerAdvanced ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.computerCommand ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'R', Blocks.COMMAND_BLOCK ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.diskDrive ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#R#" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.monitorNormal ) + .patternLine( "###" ) + .patternLine( "#G#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.STONE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.monitorAdvanced, 4 ) + .patternLine( "###" ) + .patternLine( "#G#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.pocketComputerNormal ) + .patternLine( "###" ) + .patternLine( "#A#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.STONE ) + .key( 'A', Items.GOLDEN_APPLE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.pocketComputerAdvanced ) + .patternLine( "###" ) + .patternLine( "#A#" ) + .patternLine( "#G#" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'A', Items.GOLDEN_APPLE ) + .key( 'G', Tags.Items.GLASS_PANES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.printer ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "#D#" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .key( 'D', Tags.Items.DYES ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.speaker ) + .patternLine( "###" ) + .patternLine( "#N#" ) + .patternLine( "#R#" ) + .key( '#', Tags.Items.STONE ) + .key( 'N', Blocks.NOTE_BLOCK ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Items.wiredModem ) + .patternLine( "###" ) + .patternLine( "#R#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.STONE ) + .key( 'R', Tags.Items.DUSTS_REDSTONE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_cable", inventoryChange( ComputerCraft.Items.cable ) ) + .build( add ); + + ShapelessRecipeBuilder + .shapelessRecipe( ComputerCraft.Blocks.wiredModemFull ) + .addIngredient( ComputerCraft.Items.wiredModem ) + .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) ) + .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) ); + ShapelessRecipeBuilder + .shapelessRecipe( ComputerCraft.Items.wiredModem ) + .addIngredient( ComputerCraft.Blocks.wiredModemFull ) + .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) ) + .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.wirelessModemNormal ) + .patternLine( "###" ) + .patternLine( "#E#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.STONE ) + .key( 'E', Tags.Items.ENDER_PEARLS ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .build( add ); + + ShapedRecipeBuilder + .shapedRecipe( ComputerCraft.Blocks.wirelessModemAdvanced ) + .patternLine( "###" ) + .patternLine( "#E#" ) + .patternLine( "###" ) + .key( '#', Tags.Items.INGOTS_GOLD ) + .key( 'E', Items.ENDER_EYE ) + .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) + .addCriterion( "has_wireless", inventoryChange( ComputerCraft.Blocks.wirelessModemNormal ) ) + .build( add ); + } + private static DyeColor ofColour( Colour colour ) { return DyeColor.byId( 15 - colour.ordinal() ); } + + private static InventoryChangeTrigger.Instance inventoryChange( Tag stack ) + { + return InventoryChangeTrigger.Instance.forItems( ItemPredicate.Builder.create().tag( stack ).build() ); + } + + private static InventoryChangeTrigger.Instance inventoryChange( IItemProvider... stack ) + { + return InventoryChangeTrigger.Instance.forItems( stack ); + } } diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java new file mode 100644 index 000000000..bc78e3e7b --- /dev/null +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -0,0 +1,52 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.data; + +import dan200.computercraft.ComputerCraft; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.ItemTagsProvider; +import net.minecraft.item.Item; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.Tag; +import net.minecraft.util.ResourceLocation; + +import static dan200.computercraft.data.Tags.CCTags.*; + +public class Tags extends ItemTagsProvider +{ + public static class CCTags + { + public static final Tag COMPUTER = item( "computer" ); + public static final Tag TURTLE = item( "turtle" ); + public static final Tag WIRED_MODEM = item( "wired_modem" ); + public static final Tag MONITOR = item( "monitor" ); + } + + public Tags( DataGenerator generator ) + { + super( generator ); + } + + @Override + protected void registerTags() + { + getBuilder( COMPUTER ) + .add( ComputerCraft.Items.computerNormal ) + .add( ComputerCraft.Items.computerAdvanced ) + .add( ComputerCraft.Items.computerCommand ); + getBuilder( TURTLE ).add( ComputerCraft.Items.turtleNormal, ComputerCraft.Items.turtleAdvanced ); + getBuilder( WIRED_MODEM ).add( ComputerCraft.Items.wiredModem, ComputerCraft.Blocks.wiredModemFull.asItem() ); + getBuilder( MONITOR ) + .add( ComputerCraft.Blocks.monitorNormal.asItem() ) + .add( ComputerCraft.Blocks.monitorAdvanced.asItem() ); + } + + private static Tag item( String name ) + { + return new ItemTags.Wrapper( new ResourceLocation( ComputerCraft.MOD_ID, name ) ); + } +} diff --git a/src/main/resources/data/computercraft/advancements/recipes/cable.json b/src/main/resources/data/computercraft/advancements/recipes/cable.json deleted file mode 100644 index e0aeae8ba..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/cable.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:cable" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_modem": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:cable" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:cable" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_modem", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/command_computer.json b/src/main/resources/data/computercraft/advancements/recipes/command_computer.json deleted file mode 100644 index 692278666..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/command_computer.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:command_computer" ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:command_block" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:command_computer" } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json deleted file mode 100644 index fa3783c51..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computer_advanced.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:advanced_computer" ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "tag": "forge:dusts/redstone" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:advanced_computer" } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/computer_normal.json b/src/main/resources/data/computercraft/advancements/recipes/computer_normal.json deleted file mode 100644 index 1ad34028d..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/computer_normal.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_computer" ] - }, - "criteria": { - "has_redstone": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "tag": "forge:dusts/redstone" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:normal_computer" } - } - }, - "requirements": [ - [ - "has_redstone", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/disk_drive.json b/src/main/resources/data/computercraft/advancements/recipes/disk_drive.json deleted file mode 100644 index b1225ca70..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/disk_drive.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:disk_drive" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:disk_drive" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json deleted file mode 100644 index 270f01765..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/monitor_advanced.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:monitor_advanced" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:monitor_advanced" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json b/src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json deleted file mode 100644 index b1076ddf0..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/monitor_normal.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_monitor" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:normal_monitor" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json deleted file mode 100644 index b74f2d529..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_advanced.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:pocket_computer_advanced" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_apple": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:golden_apple" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:pocket_computer_advanced" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_apple", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json b/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json deleted file mode 100644 index 02f6be078..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/pocket_computer_normal.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:normal_pocket_computer_normal" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_apple": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:golden_apple" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:pocket_computer_normal" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_apple", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/printer.json b/src/main/resources/data/computercraft/advancements/recipes/printer.json deleted file mode 100644 index 9e00f37a7..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/printer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:printer" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:printer" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/speaker.json b/src/main/resources/data/computercraft/advancements/recipes/speaker.json deleted file mode 100644 index 721c93595..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/speaker.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:speaker" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_noteblock": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "minecraft:note_block" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:speaker" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_noteblock", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json b/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json deleted file mode 100644 index 8819a76f5..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_advanced.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:wireless_modem_advanced" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_wireless": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:wireless_modem_normal" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:wireless_modem_advanced" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_wireless", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json b/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json deleted file mode 100644 index f82624da3..000000000 --- a/src/main/resources/data/computercraft/advancements/recipes/wireless_modem_normal.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ "computercraft:wireless_modem_normal" ] - }, - "criteria": { - "has_normal": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_normal" } ] - } - }, - "has_advanced": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ { "item": "computercraft:computer_advanced" } ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { "recipe": "computercraft:wireless_modem_normal" } - } - }, - "requirements": [ - [ - "has_normal", - "has_advanced", - "has_the_recipe" - ] - ] -} diff --git a/src/main/resources/data/computercraft/recipes/cable.json b/src/main/resources/data/computercraft/recipes/cable.json deleted file mode 100644 index 09115ec12..000000000 --- a/src/main/resources/data/computercraft/recipes/cable.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - " # ", - "#R#", - " # " - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" } - }, - "result": { "item": "computercraft:cable", "count": 6 } -} diff --git a/src/main/resources/data/computercraft/recipes/computer_advanced.json b/src/main/resources/data/computercraft/recipes/computer_advanced.json deleted file mode 100644 index 81afaad43..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_advanced.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "R": { "tag": "forge:dusts/redstone" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:computer_advanced" } -} diff --git a/src/main/resources/data/computercraft/recipes/computer_command.json b/src/main/resources/data/computercraft/recipes/computer_command.json deleted file mode 100644 index c89aa7f6d..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_command.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "item": "minecraft:command_block" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:computer_command" } -} diff --git a/src/main/resources/data/computercraft/recipes/computer_normal.json b/src/main/resources/data/computercraft/recipes/computer_normal.json deleted file mode 100644 index 1761701bc..000000000 --- a/src/main/resources/data/computercraft/recipes/computer_normal.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#G#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:computer_normal" } -} diff --git a/src/main/resources/data/computercraft/recipes/disk_drive.json b/src/main/resources/data/computercraft/recipes/disk_drive.json deleted file mode 100644 index 59c78b50f..000000000 --- a/src/main/resources/data/computercraft/recipes/disk_drive.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#R#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" } - }, - "result": { "item": "computercraft:disk_drive" } -} diff --git a/src/main/resources/data/computercraft/recipes/monitor_advanced.json b/src/main/resources/data/computercraft/recipes/monitor_advanced.json deleted file mode 100644 index 6dc27ecff..000000000 --- a/src/main/resources/data/computercraft/recipes/monitor_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#G#", - "###" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:monitor_advanced", "count": 4 } -} diff --git a/src/main/resources/data/computercraft/recipes/monitor_normal.json b/src/main/resources/data/computercraft/recipes/monitor_normal.json deleted file mode 100644 index 8ee786686..000000000 --- a/src/main/resources/data/computercraft/recipes/monitor_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#G#", - "###" - ], - "key": { - "#": { "tag": "forge:stone" }, - "G": { "item": "minecraft:glass_pane" } - }, - "result": { "item": "computercraft:monitor_normal" } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json b/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json deleted file mode 100644 index f4119b18b..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_advanced.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#A#", - "#G#" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "G": { "item": "minecraft:glass_pane" }, - "A": { "item": "minecraft:golden_apple" } - }, - "result": { "item": "computercraft:pocket_computer_advanced" } -} diff --git a/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json b/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json deleted file mode 100644 index f01612779..000000000 --- a/src/main/resources/data/computercraft/recipes/pocket_computer_normal.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#A#", - "#G#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "G": { "item": "minecraft:glass_pane" }, - "A": { "item": "minecraft:golden_apple" } - }, - "result": { "item": "computercraft:pocket_computer_normal" } -} diff --git a/src/main/resources/data/computercraft/recipes/printer.json b/src/main/resources/data/computercraft/recipes/printer.json deleted file mode 100644 index 4d120a541..000000000 --- a/src/main/resources/data/computercraft/recipes/printer.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "#D#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "item": "minecraft:glass_pane" }, - "D": { "tag": "forge:dyes" } - }, - "result": { "item": "computercraft:printer" } -} diff --git a/src/main/resources/data/computercraft/recipes/speaker.json b/src/main/resources/data/computercraft/recipes/speaker.json deleted file mode 100644 index 6c0cf7595..000000000 --- a/src/main/resources/data/computercraft/recipes/speaker.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#N#", - "#R#" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" }, - "N": { "item": "minecraft:note_block" } - }, - "result": { "item": "computercraft:speaker" } -} diff --git a/src/main/resources/data/computercraft/recipes/wired_modem.json b/src/main/resources/data/computercraft/recipes/wired_modem.json deleted file mode 100644 index fa9e47af2..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#R#", - "###" - ], - "key": { - "#": { "tag": "forge:stone" }, - "R": { "tag": "forge:dusts/redstone" } - }, - "result": { "item": "computercraft:wired_modem" } -} diff --git a/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json b/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json deleted file mode 100644 index f9579b354..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem_full_from.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "crafting_shapeless", - "ingredients": [ - { "item": "computercraft:wired_modem_full" } - ], - "result": { "item": "computercraft:wired_modem" } -} diff --git a/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json b/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json deleted file mode 100644 index 204170660..000000000 --- a/src/main/resources/data/computercraft/recipes/wired_modem_full_to.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "type": "crafting_shapeless", - "ingredients": [ - { "item": "computercraft:wired_modem" } - ], - "result": { "item": "computercraft:wired_modem_full" } -} diff --git a/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json b/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json deleted file mode 100644 index 3d3297d6c..000000000 --- a/src/main/resources/data/computercraft/recipes/wireless_modem_advanced.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#E#", - "###" - ], - "key": { - "#": { "tag": "forge:ingots/gold" }, - "E": { "item": "minecraft:ender_eye" } - }, - "result": { "item": "computercraft:wireless_modem_advanced" } -} diff --git a/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json b/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json deleted file mode 100644 index 3005edd7d..000000000 --- a/src/main/resources/data/computercraft/recipes/wireless_modem_normal.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "crafting_shaped", - "pattern": [ - "###", - "#E#", - "###" - ], - "key": { - "#": { "tag": "forge:stone" }, - "E": { "item": "minecraft:ender_pearl" } - }, - "result": { "item": "computercraft:wireless_modem_normal" } -} From 68762fe84c1eff4f3ce32f23c01c597fc408222d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 9 Apr 2020 22:06:53 +0100 Subject: [PATCH 157/711] Switch FileMount to use Files.walkFileTree This means we are already provided with file attributes, which halfs[^1] the time taken to scan folders. [^1]: This dropped the fastest scan time from ~1.3s to ~0.6. It's by no means a perfect benchmark, but this is still an obvious improvement. --- .../core/filesystem/FileMount.java | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index 13cf9b062..9cf1ecd3e 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.filesystem; import com.google.common.collect.Sets; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.FileOperationException; import dan200.computercraft.api.filesystem.IWritableMount; @@ -13,9 +14,7 @@ import javax.annotation.Nonnull; import java.io.*; import java.nio.ByteBuffer; import java.nio.channels.*; -import java.nio.file.Files; -import java.nio.file.OpenOption; -import java.nio.file.StandardOpenOption; +import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.Collections; import java.util.List; @@ -404,23 +403,46 @@ public class FileMount implements IWritableMount } } + private static class Visitor extends SimpleFileVisitor + { + long size; + + @Override + public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs ) + { + size += MINIMUM_FILE_SIZE; + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile( Path file, BasicFileAttributes attrs ) + { + size += Math.max( attrs.size(), MINIMUM_FILE_SIZE ); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed( Path file, IOException exc ) + { + ComputerCraft.log.error( "Error computing file size for {}", file, exc ); + return FileVisitResult.CONTINUE; + } + } + private static long measureUsedSpace( File file ) { if( !file.exists() ) return 0; - if( file.isDirectory() ) + try { - long size = MINIMUM_FILE_SIZE; - String[] contents = file.list(); - for( String content : contents ) - { - size += measureUsedSpace( new File( file, content ) ); - } - return size; + Visitor visitor = new Visitor(); + Files.walkFileTree( file.toPath(), visitor ); + return visitor.size; } - else + catch( IOException e ) { - return Math.max( file.length(), MINIMUM_FILE_SIZE ); + ComputerCraft.log.error( "Error computing file size for {}", file, e ); + return 0; } } } From 68e6bc464b69c55dd64e7d17d12a34a6160e8d8f Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Thu, 9 Apr 2020 22:15:06 +0100 Subject: [PATCH 158/711] Bump illuaminate version For now, we just perform the minimal number of changes to get this working. We'll switch to a more strict bracket handling system in the future. --- .github/workflows/main-ci.yml | 2 +- .../resources/assets/computercraft/lua/bios.lua | 8 ++++---- .../assets/computercraft/lua/rom/apis/term.lua | 2 +- .../computercraft/lua/rom/apis/textutils.lua | 6 +++--- .../lua/rom/modules/main/cc/pretty.lua | 2 +- .../lua/rom/modules/main/cc/shell/completion.lua | 2 +- .../assets/computercraft/lua/rom/programs/edit.lua | 4 ++-- .../lua/rom/programs/fun/advanced/paint.lua | 2 +- .../lua/rom/programs/fun/advanced/redirection.lua | 2 +- .../lua/rom/programs/fun/adventure.lua | 2 +- .../computercraft/lua/rom/programs/fun/dj.lua | 2 +- .../computercraft/lua/rom/programs/fun/worm.lua | 2 +- .../lua/rom/programs/pocket/falling.lua | 2 +- .../computercraft/lua/rom/programs/rednet/chat.lua | 2 +- .../assets/computercraft/lua/rom/startup.lua | 4 ++-- src/test/resources/test-rom/mcfly.lua | 2 +- .../resources/test-rom/spec/apis/http_spec.lua | 14 +++++++------- .../spec/modules/cc/shell/completion_spec.lua | 2 +- .../test-rom/spec/programs/http/pastebin_spec.lua | 4 ++-- .../test-rom/spec/programs/peripherals_spec.lua | 2 +- 20 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 924abb37a..0aee2ef4f 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -42,7 +42,7 @@ jobs: - name: Lint Lua code run: | test -d bin || mkdir bin - test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/bin/illuaminate + test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate chmod +x bin/illuaminate bin/illuaminate lint diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 500276da4..a7f7a9d21 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -253,7 +253,7 @@ end function print( ... ) local nLinesPrinted = 0 - local nLimit = select("#", ... ) + local nLimit = select("#", ...) for n = 1, nLimit do local s = tostring( select( n, ... ) ) if n < nLimit then @@ -695,7 +695,7 @@ if http then end local function checkOptions( options, body ) - checkKey( options, "url", "string") + checkKey( options, "url", "string" ) if body == false then checkKey( options, "body", "nil" ) else @@ -725,7 +725,7 @@ if http then return nil, err end - http.get = function( _url, _headers, _binary) + http.get = function(_url, _headers, _binary) if type( _url ) == "table" then checkOptions( _url, false ) return wrapRequest( _url.url, _url ) @@ -737,7 +737,7 @@ if http then return wrapRequest( _url, _url, nil, _headers, _binary ) end - http.post = function( _url, _post, _headers, _binary) + http.post = function(_url, _post, _headers, _binary) if type( _url ) == "table" then checkOptions( _url, true ) return wrapRequest( _url.url, _url ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index 706bd16f6..c6f9c2a9b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -43,7 +43,7 @@ end -- Some methods shouldn't go through redirects, so we move them to the main -- term API. -for _, method in ipairs { "nativePaletteColor", "nativePaletteColour"} do +for _, method in ipairs { "nativePaletteColor", "nativePaletteColour" } do term[method] = native[method] native[method] = nil end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 38360ea71..de7cd4e95 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -346,10 +346,10 @@ function urlEncode( str ) else -- Non-ASCII (encode as UTF-8) return - string.format("%%%02X", 192 + bit32.band( bit32.arshift(n, 6), 31 ) ) .. - string.format("%%%02X", 128 + bit32.band( n, 63 ) ) + string.format("%%%02X", 192 + bit32.band( bit32.arshift(n, 6), 31 )) .. + string.format("%%%02X", 128 + bit32.band( n, 63 )) end - end ) + end) str = string.gsub(str, " ", "+") end return str diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua index cf0007568..2fdaee187 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -393,7 +393,7 @@ end -- @treturn Doc The object formatted as a document. -- @usage Display a table on the screen -- local pretty = require "cc.pretty" --- pretty.print(pretty.pretty({ 1, 2, 3 }) +-- pretty.print(pretty.pretty({ 1, 2, 3 })) local function pretty(obj) return pretty_impl(obj, {}) end diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua index 865e54dcb..d89c72a91 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -97,7 +97,7 @@ end -- complete.build( -- { complete.choice, { "get", "put" } }, -- complete.dir, --- } complete.file, many = true } +-- { complete.file, many = true } -- ) local function build(...) local arguments = table.pack(...) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index 5e6cfee1c..0125d5b12 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -15,7 +15,7 @@ end -- Create .lua files by default if not fs.exists( sPath ) and not string.find( sPath, "%." ) then - local sExtension = settings.get("edit.default_extension", "" ) + local sExtension = settings.get("edit.default_extension", "") if sExtension ~= "" and type( sExtension ) == "string" then sPath = sPath .. "." .. sExtension end @@ -85,7 +85,7 @@ end local function save( _sPath ) -- Create intervening folder - local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len() ) + local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len()) if not fs.exists( sDir ) then fs.makeDir( sDir ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index 758e82074..d2f3a5159 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -46,7 +46,7 @@ end -- Create .nfp files by default if not fs.exists( sPath ) and not string.find( sPath, "%." ) then - local sExtension = settings.get("paint.default_extension", "" ) + local sExtension = settings.get("paint.default_extension", "") if sExtension ~= "" and type( sExtension ) == "string" then sPath = sPath .. "." .. sExtension end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua index fc6e0f038..3f68e3859 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua @@ -525,7 +525,7 @@ function InterFace.drawBar() term.setCursorPos( TermW - 8, TermH ) term.setBackgroundColor( colors.black ) term.setTextColour(InterFace.cSpeedD) - write(" <<" ) + write(" <<") if bPaused then term.setTextColour(InterFace.cSpeedA) else diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua index 17c2b9a2b..48e06a950 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua @@ -1001,7 +1001,7 @@ function commands.cbreak( _sItem, _sTool ) end end else - print( "You can't break " .. sItem .. " with " .. sTool .. ".") + print("You can't break " .. sItem .. " with " .. sTool .. ".") end elseif tItem.creature == true then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua index 78b259fe0..5ec03d2ce 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua @@ -1,7 +1,7 @@ local tArgs = { ... } local function printUsage() - print( "Usages:") + print( "Usages:" ) print( "dj play" ) print( "dj play " ) print( "dj stop" ) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua index 507763cb4..e02654d1f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua @@ -89,7 +89,7 @@ local function drawMenu() term.setTextColour( headingColour ) term.setCursorPos(w - 11, 1) - term.write( "DIFFICULTY ") + term.write( "DIFFICULTY " ) term.setTextColour( textColour ) term.setCursorPos(w, 1) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua index bdc922e4f..330042936 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua @@ -158,7 +158,7 @@ local block_T = { bg = colorass(colors.purple, colors.white), } -local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T} +local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T } local points = {4, 10, 30, 120} diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index 4c4ae75c0..ac8f4bc65 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -387,7 +387,7 @@ elseif sCommand == "join" then promptWindow.setCursorPos( 1, 1 ) promptWindow.clearLine() promptWindow.setTextColor( highlightColour ) - promptWindow.write( ": ") + promptWindow.write( ": " ) promptWindow.setTextColor( textColour ) local sChat = read( nil, tSendHistory ) diff --git a/src/main/resources/assets/computercraft/lua/rom/startup.lua b/src/main/resources/assets/computercraft/lua/rom/startup.lua index dcefffb93..e19eb0317 100644 --- a/src/main/resources/assets/computercraft/lua/rom/startup.lua +++ b/src/main/resources/assets/computercraft/lua/rom/startup.lua @@ -43,7 +43,7 @@ end local function completePastebinPut(shell, text, previous) if previous[2] == "put" then - return fs.complete(text, shell.dir(), true, false ) + return fs.complete( text, shell.dir(), true, false ) end end @@ -106,7 +106,7 @@ if turtle then ) ) shell.setCompletionFunction( "rom/programs/turtle/turn.lua", completion.build( { completion.choice, { "left", "right" }, true, many = true } - )) + ) ) shell.setCompletionFunction( "rom/programs/turtle/equip.lua", completion.build( nil, { completion.choice, { "left", "right" } } diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index ac64ad565..20dcd4cd2 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -356,7 +356,7 @@ function expect_mt:called_with_matching(...) return called_with_check(matches, self, ...) end -local expect = setmetatable( { +local expect = setmetatable({ --- Construct an expectation on the error message calling this function -- produces -- diff --git a/src/test/resources/test-rom/spec/apis/http_spec.lua b/src/test/resources/test-rom/spec/apis/http_spec.lua index a6774a48c..ecaf1d307 100644 --- a/src/test/resources/test-rom/spec/apis/http_spec.lua +++ b/src/test/resources/test-rom/spec/apis/http_spec.lua @@ -1,19 +1,19 @@ describe("The http library", function() describe("http.checkURL", function() it("accepts well formed domains", function() - expect({ http.checkURL("https://google.com")}):same({ true }) + expect({ http.checkURL("https://google.com") }):same({ true }) end) it("rejects malformed URLs", function() - expect({ http.checkURL("google.com")}):same({ false, "Must specify http or https" }) - expect({ http.checkURL("https:google.com")}):same({ false, "URL malformed" }) - expect({ http.checkURL("https:/google.com")}):same({ false, "URL malformed" }) - expect({ http.checkURL("wss://google.com")}):same({ false, "Invalid protocol 'wss'" }) + expect({ http.checkURL("google.com") }):same({ false, "Must specify http or https" }) + expect({ http.checkURL("https:google.com") }):same({ false, "URL malformed" }) + expect({ http.checkURL("https:/google.com") }):same({ false, "URL malformed" }) + expect({ http.checkURL("wss://google.com") }):same({ false, "Invalid protocol 'wss'" }) end) it("rejects local domains", function() - expect({ http.checkURL("http://localhost")}):same({ false, "Domain not permitted" }) - expect({ http.checkURL("http://127.0.0.1")}):same({ false, "Domain not permitted" }) + expect({ http.checkURL("http://localhost") }):same({ false, "Domain not permitted" }) + expect({ http.checkURL("http://127.0.0.1") }):same({ false, "Domain not permitted" }) end) end) end) diff --git a/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua index ffcd3b7f3..6b2c0aaa1 100644 --- a/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/shell/completion_spec.lua @@ -22,7 +22,7 @@ describe("cc.shell.completion", function() local spec = c.build( function() return { "a", "b", "c" } end, nil, - { c.choice, { "d", "e", "f"} } + { c.choice, { "d", "e", "f" } } ) expect(spec(shell, 1, "")):same { "a", "b", "c" } diff --git a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua index 831d88fc1..61bfe833b 100644 --- a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -52,14 +52,14 @@ describe("The pastebin program", function() local file = fs.open( "testup", "w" ) file.close() - expect(capture(stub, "pastebin", "put", "testup" )) + expect(capture(stub, "pastebin", "put", "testup")) :matches { ok = true, output = "Connecting to pastebin.com... Success.\nUploaded as https://pastebin.com/abcde\nRun \"pastebin get abcde\" to download anywhere\n", error = "" } end) it("upload a not existing program to pastebin", function() setup_request() - expect(capture(stub, "pastebin", "put", "nothing" )) + expect(capture(stub, "pastebin", "put", "nothing")) :matches { ok = true, output = "No such file\n", error = "" } end) diff --git a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua index f52961a13..6c9d433bd 100644 --- a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua +++ b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua @@ -2,7 +2,7 @@ local capture = require "test_helpers".capture_program describe("The peripherals program", function() it("says when there are no peripherals", function() - expect(capture(stub, "peripherals" )) + expect(capture(stub, "peripherals")) :matches { ok = true, output = "Attached Peripherals:\nNone\n", error = "" } end) end) From a8ce5a5b2015f65f71f1ae2e75944cb57844736a Mon Sep 17 00:00:00 2001 From: "Christian L.W" Date: Thu, 9 Apr 2020 23:30:20 +0200 Subject: [PATCH 159/711] Add Danish translation (#395) --- .../assets/computercraft/lang/da_dk.lang | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 src/main/resources/assets/computercraft/lang/da_dk.lang diff --git a/src/main/resources/assets/computercraft/lang/da_dk.lang b/src/main/resources/assets/computercraft/lang/da_dk.lang new file mode 100644 index 000000000..3da64d2a4 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/da_dk.lang @@ -0,0 +1,48 @@ +tile.computercraft:computer.name=Computer +tile.computercraft:advanced_computer.name=Avanceret Computer +tile.computercraft:drive.name=Diskdrev +tile.computercraft:printer.name=Printer +tile.computercraft:monitor.name=Skærm +tile.computercraft:advanced_monitor.name=Avanceret Skærm +tile.computercraft:wireless_modem.name=TrÃ¥dløst Modem +tile.computercraft:wired_modem.name=Kablet Modem +tile.computercraft:cable.name=Netværkskabel +tile.computercraft:command_computer.name=Kommandocomputer +tile.computercraft:advanced_modem.name=Endermodem +tile.computercraft:speaker.name=Højttaler + +tile.computercraft:turtle.name=Turtle +tile.computercraft:turtle.upgraded.name=%s Turtle +tile.computercraft:turtle.upgraded_twice.name=%s %s Turtle +tile.computercraft:advanced_turtle.name=Avanceret Turtle +tile.computercraft:advanced_turtle.upgraded.name=Avanceret %s Turtle +tile.computercraft:advanced_turtle.upgraded_twice.name=Avanceret %s %s Turtle + +item.computercraft:disk.name=Floppydisk +item.computercraft:treasure_disk.name=Floppydisk +item.computercraft:page.name=Printet Side +item.computercraft:pages.name=Printede Sider +item.computercraft:book.name=Printet Bog + +item.computercraft:pocket_computer.name=Lommecomputer +item.computercraft:pocket_computer.upgraded.name=%s Lommecomputer +item.computercraft:advanced_pocket_computer.name=Avanceret Lommecomputer +item.computercraft:advanced_pocket_computer.upgraded.name=Avanceret %s Lommecomputer + +upgrade.minecraft:diamond_sword.adjective=Kæmpende +upgrade.minecraft:diamond_shovel.adjective=Gravende +upgrade.minecraft:diamond_pickaxe.adjective=Brydende +upgrade.minecraft:diamond_axe.adjective=Fældende +upgrade.minecraft:diamond_hoe.adjective=Dyrkende +upgrade.computercraft:wireless_modem.adjective=TrÃ¥dløs +upgrade.minecraft:crafting_table.adjective=Fremstillende +upgrade.computercraft:advanced_modem.adjective=EndertrÃ¥dløs +upgrade.computercraft:speaker.adjective=Larmende + +chat.computercraft.wired_modem.peripheral_connected=Perifer enhed "%s" koblet til netværk +chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet fra netværk + +# Misc tooltips +gui.computercraft.tooltip.copy=Kopier til udklipsholder +gui.computercraft.tooltip.computer_id=(Computer-ID: %s) +gui.computercraft.tooltip.disk_id=(Disk-ID: %s) From 1ccd687c009f3a915ce76cfa36bcbffc4bbd474b Mon Sep 17 00:00:00 2001 From: "E. Kim" Date: Fri, 10 Apr 2020 06:31:20 +0900 Subject: [PATCH 160/711] Create ko_kr.lang (#381) --- .../assets/computercraft/lang/ko_kr.lang | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 src/main/resources/assets/computercraft/lang/ko_kr.lang diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.lang b/src/main/resources/assets/computercraft/lang/ko_kr.lang new file mode 100644 index 000000000..784bb4b31 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/ko_kr.lang @@ -0,0 +1,195 @@ +itemGroup.computercraft=컴퓨터í¬ëž˜í”„트 + +tile.computercraft:computer.name=컴퓨터 +tile.computercraft:advanced_computer.name=고급 컴퓨터 +tile.computercraft:drive.name=ë””ìŠ¤í¬ ë“œë¼ì´ë¸Œ +tile.computercraft:printer.name=프린터 +tile.computercraft:monitor.name=모니터 +tile.computercraft:advanced_monitor.name=고급 모니터 +tile.computercraft:wireless_modem.name=무선 모뎀 +tile.computercraft:wired_modem.name=유선 모뎀 +tile.computercraft:cable.name=ë„¤íŠ¸ì›Œí¬ ì¼€ì´ë¸” +tile.computercraft:command_computer.name=명령 컴퓨터 +tile.computercraft:advanced_modem.name=ì—”ë” ëª¨ëŽ€ +tile.computercraft:speaker.name=스피커 + +tile.computercraft:turtle.name=í„°í‹€ +tile.computercraft:turtle.upgraded.name=%s í„°í‹€ +tile.computercraft:turtle.upgraded_twice.name=%s %s í„°í‹€ +tile.computercraft:advanced_turtle.name=고급 í„°í‹€ +tile.computercraft:advanced_turtle.upgraded.name=고급 %s í„°í‹€ +tile.computercraft:advanced_turtle.upgraded_twice.name=고급 %s %s í„°í‹€ + +item.computercraft:disk.name=플로피 ë””ìŠ¤í¬ +item.computercraft:treasure_disk.name=플로피 ë””ìŠ¤í¬ +item.computercraft:page.name=ì¸ì‡„ëœ íŽ˜ì´ì§€ +item.computercraft:pages.name=ì¸ì‡„ëœ íŽ˜ì´ì§€ ëª¨ìŒ +item.computercraft:book.name=ì¸ì‡„ëœ ì±… + +item.computercraft:pocket_computer.name=í¬ì¼“ 컴퓨터 +item.computercraft:pocket_computer.upgraded.name=%s í¬ì¼“ 컴퓨터 +item.computercraft:advanced_pocket_computer.name=고급 í¬ì¼“ 컴퓨터 +item.computercraft:advanced_pocket_computer.upgraded.name=고급 %s í¬ì¼“ 컴퓨터 + +upgrade.minecraft:diamond_sword.adjective=난투 +upgrade.minecraft:diamond_shovel.adjective=êµ´ì°© +upgrade.minecraft:diamond_pickaxe.adjective=채굴 +upgrade.minecraft:diamond_axe.adjective=벌목 +upgrade.minecraft:diamond_hoe.adjective=ë†ì—… +upgrade.computercraft:wireless_modem.adjective=무선 +upgrade.minecraft:crafting_table.adjective=ì¡°í•© +upgrade.computercraft:advanced_modem.adjective=ì—”ë” +upgrade.computercraft:speaker.adjective=ì†ŒìŒ + +chat.computercraft.wired_modem.peripheral_connected=주변 "%s"ì´ ë„¤íŠ¸ì›Œí¬ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤. +chat.computercraft.wired_modem.peripheral_disconnected=주변 "%s"ì´ ë„¤íŠ¸ì›Œí¬ë¡œë¶€í„° 분리ë˜ì—ˆìŠµë‹ˆë‹¤. + +# Command descriptions, usage and any additional messages. +commands.computercraft.synopsis=컴퓨터를 제어하기 위한 다양한 명령어 +commands.computercraft.desc=/computercraft 명령어는 컴퓨터를 제어하고 ìƒí˜¸ìž‘용하기 위한 다양한 디버깅 ë° ê´€ë¦¬ìž ë„구를 제공합니다. + +commands.computercraft.help.synopsis=특정 ëª…ë ¹ì–´ì— ëŒ€í•œ ë„움ë§ì„ 제공하기 +commands.computercraft.help.desc= +commands.computercraft.help.usage=[command] +commands.computercraft.help.no_children=%sì—는 하위 명령어가 없습니다. +commands.computercraft.help.no_command='%s'ë¼ëŠ” 명령어가 없습니다. + +commands.computercraft.dump.synopsis=ì»´í“¨í„°ì˜ ìƒíƒœë¥¼ 보여주기 +commands.computercraft.dump.desc=모든 ì‹œìŠ¤í…œì˜ ìƒíƒœ ë˜ëŠ” 한 ì‹œìŠ¤í…œì— ëŒ€í•œ 특정 정보를 표시합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: "@My Computer")ì„ ì§€ì •í•  수 있습니다. +commands.computercraft.dump.usage=[id] +commands.computercraft.dump.action=ì´ ì»´í“¨í„°ì— ëŒ€í•œ 추가 정보를 봅니다. + +commands.computercraft.shutdown.synopsis=ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 종료하기 +commands.computercraft.shutdown.desc=ë‚˜ì—´ëœ ì‹œìŠ¤í…œ ë˜ëŠ” ì§€ì •ëœ ì‹œìŠ¤í…œì´ ì—†ëŠ” 경우 ëª¨ë‘ ì¢…ë£Œí•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: "@My Computer")ì„ ì§€ì •í•  수 있습니다. +commands.computercraft.shutdown.usage=[ids...] +commands.computercraft.shutdown.done=%s/%s 컴퓨터 시스템 종료 + +commands.computercraft.turn_on.synopsis=ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 실행하기 +commands.computercraft.turn_on.desc=ë‚˜ì—´ëœ ì»´í“¨í„°ë¥¼ 실행합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: "@My Computer")ì„ ì§€ì •í•  수 있습니다. +commands.computercraft.turn_on.usage=[ids...] +commands.computercraft.turn_on.done=%s/%s 컴퓨터 시스템 실행 + +commands.computercraft.tp.synopsis=특정 컴퓨터로 순간ì´ë™í•˜ê¸° +commands.computercraft.tp.desc=ì»´í“¨í„°ì˜ ìœ„ì¹˜ë¡œ 순간ì´ë™í•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다. +commands.computercraft.tp.usage= +commands.computercraft.tp.action=ì´ ì»´í“¨í„°ë¡œ 순간ì´ë™í•˜ê¸° +commands.computercraft.tp.not_entity=비플레ì´ì–´í•œí…Œ 터미ë„ì„ ì—´ 수 없습니다. +commands.computercraft.tp.not_there=월드ì—서 컴퓨터를 위치시킬 수 없습니다. + +commands.computercraft.view.synopsis=ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ë³´ê¸° +commands.computercraft.view.desc=ì»´í“¨í„°ì˜ ì›ê²© 제어를 허용하는 ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ì—½ë‹ˆë‹¤. ì´ê²ƒì€ í„°í‹€ì˜ ì¸ë²¤í† ë¦¬ì— 대한 ì ‘ê·¼ì„ ì œê³µí•˜ì§€ 않습니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다. +commands.computercraft.view.usage= +commands.computercraft.view.action=ì´ ì»´í“¨í„°ë¥¼ 봅니다. +commands.computercraft.view.not_player=비플레ì´ì–´í•œí…Œ 터미ë„ì„ ì—´ 수 없습니다. + +commands.computercraft.track.synopsis=ì»´í“¨í„°ì˜ ì‹¤í–‰ ì‹œê°„ì„ ì¶”ì í•˜ê¸° +commands.computercraft.track.desc=컴퓨터가 실행ë˜ëŠ” 기간과 처리ë˜ëŠ” ì´ë²¤íЏ 수를 ì¶”ì í•©ë‹ˆë‹¤. ì´ëŠ” /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 ë¡œê·¸ì— ìœ ìš©í•  수 있습니다. + +commands.computercraft.track.start.synopsis=모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 시작하기 +commands.computercraft.track.start.desc=모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 시작합니다. ì´ëŠ” ì´ì „ ì‹¤í–‰ì˜ ê²°ê³¼ë¥¼ í기할 것입니다. +commands.computercraft.track.start.usage= +commands.computercraft.track.start.stop=%sì„(를) 실행하여 ì¶”ì ì„ 중지하고 결과를 확ì¸í•©ë‹ˆë‹¤. + +commands.computercraft.track.stop.synopsis=모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 중지하기 +commands.computercraft.track.stop.desc=모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 중지합니다. +commands.computercraft.track.stop.usage= +commands.computercraft.track.stop.action=ì¶”ì ì„ 중지하려면 í´ë¦­í•˜ì„¸ìš”. +commands.computercraft.track.stop.not_enabled=현재 ì¶”ì í•˜ëŠ” 컴퓨터가 없습니다. + +commands.computercraft.track.dump.synopsis=최신 ì¶”ì  ê²°ê³¼ë¥¼ ë¤í”„하기 +commands.computercraft.track.dump.desc=최신 컴퓨터 ì¶”ì ì˜ 결과를 ë¤í”„합니다. +commands.computercraft.track.dump.usage=[kind] +commands.computercraft.track.dump.no_timings=사용가능한 ì‹œê°„ì´ ì—†ìŠµë‹ˆë‹¤. +commands.computercraft.track.dump.no_field=알 수 없는 필드 '%s' +commands.computercraft.track.dump.computer=컴퓨터 + +commands.computercraft.reload.synopsis=컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드하기 +commands.computercraft.reload.desc=컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드합니다. +commands.computercraft.reload.usage= +commands.computercraft.reload.done=ë¦¬ë¡œë“œëœ êµ¬ì„± + +commands.computercraft.queue.synopsis=computer_command ì´ë²¤íŠ¸ë¥¼ 명령 ì»´í“¨í„°ì— ë³´ë‚´ê¸° +commands.computercraft.queue.desc=computer_command ì´ë²¤íŠ¸ë¥¼ 명령 컴퓨터로 전송하여 추가 ì¸ìˆ˜ë¥¼ 전달합니다. ì´ëŠ” 대부분 ì§€ë„ ì œìž‘ìžë¥¼ 위해 설계ë˜ì—ˆìœ¼ë©°, 보다 컴퓨터 친화ì ì¸ ë²„ì „ì˜ /trigger ì—­í• ì„ í•©ë‹ˆë‹¤. ì–´ë–¤ 플레ì´ì–´ë“  ëª…ë ¹ì„ ì‹¤í–‰í•  수 있으며, ì´ëŠ” í…스트 구성 ìš”ì†Œì˜ í´ë¦­ ì´ë²¤íŠ¸ë¥¼ 통해 ìˆ˜í–‰ë  ê°€ëŠ¥ì„±ì´ ê°€ìž¥ 높습니다. +commands.computercraft.queue.usage= [args...] + +commands.computercraft.generic.no_position= +commands.computercraft.generic.position=%s, %s, %s +commands.computercraft.generic.yes=Y +commands.computercraft.generic.no=N +commands.computercraft.generic.exception=처리ë˜ì§€ ì•Šì€ ì˜ˆì™¸ (%s) +commands.computercraft.generic.additional_rows=%dê°œì˜ ì¶”ê°€ í–‰... + +commands.computercraft.argument.no_matching='%s'와 ì¼ì¹˜í•˜ëŠ” 컴퓨터가 없습니다. +commands.computercraft.argument.many_matching='%s'와 ì¼ì¹˜í•˜ëŠ” 여러 컴퓨터 (ì¸ìŠ¤í„´ìŠ¤ %s) +commands.computercraft.argument.not_number='%s'는 숫ìžê°€ 아닙니다. + +# Names for the various tracking fields. +tracking_field.computercraft.tasks.name=작업 +tracking_field.computercraft.total.name=ì „ì²´ 시간 +tracking_field.computercraft.average.name=í‰ê·  시간 +tracking_field.computercraft.max.name=최대 시간 + +tracking_field.computercraft.server_count.name=서버 작업 수 +tracking_field.computercraft.server_time.name=서버 작업 시간 + +tracking_field.computercraft.peripheral.name=주변 호출 +tracking_field.computercraft.fs.name=파ì¼ì‹œìŠ¤í…œ 작업 +tracking_field.computercraft.turtle.name=í„°í‹€ 작업 + +tracking_field.computercraft.http.name=HTTP 요청 +tracking_field.computercraft.http_upload.name=HTTP 업로드 +tracking_field.computercraft.http_download.name=HTTT 다운로드 + +tracking_field.computercraft.websocket_incoming.name=웹소켓 수신 +tracking_field.computercraft.websocket_outgoing.name=웹소켓 송신 + +tracking_field.computercraft.coroutines_created.name=코루틴 ìƒì„±ë¨ +tracking_field.computercraft.coroutines_dead.name=코루틴 ì²˜ë¦¬ë¨ + +# Misc tooltips +gui.computercraft.tooltip.copy=í´ë¦½ë³´ë“œì— 복사 +gui.computercraft.tooltip.computer_id=(컴퓨터 ID: %s) +gui.computercraft.tooltip.disk_id=(ë””ìŠ¤í¬ ID: %s) + +# Config options +gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (ë°”ì´íЏ) +gui.computercraft:config.floppy_space_limit=플로피 ë””ìŠ¤í¬ ê³µê°„ 제한 (ë°”ì´íЏ) +gui.computercraft:config.maximum_open_files=컴퓨터당 최대 íŒŒì¼ ì—´ê¸° +gui.computercraft:config.disable_lua51_features=Lua 5.1 기능 미사용 +gui.computercraft:config.default_computer_settings=기본 컴퓨터 설정 +gui.computercraft:config.debug_enabled=디버그 ë¼ì´ë¸ŒëŸ¬ë¦¬ 사용 +gui.computercraft:config.log_computer_errors=컴퓨터 오류 로그 + +gui.computercraft:config.execution=실행 +gui.computercraft:config.execution.computer_threads=컴퓨터 쓰레드 +gui.computercraft:config.execution.max_main_global_time=ì „ì—­ 시간 당 서버 제한 +gui.computercraft:config.execution.max_main_computer_time=컴퓨터 시간 당 서버 제한 + +gui.computercraft:config.http=HTTP +gui.computercraft:config.http.enabled=HTTP API 사용하기 +gui.computercraft:config.http.websocket_enabled=웹소켓 사용 +gui.computercraft:config.http.allowed_domains=í—ˆìš©ëœ ë„ë©”ì¸ +gui.computercraft:config.http.blocked_domains=ì°¨ë‹¨ëœ ë„ë©”ì¸ + +gui.computercraft:config.http.timeout=타임아웃 +gui.computercraft:config.http.max_requests=최대 ë™ì‹œ 요청 수 +gui.computercraft:config.http.max_download=최대 ì‘답 í¬ê¸° +gui.computercraft:config.http.max_upload=최대 요청 í¬ê¸° +gui.computercraft:config.http.max_websockets=최대 ë™ì‹œ 웹소켓 수 +gui.computercraft:config.http.max_websocket_message=최대 웹 í¬ì¼“ 메시지 í¬ê¸° + +gui.computercraft:config.peripheral=주변 +gui.computercraft:config.peripheral.command_block_enabled=명령 ë¸”ë¡ ì£¼ë³€ 장치 사용 +gui.computercraft:config.peripheral.modem_range=모뎀 범위(기본값) +gui.computercraft:config.peripheral.modem_high_altitude_range=모뎀 범위(ë†’ì€ ê³ ë„) +gui.computercraft:config.peripheral.modem_range_during_storm=모뎀 범위(ë‚˜ìœ ë‚ ì”¨) +gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=모뎀 범위(ë†’ì€ ê³ ë„, ë‚˜ìœ ë‚ ì”¨) +gui.computercraft:config.peripheral.max_notes_per_tick=컴퓨터가 한 ë²ˆì— ìž¬ìƒí•  수 있는 최대 소리 수 + +gui.computercraft:config.turtle=í„°í‹€ +gui.computercraft:config.turtle.need_fuel=연료 사용 +gui.computercraft:config.turtle.normal_fuel_limit=í„°í‹€ 연료 제한 +gui.computercraft:config.turtle.advanced_fuel_limit=고급 í„°í‹€ 연료 제한 +gui.computercraft:config.turtle.obey_block_protection=í„°í‹€ì´ ë¸”ë¡ ë³´í˜¸ì— ë”°ë¥´ê¸° +gui.computercraft:config.turtle.can_push=í„°í‹€ì´ ì—”í‹°í‹° 밀어내기 +gui.computercraft:config.turtle.disabled_actions=í„°í‹€ ì•¡ì…˜ 미사용 From ef8da8054f9b774d5f85b06c9a3f76de8be59b17 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 10 Apr 2020 10:27:53 +0100 Subject: [PATCH 161/711] An initial stab at documentation generation (#360) This adds documentation comments to many of CC's Lua APIs, and a couple of the Java ones, through the use of stubs. We then export these to HTML using illuaminate [1] and upload them to our documentation site [2]. Uploads currently occur on pushes to master and any release/tag. The site is entirely static - there is no way to switch between versions, etc... but hopefully we can improve this in the future. [1]: github.com/SquidDev/illuaminate/ [2]: https://tweaked.cc/ --- .editorconfig | 4 + .github/workflows/make-doc.sh | 16 ++ .github/workflows/make-doc.yml | 29 ++ .gitignore | 1 + README.md | 2 +- doc/index.md | 13 + logo.png => doc/logo.png | Bin doc/stub/commands.lua | 6 + doc/stub/fs.lua | 42 +++ doc/stub/http.lua | 213 +++++++++++++++ doc/stub/os.lua | 17 ++ doc/stub/redstone.lua | 14 + doc/stub/term.lua | 52 ++++ doc/stub/turtle.lua | 42 +++ doc/styles.css | 186 +++++++++++++ illuaminate.sexp | 32 ++- .../assets/computercraft/lua/bios.lua | 2 +- .../computercraft/lua/rom/apis/colors.lua | 173 ++++++++++-- .../computercraft/lua/rom/apis/colours.lua | 18 +- .../lua/rom/apis/command/commands.lua | 21 +- .../computercraft/lua/rom/apis/disk.lua | 86 +++++- .../assets/computercraft/lua/rom/apis/gps.lua | 34 +++ .../computercraft/lua/rom/apis/help.lua | 30 +++ .../assets/computercraft/lua/rom/apis/io.lua | 213 +++++++++++---- .../computercraft/lua/rom/apis/keys.lua | 31 ++- .../computercraft/lua/rom/apis/paintutils.lua | 112 ++++++-- .../computercraft/lua/rom/apis/parallel.lua | 27 +- .../computercraft/lua/rom/apis/peripheral.lua | 206 ++++++++++----- .../computercraft/lua/rom/apis/rednet.lua | 165 ++++++++++-- .../computercraft/lua/rom/apis/settings.lua | 75 +++++- .../computercraft/lua/rom/apis/term.lua | 48 +++- .../computercraft/lua/rom/apis/textutils.lua | 142 +++++++++- .../lua/rom/apis/turtle/turtle.lua | 3 + .../computercraft/lua/rom/apis/vector.lua | 247 ++++++++++++------ .../computercraft/lua/rom/apis/window.lua | 51 +++- .../lua/rom/modules/main/cc/expect.lua | 2 +- .../lua/rom/modules/main/cc/pretty.lua | 17 +- src/test/resources/test-rom/mcfly.lua | 56 ++-- .../test-rom/spec/modules/cc/pretty_spec.lua | 2 +- 39 files changed, 2094 insertions(+), 336 deletions(-) create mode 100755 .github/workflows/make-doc.sh create mode 100644 .github/workflows/make-doc.yml create mode 100644 doc/index.md rename logo.png => doc/logo.png (100%) create mode 100644 doc/stub/commands.lua create mode 100644 doc/stub/fs.lua create mode 100644 doc/stub/http.lua create mode 100644 doc/stub/os.lua create mode 100644 doc/stub/redstone.lua create mode 100644 doc/stub/term.lua create mode 100644 doc/stub/turtle.lua create mode 100644 doc/styles.css diff --git a/.editorconfig b/.editorconfig index f11468850..d57b269a4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,5 +14,9 @@ trim_trailing_whitespace = false [*.sexp] indent_size = 2 +[*.yml] +indent_size = 2 + + [*.properties] insert_final_newline = false diff --git a/.github/workflows/make-doc.sh b/.github/workflows/make-doc.sh new file mode 100755 index 000000000..e447c3046 --- /dev/null +++ b/.github/workflows/make-doc.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -eu + +DEST="${GITHUB_REF#refs/*/}" +echo "Uploading docs to https://tweaked.cc/$DEST" + +# Setup ssh key +mkdir -p "$HOME/.ssh/" +echo "$SSH_KEY" > "$HOME/.ssh/key" +chmod 600 "$HOME/.ssh/key" + +# And upload +rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \ + "$GITHUB_WORKSPACE/doc/" \ + "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST" diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml new file mode 100644 index 000000000..1d5e4605d --- /dev/null +++ b/.github/workflows/make-doc.yml @@ -0,0 +1,29 @@ +name: Build documentation + +on: + push: + branches: [ master ] + tags: + +jobs: + make_doc: + name: Build + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + + - name: Build documentation + run: | + test -d bin || mkdir bin + test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate + chmod +x bin/illuaminate + bin/illuaminate doc-gen + + - name: Upload documentation + run: .github/workflows/make-doc.sh 2> /dev/null + env: + SSH_KEY: ${{ secrets.SSH_KEY }} + SSH_USER: ${{ secrets.SSH_USER }} + SSH_HOST: ${{ secrets.SSH_HOST }} + SSH_PORT: ${{ secrets.SSH_PORT }} diff --git a/.gitignore b/.gitignore index 80c50f9b8..cc7ddcea3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /logs /build /out +/doc/**/*.html # Runtime directories /run diff --git a/README.md b/README.md index 692e7bb48..fd3003786 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ![CC: Tweaked](logo.png) +# ![CC: Tweaked](doc/logo.png) [![Current build status](https://github.com/SquidDev-CC/CC-Tweaked/workflows/Build/badge.svg)](https://github.com/SquidDev-CC/CC-Tweaked/actions "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers, diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 000000000..efc2afafa --- /dev/null +++ b/doc/index.md @@ -0,0 +1,13 @@ +# CC: Tweaked + +This is a small website to test documentation generation from Lua source code. + +This is still very much in the proof-of-concept stage. We've rolled own own documentation +generation tool, and there's a couple of missing features. Furthermore, Java-based APIs +(such as Lua builtins, or @{os}) are not documented. + +For more information, please check out [the GitHub issue][gh_issue] and [the +documented source][gh_branch]. + +[gh_issue]: https://github.com/SquidDev-CC/CC-Tweaked/issues/133 +[gh_branch]: https://github.com/SquidDev-CC/CC-Tweaked/tree/feature/doc-gen diff --git a/logo.png b/doc/logo.png similarity index 100% rename from logo.png rename to doc/logo.png diff --git a/doc/stub/commands.lua b/doc/stub/commands.lua new file mode 100644 index 000000000..89b0f604b --- /dev/null +++ b/doc/stub/commands.lua @@ -0,0 +1,6 @@ +function exec(command) end +function execAsync(commad) end +function list() end +function getBlockPosition() end +function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end +function getBlockInfo(x, y, z) end diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua new file mode 100644 index 000000000..73d578e01 --- /dev/null +++ b/doc/stub/fs.lua @@ -0,0 +1,42 @@ +--- The FS API allows you to manipulate files and the filesystem. +-- +-- @module fs + +function list(path) end +function combine(base, child) end +function getName(path) end +function getSize(path) end +function exists(path) end +function isDir(path) end +function isReadOnly(path) end +function makeDir(path) end +function move(from, to) end +function copy(from, to) end +function delete(path) end +function open(path, mode) end +function getDrive(path) end +function getFreeSpace(path) end +function find(pattern) end +function getDir(path) end + +--- A file handle which can be read from. +-- +-- @type ReadHandle +-- @see fs.open +local ReadHandle = {} +function ReadHandle.read(count) end +function ReadHandle.readAll() end +function ReadHandle.readLine(with_trailing) end +function ReadHandle.seek(whence, offset) end +function ReadHandle.close() end + +--- A file handle which can be written to. +-- +-- @type WriteHandle +-- @see fs.open +local WriteHandle = {} +function WriteHandle.write(text) end +function WriteHandle.writeLine(text) end +function WriteHandle.flush(text) end +function WriteHandle.seek(whence, offset) end +function WriteHandle.close() end diff --git a/doc/stub/http.lua b/doc/stub/http.lua new file mode 100644 index 000000000..8e7df608f --- /dev/null +++ b/doc/stub/http.lua @@ -0,0 +1,213 @@ +--- The http library allows communicating with web servers, sending and +-- receiving data from them. +-- +-- #### `http_check` event +-- +-- @module http + +--- Asynchronously make a HTTP request to the given url. +-- +-- This returns immediately, a [`http_success`](#http-success-event) or +-- [`http_failure`](#http-failure-event) will be queued once the request has +-- completed. +-- +-- @tparam string url The url to request +-- @tparam[opt] string body An optional string containing the body of the +-- request. If specified, a `POST` request will be made instead. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. +-- +-- This table form is an expanded version of the previous syntax. All arguments +-- from above are passed in as fields instead (for instance, +-- `http.request("https://example.com")` becomes `http.request { url = +-- "https://example.com" }`). +-- +-- This table also accepts several additional options: +-- +-- - `method`: Which HTTP method to use, for instance `"PATCH"` or `"DELETE"`. +-- - `redirect`: Whether to follow HTTP redirects. Defaults to true. +-- +-- @see http.get For a synchronous way to make GET requests. +-- @see http.post For a synchronous way to make POST requests. +function request(...) end + +--- Make a HTTP GET request to the given url. +-- +-- @tparam string url The url to request +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +-- +-- @usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), +-- and print the returned page. +-- ```lua +-- local request = http.get("https://example.computercraft.cc") +-- print(request.readAll()) +-- -- => HTTP is working! +-- request.close() +-- ``` +function get(...) end + +--- Make a HTTP POST request to the given url. +-- +-- @tparam string url The url to request +-- @tparam string body The body of the POST request. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of this request. +-- @tparam[opt] boolean binary Whether to make a binary HTTP request. If true, +-- the body will not be UTF-8 encoded, and the received response will not be +-- decoded. +-- +-- @tparam[2] { +-- url = string, body? = string, headers? = { [string] = string }, +-- binary? = boolean, method? = string, redirect? = boolean, +-- } request Options for the request. See @{http.request} for details on how +-- these options behave. +-- +-- @treturn Response The resulting http response, which can be read from. +-- @treturn[2] nil When the http request failed, such as in the event of a 404 +-- error or connection timeout. +-- @treturn string A message detailing why the request failed. +-- @treturn Response|nil The failing http response, if available. +function post(...) end + +--- A http response. This acts very much like a @{fs.ReadHandle|file}, though +-- provides some http specific methods. +-- +-- #### `http_success` event +-- #### `http_failure` event +-- +-- @type Response +-- @see http.request On how to make a http request. +local Response = {} + +--- Returns the response code and response message returned by the server +-- +-- @treturn number The response code (i.e. 200) +-- @treturn string The response message (i.e. "OK") +function Response.getResponseCode() end + +--- Get a table containing the response's headers, in a format similar to that +-- required by @{http.request}. If multiple headers are sent with the same +-- name, they will be combined with a comma. +-- +-- @treturn { [string]=string } The response's headers. +-- Make a request to [example.computercraft.cc](https://example.computercraft.cc), +-- and print the returned headers. +-- ```lua +-- local request = http.get("https://example.computercraft.cc") +-- print(textutils.serialize(request.getResponseHeaders())) +-- -- => { +-- -- [ "Content-Type" ] = "text/plain; charset=utf8", +-- -- [ "content-length" ] = 17, +-- -- ... +-- -- } +-- request.close() +-- ``` +function Response.getResponseHeaders() end + +function Response.read(count) end +function Response.readAll() end +function Response.readLine(with_trailing) end +function Response.seek(whence, offset) end +function Response.close() end + +--- Asynchronously determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is not invalid. This does not imply that it is +-- allowed - see the comment above. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURL For a synchronous version. +function checkURLAsync(url) end + +--- Determine whether a URL can be requested. +-- +-- If this returns `true`, one should also listen for [`http_check` +-- events](#http-check-event) which will container further information about +-- whether the URL is allowed or not. +-- +-- @tparam string url The URL to check. +-- @treturn true When this url is valid and can be requested via @{http.request}. +-- @treturn[2] false When this url is invalid. +-- @treturn string A reason why this URL is not valid (for instance, if it is +-- malformed, or blocked). +-- +-- @see http.checkURLAsync For an asynchronous version. +-- +-- @usage +-- ```lua +-- print(http.checkURL("https://example.computercraft.cc/")) +-- -- => true +-- print(http.checkURL("http://localhost/")) +-- -- => false Domain not permitted +-- print(http.checkURL("not a url")) +-- -- => false URL malformed +-- ``` +function checkURL(url) end + +--- Open a websocket. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +-- +-- @treturn Websocket The websocket connection. +-- @treturn[2] false If the websocket connection failed. +-- @treturn string An error message describing why the connection failed. +function websocket(url, headers) end + +--- Asynchronously open a websocket. +-- +-- This returns immediately, a [`websocket_success`](#websocket-success-event) +-- or [`websocket_failure`](#websocket-failure-event) will be queued once the +-- request has completed. +-- +-- @tparam string url The websocket url to connect to. This should have the +-- `ws://` or `wss://` protocol. +-- @tparam[opt] { [string] = string } headers Additional headers to send as part +-- of the initial websocket connection. +function websocketAsync(url, headers) end + + + +--- A websocket, which can be used to send an receive messages with a web +-- server. +-- +-- @type Websocket +-- @see http.websocket On how to open a websocket. +local Websocket = {} + +function Websocket.send(message, binary) end +function Websocket.receive() end +function Websocket.close() end diff --git a/doc/stub/os.lua b/doc/stub/os.lua new file mode 100644 index 000000000..163d2c2b0 --- /dev/null +++ b/doc/stub/os.lua @@ -0,0 +1,17 @@ +function queueEvent(event, ...) end +function startTimer(delay) end +function setAlarm(time) end +function shutdown() end +function reboot() end +function getComputerID() end +computerID = getComputerID +function setComputerLabel(label) end +function getComputerLabel() end +computerLabel = getComputerLabel +function clock() end +function time(timezone) end +function day(timezone) end +function cancelTimer(id) end +function cancelAlarm(id) end +function epoch(timezone) end +function date(format, time) end diff --git a/doc/stub/redstone.lua b/doc/stub/redstone.lua new file mode 100644 index 000000000..cf10a45ca --- /dev/null +++ b/doc/stub/redstone.lua @@ -0,0 +1,14 @@ +function getSides() end +function setOutput(side, on) end +function getOutput(side) end +function getInput(side) end +function setBundledOutput(side, output) end +function getBundledOutput(side) end +function getBundledInput(side) end +function testBundledInput(side, mask) end +function setAnalogOutput(side, value) end +setAnalogueOutput = setAnalogOutput +function getAnalogOutput(sid) end +getAnalogueOutput = getAnalogOutput +function getAnalogInput(side) end +getAnalogueInput = getAnaloguInput diff --git a/doc/stub/term.lua b/doc/stub/term.lua new file mode 100644 index 000000000..2111949b6 --- /dev/null +++ b/doc/stub/term.lua @@ -0,0 +1,52 @@ +function write(text) end +function scroll(lines) end +function setCursorPos(x, y) end +function setCursorBlink(blink) end +function getCursorPos() end +function getSize() end +function clear() end +function clearLine() end +function setTextColour(colour) end +setTextColor = setTextColour +function setBackgroundColour(colour) end +setBackgroundColor = setBackgroundColour +function isColour() end +isColor = isColour +function getTextColour() end +getTextColor = getTextColor +function getBackgroundColour() end +getBackgroundColour = getBackgroundColour +function blit(text, text_colours, background_colours) end +function setPaletteColour(colour, ...) end +setPaletteColour = setPaletteColour +function getPaletteColour(colour, ...) end +getPaletteColour = getPaletteColour +function nativePaletteColour(colour) end +nativePaletteColour = nativePaletteColour + +--- @type Redirect +local Redirect = {} + +Redirect.write = write +Redirect.scroll = scroll +Redirect.setCursorPos = setCursorPos +Redirect.setCursorBlink = setCursorBlink +Redirect.getCursorPos = getCursorPos +Redirect.getSize = getSize +Redirect.clear = clear +Redirect.clearLine = clearLine +Redirect.setTextColour = setTextColour +Redirect.setTextColor = setTextColor +Redirect.setBackgroundColour = setBackgroundColour +Redirect.setBackgroundColor = setBackgroundColor +Redirect.isColour = isColour +Redirect.isColor = isColor +Redirect.getTextColour = getTextColour +Redirect.getTextColor = getTextColor +Redirect.getBackgroundColour = getBackgroundColour +Redirect.getBackgroundColor = getBackgroundColor +Redirect.blit = blit +Redirect.setPaletteColour = setPaletteColour +Redirect.setPaletteColor = setPaletteColor +Redirect.getPaletteColour = getPaletteColour +Redirect.getPaletteColor = getPaletteColor diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua new file mode 100644 index 000000000..0baa4c6fa --- /dev/null +++ b/doc/stub/turtle.lua @@ -0,0 +1,42 @@ +function forward() end +function back() end +function up() end +function down() end +function turnLeft() end +function turnRight() end +function dig(side) end +function digUp(side) end +function digDown(side) end +function place() end +function placeUp() end +function placeDown() end +function drop(count) end +function select(slot) end +function getItemCount(slot) end +function getItemSpace(slot) end +function detect() end +function detectUp() end +function detectDown() end +function compare() end +function compareUp() end +function compareDown() end +function attack(side) end +function attackUp(side) end +function attackDown(side) end +function dropUp(count) end +function dropDown(count) end +function suck(count) end +function suckUp(count) end +function suckDown(count) end +function getFuelLevel() end +function refuel(count) end +function compareTo(slot) end +function transferTo(slot, count) end +function getSelectedSlot() end +function getFuelLimit() end +function equipLeft() end +function equipRight() end +function inspect() end +function inspectUp() end +function inspectDown() end +function getItemDetail(slot) end diff --git a/doc/styles.css b/doc/styles.css new file mode 100644 index 000000000..ef14a7d94 --- /dev/null +++ b/doc/styles.css @@ -0,0 +1,186 @@ +/* Basic reset on elements */ +h1, h2, h3, h4, p, table, div, body { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* Make the page a little more airy */ +body { + margin: 20px auto; + max-width: 1200px; + padding: 0 10px; + line-height: 1.6; + color: #222; + background: #fff; +} + +/* Try to use system default fonts. */ +body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", + "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; +} + +code, pre, .parameter, .type, .definition-name, .reference { + font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; +} + +/* Some definitions of basic tags */ +code { + color: #c7254e; + background-color: #f9f2f4; +} + +p { + margin: 0.9em 0; +} + +h1 { + font-size: 1.5em; + font-weight: lighter; + border-bottom: solid 1px #aaa; +} + +h2, h3, h4 { margin: 1.4em 0 0.3em;} +h2 { font-size: 1.25em; } +h3 { font-size: 1.15em; font-weight: bold; } +h4 { font-size: 1.06em; } + +a, a:visited, a:active { font-weight: bold; color: #004080; text-decoration: none; } +a:hover { text-decoration: underline; } + +blockquote { margin-left: 3em; } + +/* Stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* Make the target distinct; helps when we're navigating to a function */ +a:target + * { background-color: #FFFF99; } + +/* Allow linking to any subsection */ +a[name]::before { content: "#"; } + +/* Layout */ +#main { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + min-height: calc(100vh - 100px); +} + +#main > nav { + flex-basis: 30%; + min-width: 150px; + max-width: 250px; + background-color: #f0f0f0; +} + +nav h1, nav ul { padding: 0em 10px; } + +nav h2 { + background-color:#e7e7e7; + font-size: 1.1em; + color:#000000; + padding: 5px 10px; +} + +nav ul { + list-style-type: none; + margin: 0; +} + +#content { + flex-shrink: 1; + flex-basis: 80%; + padding: 0px 10px; +} + +footer { + text-align: right; + font-size: 0.8em; +} + +/* The definition lists at the top of each page */ +table.definition-list { + border-collapse: collapse; + width: 100%; +} + +table.definition-list td, table.definition-list th { + border: 1px solid #cccccc; + padding: 5px; +} + +table.definition-list th { + background-color: #f0f0f0; + min-width: 200px; + white-space: nowrap; + text-align: right; +} + +table.definition-list td { width: 100%; } + +dl.definition dt { + border-top: 1px solid #ccc; + padding-top: 1em; + display: flex; +} + +dl.definition dt .definition-name { + padding: 0 0.1em; + margin: 0 0.1em; + flex-grow: 1; +} + + +dl.definition dd { + padding-bottom: 1em; + margin: 10px 0 0 20px; +} + +dl.definition h3 { + font-size: .95em; +} + +/* Links to source-code */ +.source-link { font-size: 0.8em; } +.source-link::before { content: '[' } +.source-link::after { content: ']' } +a.source-link, a.source-link:visited, a.source-link:active { color: #505050; } + +/* Method definitions */ +span.parameter:after { content:":"; padding-left: 0.3em; } +.optional { text-decoration: underline dotted; } + +/** Fancy colour display. */ +.colour-ref { + display: inline-block; + width: 0.8em; + height: 0.8em; + margin: 0.1em 0.1em 0.3em 0.1em; /* Terrrible hack to force vertical alignment. */ + border: solid 1px black; + box-sizing: border-box; + vertical-align: middle; +} + +/* styles for prettification of source */ +.highlight .comment { color: #558817; } +.highlight .constant { color: #a8660d; } +.highlight .escape { color: #844631; } +.highlight .keyword { color: #aa5050; font-weight: bold; } +.highlight .library { color: #0e7c6b; } +.highlight .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +.highlight .string { color: #8080ff; } +.highlight .literal-kw { color: #8080ff; } +.highlight .number { color: #f8660d; } +.highlight .operator { color: #2239a8; font-weight: bold; } +.highlight .preprocessor, pre .prepro { color: #a33243; } +.highlight .global { color: #800080; } +.highlight .user-keyword { color: #800080; } +.highlight .prompt { color: #558817; } +.highlight .url { color: #272fc2; text-decoration: underline; } diff --git a/illuaminate.sexp b/illuaminate.sexp index cda3d0a85..0a8fe626e 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -1,10 +1,28 @@ ; -*- mode: Lisp;-*- (sources + /doc/stub/ /src/main/resources/assets/computercraft/lua/bios.lua /src/main/resources/assets/computercraft/lua/rom/ /src/test/resources/test-rom) + +(doc + (title "CC: Tweaked") + (index doc/index.md) + (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) + + (library-path + /doc/stub/ + + /src/main/resources/assets/computercraft/lua/rom/apis + /src/main/resources/assets/computercraft/lua/rom/apis/command + /src/main/resources/assets/computercraft/lua/rom/apis/turtle + + /src/main/resources/assets/computercraft/lua/rom/modules/main + /src/main/resources/assets/computercraft/lua/rom/modules/command + /src/main/resources/assets/computercraft/lua/rom/modules/turtle)) + (at / (linters ;; It'd be nice to avoid this, but right now there's a lot of instances of @@ -16,9 +34,9 @@ -var:unused-arg ;; Suppress a couple of documentation comments warnings for now. We'll - ;; hopefully be able to remove them in the coming weeks. - -doc:detached-comment -doc:undocumented -doc:undocumented-arg - -doc:unresolved-reference)) + ;; hopefully be able to remove them in the future. + -doc:undocumented -doc:undocumented-arg -doc:unresolved-reference + -var:unresolved-member)) ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. @@ -26,5 +44,9 @@ (/src/main/resources/assets/computercraft/lua/bios.lua /src/main/resources/assets/computercraft/lua/rom/apis/) (linters -var:unused-global) - (lint - (allow-toplevel-global true))) + (lint (allow-toplevel-global true))) + +;; Silence some variable warnings in documentation stubs. +(at /doc/stub + (linters -var:unused-global) + (lint (allow-toplevel-global true))) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index a7f7a9d21..377255845 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -21,7 +21,7 @@ if _VERSION == "Lua 5.1" then local nativeloadstring = loadstring local nativesetfenv = setfenv - --- Historically load/loadstring would handle the chunk name as if it has + -- Historically load/loadstring would handle the chunk name as if it has -- been prefixed with "=". We emulate that behaviour here. local function prefix(chunkname) if type(chunkname) ~= "string" then return chunkname end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua index b2e665268..8754b1929 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua @@ -1,23 +1,91 @@ +--- The Colors API allows you to manipulate sets of colors. +-- +-- This is useful in conjunction with Bundled Cables from the RedPower mod, +-- RedNet Cables from the MineFactory Reloaded mod, and colors on Advanced +-- Computers and Advanced Monitors. +-- +-- For the non-American English version just replace @{colors} with @{colours} +-- and it will use the other API, colours which is exactly the same, except in +-- British English (e.g. @{colors.gray} is spelt @{colours.grey}). +-- +-- @see colours +-- @module colors + local expect = dofile("rom/modules/main/cc/expect.lua").expect --- Colors -white = 1 -orange = 2 -magenta = 4 -lightBlue = 8 -yellow = 16 -lime = 32 -pink = 64 -gray = 128 -lightGray = 256 -cyan = 512 -purple = 1024 -blue = 2048 -brown = 4096 -green = 8192 -red = 16384 -black = 32768 +--- White: Written as `0` in paint files and @{term.blit}, has a default +-- terminal colour of #F0F0F0. +white = 0x1 +--- Orange: Written as `1` in paint files and @{term.blit}, has a +-- default terminal colour of #F2B233. +orange = 0x2 + +--- Magenta: Written as `2` in paint files and @{term.blit}, has a +-- default terminal colour of #E57FD8. +magenta = 0x4 + +--- Light blue: Written as `3` in paint files and @{term.blit}, has a +-- default terminal colour of #99B2F2. +lightBlue = 0x8 + +--- Yellow: Written as `4` in paint files and @{term.blit}, has a +-- default terminal colour of #DEDE6C. +yellow = 0x10 + +--- Lime: Written as `5` in paint files and @{term.blit}, has a default +-- terminal colour of #7FCC19. +lime = 0x20 + +--- Pink. Written as `6` in paint files and @{term.blit}, has a default +-- terminal colour of #F2B2CC. +pink = 0x40 + +--- Gray: Written as `7` in paint files and @{term.blit}, has a default +-- terminal colour of #4C4C4C. +gray = 0x80 + +--- Light gray: Written as `8` in paint files and @{term.blit}, has a +-- default terminal colour of #999999. +lightGray = 0x100 + +--- Cyan: Written as `9` in paint files and @{term.blit}, has a default +-- terminal colour of #4C99B2. +cyan = 0x200 + +--- Purple: Written as `a` in paint files and @{term.blit}, has a +-- default terminal colour of #B266E5. +purple = 0x400 + +--- Blue: Written as `b` in paint files and @{term.blit}, has a default +-- terminal colour of #3366CC. +blue = 0x800 + +--- Brown: Written as `c` in paint files and @{term.blit}, has a default +-- terminal colour of #7F664C. +brown = 0x1000 + +--- Green: Written as `d` in paint files and @{term.blit}, has a default +-- terminal colour of #57A64E. +green = 0x2000 + +--- Red: Written as `e` in paint files and @{term.blit}, has a default +-- terminal colour of #CC4C4C. +red = 0x4000 + +--- Black: Written as `f` in paint files and @{term.blit}, has a default +-- terminal colour of #191919. +black = 0x8000 + +--- Combines a set of colors (or sets of colors) into a larger set. +-- +-- @tparam number ... The colors to combine. +-- @treturn number The union of the color sets given in `...` +-- @usage +-- ```lua +-- colors.combine(colors.white, colors.magenta, colours.lightBlue) +-- -- => 13 +-- ``` function combine( ... ) local r = 0 for i = 1, select('#', ...) do @@ -28,6 +96,20 @@ function combine( ... ) return r end +--- Removes one or more colors (or sets of colors) from an initial set. +-- +-- Each parameter beyond the first may be a single color or may be a set of +-- colors (in the latter case, all colors in the set are removed from the +-- original set). +-- +-- @tparam number colors The color from which to subtract. +-- @tparam number ... The colors to subtract. +-- @treturn number The resulting color. +-- @usage +-- ```lua +-- colours.subtract(colours.lime, colours.orange, colours.white) +-- -- => 32 +-- ``` function subtract( colors, ... ) expect(1, colors, "number") local r = colors @@ -39,12 +121,33 @@ function subtract( colors, ... ) return r end +--- Tests whether `color` is contained within `colors`. +-- +-- @tparam number colors A color, or color set +-- @tparam number color A color or set of colors that `colors` should contain. +-- @treturn boolean If `colors` contains all colors within `color`. +-- @usage +-- ```lua +-- colors.test(colors.combine(colors.white, colors.magenta, colours.lightBlue), colors.lightBlue) +-- -- => true +-- ``` function test( colors, color ) expect(1, colors, "number") expect(2, color, "number") return bit32.band(colors, color) == color end +--- Combine a three-colour RGB value into one hexadecimal representation. +-- +-- @tparam number r The red channel, should be between 0 and 1. +-- @tparam number g The red channel, should be between 0 and 1. +-- @tparam number b The blue channel, should be between 0 and 1. +-- @treturn number The combined hexadecimal colour. +-- @usage +-- ```lua +-- colors.rgb(0.7, 0.2, 0.6) +-- -- => 0xb23399 +-- ``` function packRGB( r, g, b ) expect(1, r, "number") expect(2, g, "number") @@ -55,6 +158,18 @@ function packRGB( r, g, b ) bit32.band( b * 255, 0xFF ) end +--- Separate a hexadecimal RGB colour into its three constituent channels. +-- +-- @tparam number rgb The combined hexadecimal colour. +-- @treturn number The red channel, will be between 0 and 1. +-- @treturn number The red channel, will be between 0 and 1. +-- @treturn number The blue channel, will be between 0 and 1. +-- @usage +-- ```lua +-- colors.rgb(0xb23399) +-- -- => 0.7, 0.2, 0.6 +-- ``` +-- @see colors.packRGB function unpackRGB( rgb ) expect(1, rgb, "number") return @@ -63,6 +178,30 @@ function unpackRGB( rgb ) bit32.band( rgb, 0xFF ) / 255 end +--- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many +-- arguments it receives. +-- +-- **Note:** This function is deprecated, and it is recommended you use the +-- specific pack/unpack function directly. +-- +-- @tparam[1] number r The red channel, as an argument to @{colors.packRGB}. +-- @tparam[1] number g The green channel, as an argument to @{colors.packRGB}. +-- @tparam[1] number b The blue channel, as an argument to @{colors.packRGB}. +-- @tparam[2] number rgb The combined hexadecimal color, as an argument to @{colors.unpackRGB}. +-- @treturn[1] number The combined hexadecimal colour, as returned by @{colors.packRGB}. +-- @treturn[2] number The red channel, as returned by @{colors.unpackRGB} +-- @treturn[2] number The green channel, as returned by @{colors.unpackRGB} +-- @treturn[2] number The blue channel, as returned by @{colors.unpackRGB} +-- @usage +-- ```lua +-- colors.rgb(0xb23399) +-- -- => 0.7, 0.2, 0.6 +-- ``` +-- @usage +-- ```lua +-- colors.rgb(0.7, 0.2, 0.6) +-- -- => 0xb23399 +-- ``` function rgb8( r, g, b ) if g == nil and b == nil then return unpackRGB( r ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua index fa17c6cb3..74f048df7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colours.lua @@ -1,11 +1,23 @@ --- Colours (for lovers of british spelling) +--- Colours for lovers of British spelling. +-- +-- @see colors +-- @module colours + local colours = _ENV for k, v in pairs(colors) do colours[k] = v end +--- Grey. Written as `7` in paint files and @{term.blit}, has a default +-- terminal colour of #4C4C4C. +-- +-- @see colors.gray colours.grey = colors.gray -colours.gray = nil +colours.gray = nil --- @local +--- Light grey. Written as `8` in paint files and @{term.blit}, has a +-- default terminal colour of #999999. +-- +-- @see colors.lightGray colours.lightGrey = colors.lightGray -colours.lightGray = nil +colours.lightGray = nil --- @local diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua index caf86f5cf..d0c02b304 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua @@ -1,7 +1,26 @@ +--- The commands API allows your system to directly execute [Minecraft +-- commands][mc] and gather data from the results. +-- +-- While one may use @{commands.exec} directly to execute a command, the +-- commands API also provides helper methods to execute every command. For +-- instance, `commands.say("Hi!")` is equivalent to `commands.exec("say Hi!")`. +-- +-- @{commands.async} provides a similar interface to execute asynchronous +-- commands. `commands.async.say("Hi!")` is equivalent to +-- `commands.execAsync("Hi!")`. +-- +-- [mc]: https://minecraft.gamepedia.com/Commands +-- +-- @module commands if not commands then - error( "Cannot load command API on normal computer", 2 ) + error( "Cannot load command API on normal computer", 2 ) end + +--- The builtin commands API, without any generated command helper functions +-- +-- This may be useful if a built-in function (such as @{commands.list}) has been +-- overwritten by a command. native = commands.native or commands local function collapseArgs( bJSONIsNBT, ... ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua index 7a0dbad39..502989008 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua @@ -1,3 +1,15 @@ +--- The Disk API allows you to interact with disk drives. +-- +-- These functions can operate on locally attached or remote disk drives. To use +-- a locally attached drive, specify “side†as one of the six sides +-- (e.g. `left`); to use a remote disk drive, specify its name as printed when +-- enabling its modem (e.g. `drive_0`). +-- +-- **Note:** All computers (except command computers), turtles and pocket +-- computers can be placed within a disk drive to access it's internal storage +-- like a disk. +-- +-- @module disk local function isDrive( name ) if type( name ) ~= "string" then @@ -6,6 +18,11 @@ local function isDrive( name ) return peripheral.getType( name ) == "drive" end +--- Checks whether any item at all is in the disk drive +-- +-- @tparam string name The name of the disk drive. +-- @treturn boolean If something is in the disk drive. +-- @usage disk.isPresent(false) function isPresent( name ) if isDrive( name ) then return peripheral.call( name, "isDiskPresent" ) @@ -13,6 +30,16 @@ function isPresent( name ) return false end +--- Get the label of the floppy disk, record, or other media within the given +-- disk drive. +-- +-- If there is a computer or turtle within the drive, this will set the label as +-- read by `os.getComputerLabel`. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|nil The name of the current media, or `nil` if the drive is +-- not present or empty. +-- @see disk.setLabel function getLabel( name ) if isDrive( name ) then return peripheral.call( name, "getDiskLabel" ) @@ -20,12 +47,23 @@ function getLabel( name ) return nil end +--- Set the label of the floppy disk or other media +-- +-- @tparam string name The name of the disk drive. +-- @tparam string|nil label The new label of the disk function setLabel( name, label ) if isDrive( name ) then peripheral.call( name, "setDiskLabel", label ) end end +--- Check whether the current disk provides a mount. +-- +-- This will return true for disks and computers, but not records. +-- +-- @tparam string name The name of the disk drive. +-- @treturn boolean If the disk is present and provides a mount. +-- @see disk.getMountPath function hasData( name ) if isDrive( name ) then return peripheral.call( name, "hasData" ) @@ -33,6 +71,13 @@ function hasData( name ) return false end +--- Find the directory name on the local computer where the contents of the +-- current floppy disk (or other mount) can be found. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|nil The mount's directory, or `nil` if the drive does not +-- contain a floppy or computer. +-- @see disk.hasData function getMountPath( name ) if isDrive( name ) then return peripheral.call( name, "getMountPath" ) @@ -40,6 +85,15 @@ function getMountPath( name ) return nil end +--- Whether the current disk is a [music disk][disk] as opposed to a floppy disk +-- or other item. +-- +-- If this returns true, you will can @{disk.playAudio|play} the record. +-- +-- [disk]: https://minecraft.gamepedia.com/Music_Disc +-- +-- @tparam string name The name of the disk drive. +-- @treturn boolean If the disk is present and has audio saved on it. function hasAudio( name ) if isDrive( name ) then return peripheral.call( name, "hasAudio" ) @@ -47,6 +101,13 @@ function hasAudio( name ) return false end +--- Get the title of the audio track from the music record in the drive. +-- +-- This generally returns the same as @{disk.getLabel} for records. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|false|nil The track title, `false` if there is not a music +-- record in the drive or `nil` if no drive is present. function getAudioTitle( name ) if isDrive( name ) then return peripheral.call( name, "getAudioTitle" ) @@ -54,12 +115,25 @@ function getAudioTitle( name ) return nil end +--- Starts playing the music record in the drive. +-- +-- If any record is already playing on any disk drive, it stops before the +-- target drive starts playing. The record stops when it reaches the end of the +-- track, when it is removed from the drive, when @{disk.stopAudio} is called, or +-- when another record is started. +-- +-- @tparam string name The name of the disk drive. +-- @usage disk.playAudio("bottom") function playAudio( name ) if isDrive( name ) then peripheral.call( name, "playAudio" ) end end +--- Stops the music record in the drive from playing, if it was started with +-- @{disk.playAudio}. +-- +-- @tparam string name The name o the disk drive. function stopAudio( name ) if not name then for _, sName in ipairs( peripheral.getNames() ) do @@ -72,16 +146,26 @@ function stopAudio( name ) end end +--- Ejects any item currently in the drive, spilling it into the world as a loose item. +-- +-- @tparam string name The name of the disk drive. +-- @usage disk.eject("bottom") function eject( name ) if isDrive( name ) then peripheral.call( name, "ejectDisk" ) end end +--- Returns a number which uniquely identifies the disk in the drive. +-- +-- Note, unlike @{disk.getLabel}, this does not return anything for other media, +-- such as computers or turtles. +-- +-- @tparam string name The name of the disk drive. +-- @treturn string|nil The disk ID, or `nil` if the drive does not contain a floppy disk. function getID( name ) if isDrive( name ) then return peripheral.call( name, "getDiskID" ) end return nil end - diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index 79b192494..7a4d03af0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -1,5 +1,30 @@ +--- The GPS API provides a method for turtles and computers to retrieve their +-- own locations. +-- +-- It broadcasts a PING message over @{rednet} and wait for responses. In order +-- for this system to work, there must be at least 4 computers used as gps hosts +-- which will respond and allow trilateration. Three of these hosts should be in +-- a plane, and the fourth should be either above or below the other three. The +-- three in a plane should not be in a line with each other. You can set up +-- hosts using the gps program. +-- +-- **Note**: When entering in the coordinates for the host you need to put in +-- the `x`, `y`, and `z` coordinates of the computer, not the modem, as all +-- rednet distances are measured from the block the computer is in. +-- +-- Also note that you may choose which axes x, y, or z refers to - so long as +-- your systems have the same definition as any GPS servers that're in range, it +-- works just the same. For example, you might build a GPS cluster according to +-- [this tutorial][1], using z to account for height, or you might use y to +-- account for height in the way that Minecraft's debug screen displays. +-- +-- [1]: http://www.computercraft.info/forums2/index.php?/topic/3088-how-to-guide-gps-global-position-system/ +-- +-- @module gps + local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- The channel which GPS requests and responses are broadcast on. CHANNEL_GPS = 65534 local function trilaterate( A, B, C ) @@ -56,6 +81,15 @@ local function narrow( p1, p2, fix ) end end +--- Tries to retrieve the computer or turtles own location. +-- +-- @tparam[opt] number timeout The maximum time taken to establish our +-- position. Defaults to 2 seconds if not specified. +-- @tparam[opt] boolean debug Print debugging messages +-- @treturn[1] number This computer's `x` position. +-- @treturn[1] number This computer's `y` position. +-- @treturn[1] number This computer's `z` position. +-- @treturn[2] nil If the position could not be established. function locate( _nTimeout, _bDebug ) expect(1, _nTimeout, "number", "nil") expect(2, _bDebug, "boolean", "nil") diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index ded20f2f3..1b3088c4b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -1,16 +1,38 @@ +--- Provides an API to read help files. +-- +-- @module help + local expect = dofile("rom/modules/main/cc/expect.lua").expect local sPath = "/rom/help" +--- Returns a colon-separated list of directories where help files are searched +-- for. All directories are absolute. +-- +-- @treturn string The current help search path, separated by colons. +-- @see help.setPath function path() return sPath end +--- Sets the colon-seperated list of directories where help files are searched +-- for to `newPath` +-- +-- @tparam string newPath The new path to use. +-- @usage help.setPath( "/disk/help/" ) +-- @usage help.setPath( help.path() .. ":/myfolder/help/" ) +-- @see help.path function setPath( _sPath ) expect(1, _sPath, "string") sPath = _sPath end +--- Returns the location of the help file for the given topic. +-- +-- @tparam string topic The topic to find +-- @treturn string|nil The path to the given topic's help file, or `nil` if it +-- cannot be found. +-- @usage print(help.lookup("disk")) function lookup( _sTopic ) expect(1, _sTopic, "string") -- Look on the path variable @@ -27,6 +49,9 @@ function lookup( _sTopic ) return nil end +--- Returns a list of topics that can be looked up and/or displayed. +-- +-- @treturn table A list of topics in alphabetical order. function topics() -- Add index local tItems = { @@ -59,6 +84,11 @@ function topics() return tItemList end +--- Returns a list of topic endings that match the prefix. Can be used with +-- `read` to allow input of a help topic. +-- +-- @tparam string prefix The prefix to match +-- @treturn table A list of matching topics. function completeTopic( sText ) expect(1, sText, "string") local tTopics = topics() diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index 3cf28c80b..8079e022f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -1,6 +1,10 @@ --- Definition for the IO API +--- Emulates Lua's standard [io library][io]. +-- +-- [io]: https://www.lua.org/manual/5.1/manual.html#5.7 +-- +-- @module io -local expect, typeOf = dofile("rom/modules/main/cc/expect.lua").expect, _G.type +local expect, type_of = dofile("rom/modules/main/cc/expect.lua").expect, _G.type --- If we return nil then close the file, as we've reached the end. -- We use this weird wrapper function as we wish to preserve the varargs @@ -9,6 +13,9 @@ local function checkResult(handle, ...) return ... end +--- A file handle which can be read or written to. +-- +-- @type Handle local handleMetatable handleMetatable = { __name = "FILE*", @@ -20,10 +27,17 @@ handleMetatable = { return "file (" .. hash .. ")" end end, + __index = { + --- Close this file handle, freeing any resources it uses. + -- + -- @treturn[1] true If this handle was successfully closed. + -- @treturn[2] nil If this file handle could not be closed. + -- @treturn[2] string The reason it could not be closed. + -- @throws If this handle was already closed. close = function(self) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -36,18 +50,24 @@ handleMetatable = { return nil, "attempt to close standard stream" end end, + + --- Flush any buffered output, forcing it to be written to the file + -- + -- @throws If the handle has been closed flush = function(self) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end local handle = self._handle if handle.flush then handle.flush() end + return true end, + lines = function(self, ...) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -57,9 +77,10 @@ handleMetatable = { local args = table.pack(...) return function() return checkResult(self, self:read(table.unpack(args, 1, args.n))) end end, + read = function(self, ...) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -71,9 +92,9 @@ handleMetatable = { for i = 1, n do local arg = select(i, ...) local res - if typeOf(arg) == "number" then + if type_of(arg) == "number" then if handle.read then res = handle.read(arg) end - elseif typeOf(arg) == "string" then + elseif type_of(arg) == "string" then local format = arg:gsub("^%*", ""):sub(1, 1) if format == "l" then @@ -88,7 +109,7 @@ handleMetatable = { error("bad argument #" .. i .. " (invalid format)", 2) end else - error("bad argument #" .. i .. " (expected string, got " .. typeOf(arg) .. ")", 2) + error("bad argument #" .. i .. " (expected string, got " .. type_of(arg) .. ")", 2) end output[i] = res @@ -99,9 +120,10 @@ handleMetatable = { if n == 0 and handle.readLine then return handle.readLine() end return table.unpack(output, 1, n) end, + seek = function(self, whence, offset) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -111,10 +133,18 @@ handleMetatable = { -- It's a tail call, so error positions are preserved return handle.seek(whence, offset) end, + setvbuf = function(self, mode, size) end, + + --- Write one or more values to the file + -- + -- @tparam string|number ... The values to write. + -- @treturn[1] Handle The current file, allowing chained calls. + -- @treturn[2] nil If the file could not be written to. + -- @treturn[2] string The error message which occurred while writing. write = function(self, ...) - if typeOf(self) ~= "table" or getmetatable(self) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(self) .. ")", 2) + if type_of(self) ~= "table" or getmetatable(self) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(self) .. ")", 2) end if self._closed then error("attempt to use a closed file", 2) end @@ -156,41 +186,88 @@ local defaultError = setmetatable({ local currentInput = defaultInput local currentOutput = defaultOutput +--- A file handle representing the "standard input". Reading from this +-- file will prompt the user for input. stdin = defaultInput + +--- A file handle representing the "standard output". Writing to this +-- file will display the written text to the screen. stdout = defaultOutput + +--- A file handle representing the "standard error" stream. +-- +-- One may use this to display error messages, writing to it will display +-- them on the terminal. stderr = defaultError -function close(_file) - if _file == nil then return currentOutput:close() end +--- Closes the provided file handle. +-- +-- @tparam[opt] Handle file The file handle to close, defaults to the +-- current output file. +-- +-- @see Handle:close +-- @see io.output +function close(file) + if file == nil then return currentOutput:close() end - if typeOf(_file) ~= "table" or getmetatable(_file) ~= handleMetatable then - error("bad argument #1 (FILE expected, got " .. typeOf(_file) .. ")", 2) + if type_of(file) ~= "table" or getmetatable(file) ~= handleMetatable then + error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2) end - return _file:close() + return file:close() end +--- Flushes the current output file. +-- +-- @see Handle:flush +-- @see io.output function flush() return currentOutput:flush() end -function input(_arg) - if typeOf(_arg) == "string" then - local res, err = open(_arg, "rb") +--- Get or set the current input file. +-- +-- @tparam[opt] Handle|string file The new input file, either as a file path or pre-existing handle. +-- @treturn Handle The current input file. +-- @throws If the provided filename cannot be opened for reading. +function input(file) + if type_of(file) == "string" then + local res, err = open(file, "rb") if not res then error(err, 2) end currentInput = res - elseif typeOf(_arg) == "table" and getmetatable(_arg) == handleMetatable then - currentInput = _arg - elseif _arg ~= nil then - error("bad argument #1 (FILE expected, got " .. typeOf(_arg) .. ")", 2) + elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then + currentInput = file + elseif file ~= nil then + error("bad fileument #1 (FILE expected, got " .. type_of(file) .. ")", 2) end return currentInput end -function lines(_sFileName) - expect(1, _sFileName, "string", "nil") - if _sFileName then - local ok, err = open(_sFileName, "rb") +--- Opens the given file name in read mode and returns an iterator that, +-- each time it is called, returns a new line from the file. +-- +-- This can be used in a for loop to iterate over all lines of a file: +-- +-- ```lua +-- for line in io.lines(filename) do print(line) end +-- ``` +-- +-- Once the end of the file has been reached, @{nil} will be +-- returned. The file is automatically closed. +-- +-- If no file name is given, the @{io.input|current input} will be used +-- instead. In this case, the handle is not used. +-- +-- @tparam[opt] string filename The name of the file to extract lines from +-- @treturn function():string|nil The line iterator. +-- @throws If the file cannot be opened for reading +-- +-- @see Handle:lines +-- @see io.input +function lines(filename) + expect(1, filename, "string", "nil") + if filename then + local ok, err = open(filename, "rb") if not ok then error(err, 2) end -- We set this magic flag to mark this file as being opened by io.lines and so should be @@ -202,38 +279,72 @@ function lines(_sFileName) end end -function open(_sPath, _sMode) - expect(1, _sPath, "string") - expect(2, _sMode, "string", "nil") +--- Open a file with the given mode, either returning a new file handle +-- or @{nil}, plus an error message. +-- +-- The `mode` string can be any of the following: +-- - **"r"**: Read mode +-- - **"w"**: Write mode +-- - **"w"**: Append mode +-- +-- The mode may also have a `b` at the end, which opens the file in "binary +-- mode". This allows you to read binary files, as well as seek within a file. +-- +-- @tparam string filename The name of the file to open. +-- @tparam[opt] string mode The mode to open the file with. This defaults to `rb`. +-- @treturn[1] Handle The opened file. +-- @treturn[2] nil In case of an error. +-- @treturn[2] string The reason the file could not be opened. +function open(filename, mode) + expect(1, filename, "string") + expect(2, mode, "string", "nil") - local sMode = _sMode and _sMode:gsub("%+", "") or "rb" - local file, err = fs.open(_sPath, sMode) + local sMode = mode and mode:gsub("%+", "") or "rb" + local file, err = fs.open(filename, sMode) if not file then return nil, err end return setmetatable({ _handle = file }, handleMetatable) end -function output(_arg) - if typeOf(_arg) == "string" then - local res, err = open(_arg, "w") +--- Get or set the current output file. +-- +-- @tparam[opt] Handle|string file The new output file, either as a file path or pre-existing handle. +-- @treturn Handle The current output file. +-- @throws If the provided filename cannot be opened for writing. +function output(file) + if type_of(file) == "string" then + local res, err = open(file, "w") if not res then error(err, 2) end currentOutput = res - elseif typeOf(_arg) == "table" and getmetatable(_arg) == handleMetatable then - currentOutput = _arg - elseif _arg ~= nil then - error("bad argument #1 (FILE expected, got " .. typeOf(_arg) .. ")", 2) + elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then + currentOutput = file + elseif file ~= nil then + error("bad argument #1 (FILE expected, got " .. type_of(file) .. ")", 2) end return currentOutput end +--- Read from the currently opened input file. +-- +-- This is equivalent to `io.input():read(...)`. See @{Handle:read|the +-- documentation} there for full details. +-- +-- @tparam string ... The formats to read, defaulting to a whole line. +-- @treturn (string|nil)... The data read, or @{nil} if nothing can be read. function read(...) return currentInput:read(...) end -function type(handle) - if typeOf(handle) == "table" and getmetatable(handle) == handleMetatable then - if handle._closed then +--- Checks whether `handle` is a given file handle, and determine if it is open +-- or not. +-- +-- @param obj The value to check +-- @treturn string|nil `"file"` if this is an open file, `"closed file"` if it +-- is a closed file handle, or `nil` if not a file handle. +function type(obj) + if type_of(obj) == "table" and getmetatable(obj) == handleMetatable then + if obj._closed then return "closed file" else return "file" @@ -242,6 +353,12 @@ function type(handle) return nil end +--- Write to the currently opened output file. +-- +-- This is equivalent to `io.output():write(...)`. See @{Handle:write|the +-- documentation} there for full details. +-- +-- @tparam string ... The strings to write function write(...) return currentOutput:write(...) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua index c3ab42605..d303a8087 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua @@ -1,5 +1,12 @@ --- Minecraft key code bindings --- See http://www.minecraftwiki.net/wiki/Key_codes for more info +--- The Keys API provides a table of numerical codes corresponding to keyboard +-- keys, suitable for decoding key events. +-- +-- The Minecraft wiki [has a list of key +-- codes](http://www.minecraftwiki.net/wiki/Key_codes). It is recommended that +-- you use the constants provided by this file, rather than the underlying +-- numerical values. +-- +-- @module keys local expect = dofile("rom/modules/main/cc/expect.lua").expect @@ -53,12 +60,18 @@ local keys = _ENV for nKey, sKey in pairs( tKeys ) do keys[sKey] = nKey end -keys["return"] = keys.enter ---backwards compatibility to earlier, typo prone, versions -keys.scollLock = keys.scrollLock -keys.cimcumflex = keys.circumflex -function getName( _nKey ) - expect(1, _nKey, "number") - return tKeys[ _nKey ] +keys["return"] = keys.enter --- @local +--backwards compatibility to earlier, typo prone, versions +keys.scollLock = keys.scrollLock --- @local +keys.cimcumflex = keys.circumflex --- @local + +--- Translates a numerical key code to a human-readable name. The human-readable +-- name is one of the constants in the keys API. +-- +-- @tparam number code The key code to look up. +-- @treturn string|nil The name of the key, or `nil` if not a valid key code. +function getName( code ) + expect(1, code, "number") + return tKeys[ code ] end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index d725367d0..4a5630034 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -1,3 +1,8 @@ +--- An API for advanced systems which can draw pixels and lines, load and draw +-- image files. You can use the `colors` API for easier color manipulation. +-- +-- @module paintutils + local expect = dofile("rom/modules/main/cc/expect.lua").expect local function drawPixelInternal( xPos, yPos ) @@ -18,51 +23,88 @@ local function parseLine( tImageArg, sLine ) table.insert( tImageArg, tLine ) end -function parseImage( sRawData ) - expect(1, sRawData, "string") +--- Parses an image from a multi-line string +-- +-- @tparam string image The string containing the raw-image data. +-- @treturn table The parsed image data, suitable for use with +-- @{paintutils.drawImage}. +function parseImage( image ) + expect(1, image, "string") local tImage = {} - for sLine in ( sRawData .. "\n" ):gmatch( "(.-)\n" ) do -- read each line like original file handling did + for sLine in ( image .. "\n" ):gmatch( "(.-)\n" ) do parseLine( tImage, sLine ) end return tImage end -function loadImage( sPath ) - expect(1, sPath, "string") +--- Loads an image from a file. +-- +-- You can create a file suitable for being loaded using the `paint` program. +-- +-- @tparam string path The file to load. +-- +-- @treturn table|nil The parsed image data, suitable for use with +-- @{paintutils.drawImage}, or `nil` if the file does not exist. +function loadImage( path ) + expect(1, path, "string") - if fs.exists( sPath ) then - local file = io.open( sPath, "r" ) + if fs.exists( path ) then + local file = io.open( path, "r" ) local sContent = file:read("*a") file:close() - return parseImage( sContent ) -- delegate image parse to parseImage + return parseImage( sContent ) end return nil end -function drawPixel( xPos, yPos, nColour ) +--- Draws a single pixel to the current term at the specified position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number xPos The x position to draw at, where 1 is the far left. +-- @tparam number yPos The y position to draw at, where 1 is the very top. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. +function drawPixel( xPos, yPos, colour ) expect(1, xPos, "number") expect(2, yPos, "number") - expect(3, nColour, "number", "nil") - if nColour then - term.setBackgroundColor( nColour ) + expect(3, colour, "number", "nil") + + if type( xPos ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( xPos ) .. ")", 2 ) end + if type( yPos ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( yPos ) .. ")", 2 ) end + if colour ~= nil and type( colour ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( colour ) .. ")", 2 ) end + if colour then + term.setBackgroundColor( colour ) end return drawPixelInternal( xPos, yPos ) end -function drawLine( startX, startY, endX, endY, nColour ) +--- Draws a straight line from the start to end position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number startX The starting x position of the line. +-- @tparam number startY The starting y position of the line. +-- @tparam number endX The end x position of the line. +-- @tparam number endY The end y position of the line. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. +function drawLine( startX, startY, endX, endY, colour ) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") expect(4, endY, "number") - expect(5, nColour, "number", "nil") + expect(5, colour, "number", "nil") startX = math.floor(startX) startY = math.floor(startY) endX = math.floor(endX) endY = math.floor(endY) - if nColour then - term.setBackgroundColor( nColour ) + if colour then + term.setBackgroundColor( colour ) end if startX == endX and startY == endY then drawPixelInternal( startX, startY ) @@ -110,6 +152,18 @@ function drawLine( startX, startY, endX, endY, nColour ) end end +--- Draws the outline of a box on the current term from the specified start +-- position to the specified end position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number startX The starting x position of the line. +-- @tparam number startY The starting y position of the line. +-- @tparam number endX The end x position of the line. +-- @tparam number endY The end y position of the line. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. function drawBox( startX, startY, endX, endY, nColour ) expect(1, startX, "number") expect(2, startY, "number") @@ -154,7 +208,18 @@ function drawBox( startX, startY, endX, endY, nColour ) end end end - +--- Draws a filled box on the current term from the specified start position to +-- the specified end position. +-- +-- Be warned, this may change the position of the cursor and the current +-- background colour. You should not expect either to be preserved. +-- +-- @tparam number startX The starting x position of the line. +-- @tparam number startY The starting y position of the line. +-- @tparam number endX The end x position of the line. +-- @tparam number endY The end y position of the line. +-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be +-- the current background colour if not specified. function drawFilledBox( startX, startY, endX, endY, nColour ) expect(1, startX, "number") expect(2, startY, "number") @@ -194,12 +259,17 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) end end -function drawImage( tImage, xPos, yPos ) - expect(1, tImage, "table") +--- Draw an image loaded by @{paintutils.parseImage} or @{paintutils.loadImage}. +-- +-- @tparam table image The parsed image data. +-- @tparam number xPos The x position to start drawing at. +-- @tparam number xPos The y position to start drawing at. +function drawImage( image, xPos, yPos ) + expect(1, image, "table") expect(2, xPos, "number") expect(3, yPos, "number") - for y = 1, #tImage do - local tLine = tImage[y] + for y = 1, #image do + local tLine = image[y] for x = 1, #tLine do if tLine[x] > 0 then term.setBackgroundColor( tLine[x] ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua b/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua index 43b832c8b..ea4f8d43a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua @@ -1,3 +1,18 @@ +--- Provides a simple implementation of multitasking. +-- +-- Functions are not actually executed simultaniously, but rather this API will +-- automatically switch between them whenever they yield (eg whenever they call +-- @{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or +-- functions that call that, etc - basically, anything that causes the function +-- to "pause"). +-- +-- Each function executed in "parallel" gets its own copy of the event queue, +-- and so "event consuming" functions (again, mostly anything that causes the +-- script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API, +-- etc) can safely be used in one without affecting the event queue accessed by +-- the other. +-- +-- @module parallel local function create( ... ) local tFns = table.pack(...) @@ -55,12 +70,22 @@ local function runUntilLimit( _routines, _limit ) end end +--- Switches between execution of the functions, until any of them +-- finishes. If any of the functions errors, the message is propagated upwards +-- from the @{parallel.waitForAny} call. +-- +-- @tparam function ... The functions this task will run function waitForAny( ... ) local routines = create( ... ) return runUntilLimit( routines, #routines - 1 ) end +--- Switches between execution of the functions, until all of them are +-- finished. If any of the functions errors, the message is propagated upwards +-- from the @{parallel.waitForAll} call. +-- +-- @tparam function ... The functions this task will run function waitForAll( ... ) local routines = create( ... ) - runUntilLimit( routines, 0 ) + return runUntilLimit( routines, 0 ) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index a398d696f..c3c71ff65 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -1,110 +1,182 @@ +--- The Peripheral API is for interacting with peripherals connected to the +-- computer, such as the Disk Drive, the Advanced Monitor and Monitor. +-- +-- Each peripheral block has a name, either referring to the side the peripheral +-- can be found on, or a name on an adjacent wired network. +-- +-- If the peripheral is next to the computer, its side is either `front`, +-- `back`, `left`, `right`, `top` or `bottom`. If the peripheral is attached by +-- a cable, its side will follow the format `type_id`, for example `printer_0`. +-- +-- Peripheral functions are called *methods*, a term borrowed from Java. +-- +-- @module peripheral + local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = peripheral +local sides = rs.getSides() +--- Provides a list of all peripherals available. +-- +-- If a device is located directly next to the system, then its name will be +-- listed as the side it is attached to. If a device is attached via a Wired +-- Modem, then it'll be reported according to its name on the wired network. +-- +-- @treturn table A list of the names of all attached peripherals. function getNames() - local tResults = {} - for _, sSide in ipairs( rs.getSides() ) do - if native.isPresent( sSide ) then - table.insert( tResults, sSide ) - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - local tRemote = native.call( sSide, "getNamesRemote" ) - for _, sName in ipairs( tRemote ) do - table.insert( tResults, sName ) + local results = {} + for n = 1, #sides do + local side = sides[n] + if native.isPresent(side) then + table.insert(results, side) + if native.getType(side) == "modem" and not native.call(side, "isWireless") then + local remote = native.call(side, "getNamesRemote") + for _, name in ipairs(remote) do + table.insert(results, name) end end end end - return tResults + return results end -function isPresent( _sSide ) - expect(1, _sSide, "string") - if native.isPresent( _sSide ) then +--- Determines if a peripheral is present with the given name. +-- +-- @tparam string name The side or network name that you want to check. +-- @treturn boolean If a peripheral is present with the given name. +-- @usage peripheral.isPresent("top") +-- @usage peripheral.isPresent("monitor_0") +function isPresent(name) + expect(1, name, "string") + if native.isPresent(name) then return true end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return true - end + + for n = 1, #sides do + local name = sides[n] + if native.getType(name) == "modem" and not native.call(name, "isWireless") and + native.call(name, "isPresentRemote", name) + then + return true end end return false end -function getType( _sSide ) - expect(1, _sSide, "string") - if native.isPresent( _sSide ) then - return native.getType( _sSide ) +--- Get the type of the peripheral with the given name. +-- +-- @tparam string name The name of the peripheral to find. +-- @treturn string|nil The peripheral's type, or `nil` if it is not present. +function getType(name) + expect(1, name, "string") + if native.isPresent(name) then + return native.getType(name) end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return native.call( sSide, "getTypeRemote", _sSide ) - end + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return native.call(side, "getTypeRemote", name) end end return nil end -function getMethods( _sSide ) - expect(1, _sSide, "string") - if native.isPresent( _sSide ) then - return native.getMethods( _sSide ) +--- Get all available methods for the peripheral with the given name. +-- +-- @tparam string name The name of the peripheral to find. +-- @treturn table|nil A list of methods provided by this peripheral, or `nil` if +-- it is not present. +function getMethods(name) + expect(1, name, "string") + if native.isPresent(name) then + return native.getMethods(name) end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return native.call( sSide, "getMethodsRemote", _sSide ) - end + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return native.call(side, "getMethodsRemote", name) end end return nil end -function call( _sSide, _sMethod, ... ) - expect(1, _sSide, "string") - expect(2, _sMethod, "string") - if native.isPresent( _sSide ) then - return native.call( _sSide, _sMethod, ... ) +--- Call a method on a peripheral with a given name +-- +-- @tparam string name The name of the peripheral to invoke the method on. +-- @tparam string method The name of the method +-- @param ... Additional arguments to pass to the method +-- @return The return values of the peripheral method. +-- +-- @usage peripheral.call("top", "open", 1) +function call(name, method, ...) + expect(1, name, "string") + expect(2, method, "string") + if native.isPresent(name) then + return native.call(name, method, ...) end - for _, sSide in ipairs( rs.getSides() ) do - if native.getType( sSide ) == "modem" and not native.call( sSide, "isWireless" ) then - if native.call( sSide, "isPresentRemote", _sSide ) then - return native.call( sSide, "callRemote", _sSide, _sMethod, ... ) - end + + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) + then + return native.call(side, "callRemote", name, method, ...) end end return nil end -function wrap( _sSide ) - expect(1, _sSide, "string") - if peripheral.isPresent( _sSide ) then - local tMethods = peripheral.getMethods( _sSide ) - local tResult = {} - for _, sMethod in ipairs( tMethods ) do - tResult[sMethod] = function( ... ) - return peripheral.call( _sSide, sMethod, ... ) - end - end - return tResult +--- Get a table containing functions pointing to the peripheral's methods, which +-- can then be called as if using @{peripheral.call}. +-- +-- @tparam string name The name of the peripheral to wrap. +-- @treturn table|nil The table containing the peripheral's methods, or `nil` if +-- there is no peripheral present with the given name. +-- @usage peripheral.wrap("top").open(1) +function wrap(name) + expect(1, name, "string") + + local methods = peripheral.getMethods(name) + if not methods then + return nil end - return nil + + local result = {} + for _, method in ipairs(methods) do + result[method] = function(...) + return peripheral.call(name, method, ...) + end + end + return result end -function find( sType, fnFilter ) - expect(1, sType, "string") - expect(2, fnFilter, "function", "nil") - local tResults = {} - for _, sName in ipairs( peripheral.getNames() ) do - if peripheral.getType( sName ) == sType then - local wrapped = peripheral.wrap( sName ) - if fnFilter == nil or fnFilter( sName, wrapped ) then - table.insert( tResults, wrapped ) +--- Find all peripherals of a specific type, and return the +-- @{peripheral.wrap|wrapped} peripherals. +-- +-- @tparam string ty The type of peripheral to look for. +-- @tparam[opt] function(name:string, wrapped:table):boolean filter A +-- filter function, which takes the peripheral's name and wrapped table +-- and returns if it should be included in the result. +-- @treturn table... 0 or more wrapped peripherals matching the given filters. +-- @usage local monitors = { peripheral.find("monitor") } +-- @usage peripheral.find("modem", rednet.open) +function find(ty, filter) + expect(1, ty, "string") + expect(2, filter, "function", "nil") + + local results = {} + for _, name in ipairs(peripheral.getNames()) do + if peripheral.getType(name) == ty then + local wrapped = peripheral.wrap(name) + if filter == nil or filter(name, wrapped) then + table.insert(results, wrapped) end end end - return table.unpack( tResults ) + return table.unpack(results) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index d6bf5d668..9152aa647 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -1,51 +1,92 @@ +--- The Rednet API allows systems to communicate between each other without +-- using redstone. It serves as a wrapper for the modem API, offering ease of +-- functionality (particularly in regards to repeating signals) with some +-- expense of fine control. +-- +-- In order to send and receive data, a modem (either wired, wireless, or ender) +-- is required. The data reaches any possible destinations immediately after +-- sending it, but is range limited. +-- +-- Rednet also allows you to use a "protocol" - simple string names indicating +-- what messages are about. Receiving systems may filter messages according to +-- their protocols, thereby automatically ignoring incoming messages which don't +-- specify an identical string. It's also possible to @{rednet.lookup|lookup} +-- which systems in the area use certain protocols, hence making it easier to +-- determine where given messages should be sent in the first place. +-- +-- @module rednet + local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- The channel used by the Rednet API to @{broadcast} messages. CHANNEL_BROADCAST = 65535 + +--- The channel used by the Rednet API to repeat messages. CHANNEL_REPEAT = 65533 local tReceivedMessages = {} local tReceivedMessageTimeouts = {} local tHostnames = {} -function open( sModem ) - expect(1, sModem, "string") - if peripheral.getType( sModem ) ~= "modem" then - error( "No such modem: " .. sModem, 2 ) +--- Opens a modem with the given @{peripheral} name, allowing it to send and +--- receive messages over rednet. +-- +-- This will open the modem on two channels: one which has the same +-- @{os.getComputerID|ID} as the computer, and another on +-- @{CHANNEL_BROADCAST|the broadcast channel}. +-- +-- @tparam string modem The name of the modem to open. +-- @throws If there is no such modem with the given name +function open( modem ) + expect(1, modem, "string") + if peripheral.getType( modem ) ~= "modem" then + error( "No such modem: " .. modem, 2 ) end - peripheral.call( sModem, "open", os.getComputerID() ) - peripheral.call( sModem, "open", CHANNEL_BROADCAST ) + peripheral.call( modem, "open", os.getComputerID() ) + peripheral.call( modem, "open", CHANNEL_BROADCAST ) end -function close( sModem ) - expect(1, sModem, "string", "nil") - if sModem then +--- Close a modem with the given @{peripheral} name, meaning it can no longer +-- send and receive rednet messages. +-- +-- @tparam[opt] string modem The side the modem exists on. If not given, all +-- open modems will be closed. +-- @throws If there is no such modem with the given name +function close( modem ) + expect(1, modem, "string", "nil") + if modem then -- Close a specific modem - if peripheral.getType( sModem ) ~= "modem" then - error( "No such modem: " .. sModem, 2 ) + if peripheral.getType( modem ) ~= "modem" then + error( "No such modem: " .. modem, 2 ) end - peripheral.call( sModem, "close", os.getComputerID() ) - peripheral.call( sModem, "close", CHANNEL_BROADCAST ) + peripheral.call( modem, "close", os.getComputerID() ) + peripheral.call( modem, "close", CHANNEL_BROADCAST ) else -- Close all modems - for _, sModem in ipairs( peripheral.getNames() ) do - if isOpen( sModem ) then - close( sModem ) + for _, modem in ipairs( peripheral.getNames() ) do + if isOpen( modem ) then + close( modem ) end end end end -function isOpen( sModem ) - expect(1, sModem, "string", "nil") - if sModem then +--- Determine if rednet is currently open. +-- +-- @tparam[opt] string modem Which modem to check. If not given, all connected +-- modems will be checked. +-- @treturn boolean If the given modem is open. +function isOpen( modem ) + expect(1, modem, "string", "nil") + if modem then -- Check if a specific modem is open - if peripheral.getType( sModem ) == "modem" then - return peripheral.call( sModem, "isOpen", os.getComputerID() ) and peripheral.call( sModem, "isOpen", CHANNEL_BROADCAST ) + if peripheral.getType( modem ) == "modem" then + return peripheral.call( modem, "isOpen", os.getComputerID() ) and peripheral.call( modem, "isOpen", CHANNEL_BROADCAST ) end else -- Check if any modem is open - for _, sModem in ipairs( peripheral.getNames() ) do - if isOpen( sModem ) then + for _, modem in ipairs( peripheral.getNames() ) do + if isOpen( modem ) then return true end end @@ -53,6 +94,23 @@ function isOpen( sModem ) return false end +--- Allows a computer or turtle with an attached modem to send a message +-- intended for a system with a specific ID. At least one such modem must first +-- be @{rednet.open|opened} before sending is possible. +-- +-- Assuming the target was in range and also had a correctly opened modem, it +-- may then use @{rednet.receive} to collect the message. +-- +-- @tparam number nRecipient The ID of the receiving computer. +-- @param message The message to send. This should not contain coroutines or +-- functions, as they will be converted to @{nil}. +-- @tparam[opt] string sProtocol The "protocol" to send this message under. When +-- using @{rednet.receive} one can filter to only receive messages sent under a +-- particular protocol. +-- @treturn boolean If this message was successfully sent (i.e. if rednet is +-- currently @{rednet.open|open}). Note, this does not guarantee the message was +-- actually _received_. +-- @see rednet.receive function send( nRecipient, message, sProtocol ) expect(1, nRecipient, "number") expect(3, sProtocol, "string", "nil") @@ -91,11 +149,34 @@ function send( nRecipient, message, sProtocol ) return sent end +--- Broadcasts a string message over the predefined @{CHANNEL_BROADCAST} +-- channel. The message will be received by every device listening to rednet. +-- +-- @param message The message to send. This should not contain coroutines or +-- functions, as they will be converted to @{nil}. +-- @tparam[opt] string sProtocol The "protocol" to send this message under. When +-- using @{rednet.receive} one can filter to only receive messages sent under a +-- particular protocol. +-- @see rednet.receive function broadcast( message, sProtocol ) expect(2, sProtocol, "string", "nil") send( CHANNEL_BROADCAST, message, sProtocol ) end +--- Wait for a rednet message to be received, or until `nTimeout` seconds have +-- elapsed. +-- +-- @tparam[opt] string sProtocolFilter The protocol the received message must be +-- sent with. If specified, any messages not sent under this protocol will be +-- discarded. +-- @tparam[opt] number nTimeout The number of seconds to wait if no message is +-- received. +-- @treturn[1] number The computer which sent this message +-- @return[1] The received message +-- @treturn[1] string|nil The protocol this message was sent under. +-- @treturn[2] nil If the timeout elapsed and no message was received. +-- @see rednet.broadcast +-- @see rednet.send function receive( sProtocolFilter, nTimeout ) -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility if type(sProtocolFilter) == "number" and nTimeout == nil then @@ -132,6 +213,24 @@ function receive( sProtocolFilter, nTimeout ) end end +--- Register the system as "hosting" the desired protocol under the specified +-- name. If a rednet @{rednet.lookup|lookup} is performed for that protocol (and +-- maybe name) on the same network, the registered system will automatically +-- respond via a background process, hence providing the system performing the +-- lookup with its ID number. +-- +-- Multiple computers may not register themselves on the same network as having +-- the same names against the same protocols, and the title `localhost` is +-- specifically reserved. They may, however, share names as long as their hosted +-- protocols are different, or if they only join a given network after +-- "registering" themselves before doing so (eg while offline or part of a +-- different network). +-- +-- @tparam string sProtocol The protocol this computer provides. +-- @tparam string sHostname The name this protocol exposes for the given protocol. +-- @throws If trying to register a hostname which is reserved, or currently in use. +-- @see rednet.unhost +-- @see rednet.lookup function host( sProtocol, sHostname ) expect(1, sProtocol, "string") expect(2, sHostname, "string") @@ -146,11 +245,29 @@ function host( sProtocol, sHostname ) end end +--- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer +--- respond to @{rednet.lookup} requests. +-- +-- @tparam string sProtocol The protocol to unregister your self from. function unhost( sProtocol ) expect(1, sProtocol, "string") tHostnames[ sProtocol ] = nil end +--- Search the local rednet network for systems @{rednet.host|hosting} the +-- desired protocol and returns any computer IDs that respond as "registered" +-- against it. +-- +-- If a hostname is specified, only one ID will be returned (assuming an exact +-- match is found). +-- +-- @tparam string sProtocol The protocol to search for. +-- @tparam[opt] string sHostname The hostname to search for. +-- +-- @treturn[1] { number }|nil A list of computer IDs hosting the given +-- protocol, or @{nil} if none exist. +-- @treturn[2] number|nil The computer ID with the provided hostname and protocol, +-- or @{nil} if none exists. function lookup( sProtocol, sHostname ) expect(1, sProtocol, "string") expect(2, sHostname, "string", "nil") @@ -216,6 +333,8 @@ function lookup( sProtocol, sHostname ) end local bRunning = false + +--- @local function run() if bRunning then error( "rednet is already running", 2 ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 54da34a32..50501bbaf 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -1,16 +1,31 @@ +--- The settings API allows to store values and save them to a file for +-- persistent configurations for CraftOS and your programs. +-- +-- By default, the settings API will load its configuration from the +-- `/.settings` file. One can then use @{settings.save} to update the file. +-- +-- @module settings + local expect = dofile("rom/modules/main/cc/expect.lua").expect local tSettings = {} -function set( sName, value ) - expect(1, sName, "string") +--- Set the value of a setting. +-- +-- @tparam string name The name of the setting to set +-- @param value The setting's value. This cannot be `nil`, and must be +-- serialisable by @{textutils.serialize}. +-- @throws If this value cannot be serialised +-- @see settings.unset +function set( name, value ) + expect(1, name, "string") expect(2, value, "number", "string", "boolean", "table") if type(value) == "table" then -- Ensure value is serializeable value = textutils.unserialize( textutils.serialize(value) ) end - tSettings[ sName ] = value + tSettings[ name ] = value end local copy @@ -26,9 +41,15 @@ function copy( value ) end end -function get( sName, default ) - expect(1, sName, "string") - local result = tSettings[ sName ] +--- Get the value of a setting. +-- +-- @tparam string name The name of the setting to get. +-- @param[opt] default The value to use should there be pre-existing value for +-- this setting. Defaults to `nil`. +-- @return The setting's, or `default` if the setting has not been set. +function get( name, default ) + expect(1, name, "string") + local result = tSettings[ name ] if result ~= nil then return copy(result) else @@ -36,15 +57,31 @@ function get( sName, default ) end end -function unset( sName ) - expect(1, sName, "string") - tSettings[ sName ] = nil +--- Remove the value of a setting, clearing it back to `nil`. +-- +-- @{settings.get} will return the default value until the setting's value is +-- @{settings.set|set}, or the computer is rebooted. +-- +-- @tparam string name The name of the setting to unset. +-- @see settings.set +-- @see settings.clear +function unset( name ) + expect(1, name, "string") + tSettings[ name ] = nil end +--- Removes the value of all settings. Equivalent to calling @{settings.unset} +--- on every setting. +-- +-- @see settings.unset function clear() tSettings = {} end +--- Get the names of all currently defined settings. +-- +-- @treturn { string } An alphabetically sorted list of all currently-defined +-- settings. function getNames() local result = {} for k in pairs( tSettings ) do @@ -54,6 +91,17 @@ function getNames() return result end +--- Load settings from the given file. +-- +-- Existing settings will be merged with any pre-existing ones. Conflicting +-- entries will be overwritten, but any others will be preserved. +-- +-- @tparam string sPath The file to load from. +-- @treturn boolean Whether settings were successfully read from this +-- file. Reasons for failure may include the file not existing or being +-- corrupted. +-- +-- @see settings.save function load( sPath ) expect(1, sPath, "string") local file = fs.open( sPath, "r" ) @@ -79,6 +127,15 @@ function load( sPath ) return true end +--- Save settings to the given file. +-- +-- This will entirely overwrite the pre-existing file. Settings defined in the +-- file, but not currently loaded will be removed. +-- +-- @tparam string sPath The path to save settings to. +-- @treturn boolean If the settings were successfully saved. +-- +-- @see settings.load function save( sPath ) expect(1, sPath, "string") local file = fs.open( sPath, "w" ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index c6f9c2a9b..095fe1e9f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -1,3 +1,8 @@ +--- The Terminal API provides functions for writing text to the terminal and +-- monitors, and drawing ASCII graphics. +-- +-- @module term + local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = term.native and term.native() or term @@ -9,8 +14,26 @@ local function wrap( _sFunction ) end end -local term = {} +local term = _ENV +--- Redirects terminal output to a monitor, a @{window}, or any other custom +-- terminal object. Once the redirect is performed, any calls to a "term" +-- function - or to a function that makes use of a term function, as @{print} - +-- will instead operate with the new terminal object. +-- +-- A "terminal object" is simply a table that contains functions with the same +-- names - and general features - as those found in the term table. For example, +-- a wrapped monitor is suitable. +-- +-- The redirect can be undone by pointing back to the previous terminal object +-- (which this function returns whenever you switch). +-- +-- @tparam Redirect target The terminal redirect the @{term} API will draw to. +-- @treturn Redirect The previous redirect object, as returned by +-- @{term.current}. +-- @usage +-- Redirect to a monitor on the right of the computer. +-- term.redirect(peripheral.wrap("right")) term.redirect = function( target ) expect(1, target, "table") if target == term or target == _G.term then @@ -30,14 +53,24 @@ term.redirect = function( target ) return oldRedirectTarget end +--- Returns the current terminal object of the computer. +-- +-- @treturn Redirect The current terminal redirect +-- @usage +-- Create a new @{window} which draws to the current redirect target +-- window.create(term.current(), 1, 1, 10, 10) term.current = function() return redirectTarget end +--- Get the native terminal object of the current computer. +-- +-- It is recommended you do not use this function unless you absolutely have +-- to. In a multitasked environment, @{term.native} will _not_ be the current +-- terminal object, and so drawing may interfere with other programs. +-- +-- @treturn Redirect The native terminal redirect. term.native = function() - -- NOTE: please don't use this function unless you have to. - -- If you're running in a redirected or multitasked enviorment, term.native() will NOT be - -- the current terminal when your program starts up. It is far better to use term.current() return native end @@ -49,12 +82,7 @@ for _, method in ipairs { "nativePaletteColor", "nativePaletteColour" } do end for k, v in pairs( native ) do - if type( k ) == "string" and type( v ) == "function" and term[k] == nil then + if type( k ) == "string" and type( v ) == "function" and rawget(term, k) == nil then term[k] = wrap( k ) end end - -local env = _ENV -for k, v in pairs( term ) do - env[k] = v -end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index de7cd4e95..4be4388f7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -1,5 +1,20 @@ +--- The `textutils` API provides helpful utilities for formatting and +-- manipulating strings. +-- +-- @module textutils + local expect = dofile("rom/modules/main/cc/expect.lua").expect +--- Slowly writes string text at current cursor position, +-- character-by-character. +-- +-- Like @{write}, this does not insert a newline at the end. +-- +-- @tparam string sText The the text to write to the screen +-- @tparam[opt] number nRate The number of characters to write each second, +-- Defaults to 20. +-- @usage textutils.slowWrite("Hello, world!") +-- @usage textutils.slowWrite("Hello, world!", 5) function slowWrite( sText, nRate ) expect(2, nRate, "number", "nil") nRate = nRate or 20 @@ -21,11 +36,28 @@ function slowWrite( sText, nRate ) end end +--- Slowly prints string text at current cursor position, +-- character-by-character. +-- +-- Like @{print}, this inserts a newline after printing. +-- +-- @tparam string sText The the text to write to the screen +-- @tparam[opt] number nRate The number of characters to write each second, +-- Defaults to 20. +-- @usage textutils.slowPrint("Hello, world!") +-- @usage textutils.slowPrint("Hello, world!", 5) function slowPrint( sText, nRate ) slowWrite( sText, nRate ) print() end +--- Takes input time and formats it in a more readable format such as `6:30 PM`. +-- +-- @tparam number nTime The time to format, as provided by @{os.time}. +-- @tparam[opt] boolean bTwentyFourHour Whether to format this as a 24-hour +-- clock (`18:30`) rather than a 12-hour one (`6:30 AM`) +-- @treturn string The formatted time +-- @usage textutils.formatTime(os.time()) function formatTime( nTime, bTwentyFourHour ) expect(1, nTime, "number") expect(2, bTwentyFourHour, "boolean", "nil") @@ -71,6 +103,23 @@ local function makePagedScroll( _term, _nFreeLines ) end end +--- Prints a given string to the display. +-- +-- If the action can be completed without scrolling, it acts much the same as +-- @{print}; otherwise, it will throw up a "Press any key to continue" prompt at +-- the bottom of the display. Each press will cause it to scroll down and write +-- a single line more before prompting again, if need be. +-- +-- @tparam string _sText The text to print to the screen. +-- @tparam[opt] number _nFreeLines The number of lines which will be +-- automatically scrolled before the first prompt appears (meaning _nFreeLines + +-- 1 lines will be printed). This can be set to the terminal's height - 2 to +-- always try to fill the screen. Defaults to 0, meaning only one line is +-- displayed before prompting. +-- @treturn number The number of lines printed. +-- @usage +-- local width, height = term.getSize() +-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2) function pagedPrint( _sText, _nFreeLines ) expect(2, _nFreeLines, "number", "nil") -- Setup a redirector @@ -159,10 +208,30 @@ local function tabulateCommon( bPaged, ... ) end end +--- Prints tables in a structured form. +-- +-- This accepts multiple arguments, either a table or a number. When +-- encountering a table, this will be treated as a table row, with each column +-- width being auto-adjusted. +-- +-- When encountering a number, this sets the text color of the subsequent rows to it. +-- +-- @tparam {string...}|number ... The rows and text colors to display. +-- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" }) function tabulate( ... ) return tabulateCommon( false, ... ) end +--- Prints tables in a structured form, stopping and prompting for input should +-- the result not fit on the terminal. +-- +-- This functions identically to @{textutils.tabulate}, but will prompt for user +-- input should the whole output not fit on the display. +-- +-- @tparam {string...}|number ... The rows and text colors to display. +-- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" }) +-- @see textutils.tabulate +-- @see textutils.pagedPrint function pagedTabulate( ... ) return tabulateCommon( true, ... ) end @@ -238,6 +307,13 @@ local function serializeImpl( t, tTracking, sIndent ) end end +--- A table representing an empty JSON array, in order to distinguish it from an +-- empty JSON object. +-- +-- The contents of this table should not be modified. +-- +-- @usage textutils.serialiseJSON(textutils.empty_json_array) +-- @see textutils.serialiseJSON empty_json_array = setmetatable({}, { __newindex = function() error("attempt to mutate textutils.empty_json_array", 2) @@ -310,11 +386,28 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) end end +--- Convert a Lua object into a textual representation, suitable for +-- saving in a file or pretty-printing. +-- +-- @param t The object to serialise +-- @treturn string The serialised representation +-- @throws If the object contains a value which cannot be +-- serialised. This includes functions and tables which appear multiple +-- times. function serialize( t ) local tTracking = {} return serializeImpl( t, tTracking, "" ) end +serialise = serialize -- GB version + +--- Converts a serialised string back into a reassembled Lua object. +-- +-- This is mainly used together with @{textutils.serialize}. +-- +-- @tparam string s The serialised string to deserialise. +-- @return[1] The deserialised object +-- @treturn[2] nil If the object could not be deserialised. function unserialize( s ) expect(1, s, "string") local func = load( "return " .. s, "unserialize", "t", {} ) @@ -327,6 +420,26 @@ function unserialize( s ) return nil end +unserialise = unserialize -- GB version + +--- Returns a JSON representation of the given data. +-- +-- This function attempts to guess whether a table is a JSON array or +-- object. However, empty tables are assumed to be empty objects - use +-- @{textutils.empty_json_array} to mark an empty array. +-- +-- This is largely intended for interacting with various functions from the +-- @{commands} API, though may also be used in making @{http} requests. +-- +-- @param t The value to serialise. Like @{textutils.serialise}, this should not +-- contain recursive tables or functions. +-- @tparam[opt] boolean bNBTStyle Whether to produce NBT-style JSON (non-quoted keys) +-- instead of standard JSON. +-- @treturn string The JSON representation of the input. +-- @throws If the object contains a value which cannot be +-- serialised. This includes functions and tables which appear multiple +-- times. +-- @usage textutils.serializeJSON({ values = { 1, "2", true } }) function serializeJSON( t, bNBTStyle ) expect(1, t, "table", "string", "number", "boolean") expect(2, bNBTStyle, "boolean", "nil") @@ -334,6 +447,13 @@ function serializeJSON( t, bNBTStyle ) return serializeJSONImpl( t, tTracking, bNBTStyle or false ) end +serialiseJSON = serializeJSON -- GB version + +--- Replaces certain characters in a string to make it safe for use in URLs or POST data. +-- +-- @tparam string str The string to encode +-- @treturn string The encoded string. +-- @usage print("https://example.com/?view=" .. textutils.urlEncode(read())) function urlEncode( str ) expect(1, str, "string") if str then @@ -356,6 +476,23 @@ function urlEncode( str ) end local tEmpty = {} + +--- Provides a list of possible completions for a partial Lua expression. +-- +-- If the completed element is a table, suggestions will have `.` appended to +-- them. Similarly, functions have `(` appended to them. +-- +-- @tparam string sSearchText The partial expression to complete, such as a +-- variable name or table index. +-- +-- @tparam[opt] table tSearchTable The table to find variables in, defaulting to +-- the global environment (@{_G}). The function also searches the "parent" +-- environment via the `__index` metatable field. +-- +-- @treturn { string... } The (possibly empty) list of completions. +-- @see shell.setCompletionFunction +-- @see read +-- @usage textutils.complete( "pa", getfenv() ) function complete( sSearchText, tSearchTable ) expect(1, sSearchText, "string") expect(2, tSearchTable, "table", "nil") @@ -431,8 +568,3 @@ function complete( sSearchText, tSearchTable ) table.sort( tResults ) return tResults end - --- GB versions -serialise = serialize -unserialise = unserialize -serialiseJSON = serializeJSON diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua index c471212a4..9b5fab369 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua @@ -1,3 +1,6 @@ +--- The turtle API allows you to control your turtle. +-- +-- @module turtle if not turtle then error( "Cannot load turtle API on computer", 2 ) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua index 4d6c159f9..e19937bba 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua @@ -1,85 +1,178 @@ +--- The vector API provides methods to create and manipulate vectors. +-- +-- An introduction to vectors can be found on [Wikipedia][wiki]. +-- +-- [wiki]: http://en.wikipedia.org/wiki/Euclidean_vector +-- +-- @module vector +--- A 3-dimensional vector, with `x`, `y`, and `z` values. +-- +-- This is suitable for representing both position and directional vectors. +-- +-- @type Vector local vector = { - add = function( self, o ) - return vector.new( - self.x + o.x, - self.y + o.y, - self.z + o.z - ) - end, - sub = function( self, o ) - return vector.new( - self.x - o.x, - self.y - o.y, - self.z - o.z - ) - end, - mul = function( self, m ) - return vector.new( - self.x * m, - self.y * m, - self.z * m - ) - end, - div = function( self, m ) - return vector.new( - self.x / m, - self.y / m, - self.z / m - ) - end, - unm = function( self ) - return vector.new( - -self.x, - -self.y, - -self.z - ) - end, - dot = function( self, o ) - return self.x * o.x + self.y * o.y + self.z * o.z - end, - cross = function( self, o ) - return vector.new( - self.y * o.z - self.z * o.y, - self.z * o.x - self.x * o.z, - self.x * o.y - self.y * o.x - ) - end, - length = function( self ) - return math.sqrt( self.x * self.x + self.y * self.y + self.z * self.z ) - end, - normalize = function( self ) - return self:mul( 1 / self:length() ) - end, - round = function( self, nTolerance ) - nTolerance = nTolerance or 1.0 - return vector.new( - math.floor( (self.x + nTolerance * 0.5) / nTolerance ) * nTolerance, - math.floor( (self.y + nTolerance * 0.5) / nTolerance ) * nTolerance, - math.floor( (self.z + nTolerance * 0.5) / nTolerance ) * nTolerance - ) - end, - tostring = function( self ) - return self.x .. "," .. self.y .. "," .. self.z - end, + --- Adds two vectors together. + -- + -- @tparam Vector self The first vector to add. + -- @tparam Vector o The second vector to add. + -- @treturn Vector The resulting vector + -- @usage v1:add(v2) + -- @usage v1 + v2 + add = function(self, o) + return vector.new( + self.x + o.x, + self.y + o.y, + self.z + o.z + ) + end, + + --- Subtracts one vector from another. + -- + -- @tparam Vector self The vector to subtract from. + -- @tparam Vector o The vector to subtract. + -- @treturn Vector The resulting vector + -- @usage v1:sub(v2) + -- @usage v1 - v2 + sub = function(self, o) + return vector.new( + self.x - o.x, + self.y - o.y, + self.z - o.z + ) + end, + + --- Multiplies a vector by a scalar value. + -- + -- @tparam Vector self The vector to multiply. + -- @tparam number m The scalar value to multiply with. + -- @treturn Vector A vector with value `(x * m, y * m, z * m)`. + -- @usage v:mul(3) + -- @usage v * 3 + mul = function(self, m) + return vector.new( + self.x * m, + self.y * m, + self.z * m + ) + end, + + --- Divides a vector by a scalar value. + -- + -- @tparam Vector self The vector to divide. + -- @tparam number m The scalar value to divide by. + -- @treturn Vector A vector with value `(x / m, y / m, z / m)`. + -- @usage v:div(3) + -- @usage v / 3 + div = function(self, m) + return vector.new( + self.x / m, + self.y / m, + self.z / m + ) + end, + + --- Negate a vector + -- + -- @tparam Vector self The vector to negate. + -- @treturn Vector The negated vector. + -- @usage -v + unm = function(self) + return vector.new( + -self.x, + -self.y, + -self.z + ) + end, + + --- Compute the dot product of two vectors + -- + -- @tparam Vector self The first vector to compute the dot product of. + -- @tparam Vector o The second vector to compute the dot product of. + -- @treturn Vector The dot product of `self` and `o`. + -- @usage v1:dot(v2) + dot = function(self, o) + return self.x * o.x + self.y * o.y + self.z * o.z + end, + + --- Compute the cross product of two vectors + -- + -- @tparam Vector self The first vector to compute the cross product of. + -- @tparam Vector o The second vector to compute the cross product of. + -- @treturn Vector The cross product of `self` and `o`. + -- @usage v1:cross(v2) + cross = function(self, o) + return vector.new( + self.y * o.z - self.z * o.y, + self.z * o.x - self.x * o.z, + self.x * o.y - self.y * o.x + ) + end, + + --- Get the length (also referred to as magnitude) of this vector. + -- @tparam Vector self This vector. + -- @treturn number The length of this vector. + length = function(self) + return math.sqrt( self.x * self.x + self.y * self.y + self.z * self.z ) + end, + + --- Divide this vector by its length, producing with the same direction, but + -- of length 1. + -- + -- @tparam Vector self The vector to normalise + -- @treturn Vector The normalised vector + -- @usage v:normalize() + normalize = function(self) + return self:mul( 1 / self:length() ) + end, + + --- Construct a vector with each dimension rounded to the nearest value. + -- + -- @tparam Vector self The vector to round + -- @tparam[opt] number tolerance The tolerance that we should round to, + -- defaulting to 1. For instance, a tolerance of 0.5 will round to the + -- nearest 0.5. + -- @treturn Vector The rounded vector. + round = function(self, tolerance) + tolerance = tolerance or 1.0 + return vector.new( + math.floor((self.x + tolerance * 0.5) / tolerance) * tolerance, + math.floor((self.y + tolerance * 0.5) / tolerance) * tolerance, + math.floor((self.z + tolerance * 0.5) / tolerance) * tolerance + ) + end, + + --- Convert this vector into a string, for pretty printing. + -- + -- @tparam Vector self This vector. + -- @treturn string This vector's string representation. + -- @usage v:tostring() + -- @usage tostring(v) + tostring = function(self) + return self.x .. "," .. self.y .. "," .. self.z + end, } local vmetatable = { - __index = vector, - __add = vector.add, - __sub = vector.sub, - __mul = vector.mul, - __div = vector.div, - __unm = vector.unm, - __tostring = vector.tostring, + __index = vector, + __add = vector.add, + __sub = vector.sub, + __mul = vector.mul, + __div = vector.div, + __unm = vector.unm, + __tostring = vector.tostring, } -function new( x, y, z ) - local v = { - x = tonumber(x) or 0, - y = tonumber(y) or 0, - z = tonumber(z) or 0, - } - setmetatable( v, vmetatable ) - return v +--- Construct a new @{Vector} with the given coordinates. +-- +-- @tparam number x The X coordinate or direction of the vector. +-- @tparam number y The Y coordinate or direction of the vector. +-- @tparam number z The Z coordinate or direction of the vector. +-- @treturn Vector The constructed vector. +function new(x, y, z) + return setmetatable({ + x = tonumber(x) or 0, + y = tonumber(y) or 0, + z = tonumber(z) or 0, + }, vmetatable) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 0e24b7696..5617c2175 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -1,3 +1,32 @@ +--- The Window API allows easy definition of spaces within the display that can +-- be written/drawn to, then later redrawn/repositioned/etc as need be. The API +-- itself contains only one function, @{window.create}, which returns the +-- windows themselves. +-- +-- Windows are considered terminal objects - as such, they have access to nearly +-- all the commands in the term API (plus a few extras of their own, listed +-- within said API) and are valid targets to redirect to. +-- +-- Each window has a "parent" terminal object, which can be the computer's own +-- display, a monitor, another window or even other, user-defined terminal +-- objects. Whenever a window is rendered to, the actual screen-writing is +-- performed via that parent (or, if that has one too, then that parent, and so +-- forth). Bear in mind that the cursor of a window's parent will hence be moved +-- around etc when writing a given child window. +-- +-- Windows retain a memory of everything rendered "through" them (hence acting +-- as display buffers), and if the parent's display is wiped, the window's +-- content can be easily redrawn later. A window may also be flagged as +-- invisible, preventing any changes to it from being rendered until it's +-- flagged as visible once more. +-- +-- A parent terminal object may have multiple children assigned to it, and +-- windows may overlap. For example, the Multishell system functions by +-- assigning each tab a window covering the screen, each using the starting +-- terminal display as its parent, and only one of which is visible at a time. +-- +-- @module window + local expect = dofile("rom/modules/main/cc/expect.lua").expect local tHex = { @@ -23,6 +52,24 @@ local type = type local string_rep = string.rep local string_sub = string.sub +--- Returns a terminal object that is a space within the specified parent +-- terminal object. This can then be used (or even redirected to) in the same +-- manner as eg a wrapped monitor. Refer to @{term|the term API} for a list of +-- functions available to it. +-- +-- @{term} itself may not be passed as the parent, though @{term.native} is +-- acceptable. Generally, @{term.current} or a wrapped monitor will be most +-- suitable, though windows may even have other windows assigned as their +-- parents. +-- +-- @tparam term.Redirect parent The parent terminal redirect to draw to. +-- @tparam number nX The x coordinate this window is drawn at in the parent terminal +-- @tparam number nY The y coordinate this window is drawn at in the parent terminal +-- @tparam number nWidth The width of this window +-- @tparam number nHeight The height of this window +-- @tparam[opt] boolean bStartVisible Whether this window is visible by +-- default. Defaults to `true`. +-- @treturn Window The constructed window function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) expect(1, parent, "table") expect(2, nX, "number") @@ -182,7 +229,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end end - -- Terminal implementation + --- Terminal implementation + -- + -- @type Window local window = {} function window.write( sText ) diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua index 7b1a53e8c..1791a29a0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua @@ -7,7 +7,7 @@ local native_select, native_type = select, type --- Expect an argument to have a specific type. -- --- @tparam int index The 1-based argument index. +-- @tparam number index The 1-based argument index. -- @param value The argument's value. -- @tparam string ... The allowed types of the argument. -- @throws If the value is not one of the allowed types. diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua index 2fdaee187..5a34ad389 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -2,7 +2,7 @@ -- aesthetically pleasing manner. -- -- In order to display something using @{cc.pretty}, you build up a series of --- @{documents|Doc}. These behave a little bit like strings; you can concatenate +-- @{Doc|documents}. These behave a little bit like strings; you can concatenate -- them together and then print them to the screen. -- -- However, documents also allow you to control how they should be printed. There @@ -28,7 +28,7 @@ local function append(out, value) out[n], out.n = value, n end ---- A document, which +--- A document containing formatted text, with multiple possible layouts. -- -- Documents effectively represent a sequence of strings in alternative layouts, -- which we will try to print in the most compact form necessary. @@ -61,7 +61,7 @@ end -- -- @tparam string text The string to construct a new document with. -- @tparam[opt] number colour The colour this text should be printed with. If not given, we default to the current --- colour. +-- colour. -- @treturn Doc The document with the provided text. local function text(text, colour) expect(1, text, "string") @@ -94,7 +94,7 @@ local function text(text, colour) end --- Concatenate several documents together. This behaves very similar to string concatenation. - +-- -- @tparam Doc|string ... The documents to concatenate. -- @treturn Doc The concatenated documents. -- @usage pretty.concat(doc1, " - ", doc2) @@ -113,7 +113,7 @@ local function concat(...) return setmetatable(args, Doc) end -Doc.__concat = concat +Doc.__concat = concat --- @local --- Indent later lines of the given document with the given number of spaces. -- @@ -121,7 +121,7 @@ Doc.__concat = concat -- ```txt -- foo -- bar --- `` +-- ``` -- by two spaces will produce -- ```txt -- foo @@ -271,8 +271,9 @@ end -- -- @tparam Doc doc The document to render. -- @tparam[opt] number width The maximum width of this document. Note that long strings will not be wrapped to --- fit this width - it is only used for finding the best layout. +-- fit this width - it is only used for finding the best layout. -- @tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in. +-- @treturn string The rendered document as a string. local function render(doc, width, ribbon_frac) if getmetatable(doc) ~= Doc then expect(1, doc, "document") end expect(2, width, "number", "nil") @@ -316,6 +317,8 @@ local function render(doc, width, ribbon_frac) return table.concat(out, "", 1, out.n) end +Doc.__tostring = render --- @local + local keywords = { [ "and" ] = true, [ "break" ] = true, [ "do" ] = true, [ "else" ] = true, [ "elseif" ] = true, [ "end" ] = true, [ "false" ] = true, [ "for" ] = true, diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 20dcd4cd2..2fe853b95 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -356,32 +356,33 @@ function expect_mt:called_with_matching(...) return called_with_check(matches, self, ...) end -local expect = setmetatable({ - --- Construct an expectation on the error message calling this function - -- produces - -- - -- @tparam fun The function to call - -- @param ... The function arguments - -- @return The new expectation - error = function(fun, ...) - local ok, res = pcall(fun, ...) local _, line = pcall(error, "", 2) - if ok then fail("expected function to error") end - if res:sub(1, #line) == line then - res = res:sub(#line + 1) - elseif res:sub(1, 7) == "pcall: " then - res = res:sub(8) - end - return setmetatable({ value = res }, expect_mt) - end, -}, { - --- Construct a new expectation from the provided value - -- - -- @param value The value to apply assertions to - -- @return The new expectation - __call = function(_, value) - return setmetatable({ value = value }, expect_mt) - end, -}) +local expect = {} +setmetatable(expect, expect) + +--- Construct an expectation on the error message calling this function +-- produces +-- +-- @tparam fun The function to call +-- @param ... The function arguments +-- @return The new expectation +function expect.error(fun, ...) + local ok, res = pcall(fun, ...) local _, line = pcall(error, "", 2) + if ok then fail("expected function to error") end + if res:sub(1, #line) == line then + res = res:sub(#line + 1) + elseif res:sub(1, 7) == "pcall: " then + res = res:sub(8) + end + return setmetatable({ value = res }, expect_mt) +end + +--- Construct a new expectation from the provided value +-- +-- @param value The value to apply assertions to +-- @return The new expectation +function expect:__call(value) + return setmetatable({ value = value }, expect_mt) +end --- The stack of "describe"s. local test_stack = { n = 0 } @@ -390,7 +391,8 @@ local test_stack = { n = 0 } local tests_locked = false --- The list of tests that we'll run -local test_list, test_map, test_count = { }, { }, 0 +local test_list = {} +local test_map, test_count = {}, 0 --- Add a new test to our queue. -- diff --git a/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua index 38b2ecc3c..2949c1a75 100644 --- a/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua @@ -163,7 +163,7 @@ describe("cc.pretty", function() end) describe("pretty", function() - --- We make use of "render" here, as it's considerably easier than checking against the actual structure. + -- We make use of "render" here, as it's considerably easier than checking against the actual structure. -- However, it does also mean our tests are less unit-like. local function pretty(x, width) return pp.render(pp.pretty(x), width) end From e52d98ad8bcce5b85647921a7aa12168451a1ac6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 10 Apr 2020 14:28:46 +0100 Subject: [PATCH 162/711] Make IDAssigner.getNextID synchronized This should prevent race conditions when allocating IDs. Fixes #386. --- src/main/java/dan200/computercraft/shared/util/IDAssigner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index fd0f222ab..fbbf461bf 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -36,7 +36,7 @@ public final class IDAssigner return getNextID( file, false ); } - private static int getNextID( File location, boolean directory ) + private static synchronized int getNextID( File location, boolean directory ) { // Determine where to locate ID file File lastIdFile; From 062977336a45f90612e075f90d5eee7360c5e880 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 10 Apr 2020 14:43:42 +0100 Subject: [PATCH 163/711] Handle missing file metadata on zip files - Return EPOCH if a zip entry's creation/modification/access time is missing. - If a BasicFileAttributes.*Time method returns null, use 0 as our time. This shouldn't happen, but is a good sanity check. Fixes #371 --- .../dan200/computercraft/core/apis/FSAPI.java | 10 ++++-- .../core/filesystem/JarMount.java | 15 +++++++-- .../core/filesystem/JarMountTest.java | 31 ++++++++++++++++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 74f786f23..90a866a53 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -23,6 +23,7 @@ import java.io.BufferedWriter; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; import java.util.HashMap; import java.util.Map; import java.util.OptionalLong; @@ -359,8 +360,8 @@ public class FSAPI implements ILuaAPI { BasicFileAttributes attributes = m_fileSystem.getAttributes( path ); Map result = new HashMap<>(); - result.put( "modification", attributes.lastModifiedTime().toMillis() ); - result.put( "created", attributes.creationTime().toMillis() ); + result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); + result.put( "created", getFileTime( attributes.creationTime() ) ); result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); result.put( "isDir", attributes.isDirectory() ); return new Object[] { result }; @@ -375,4 +376,9 @@ public class FSAPI implements ILuaAPI return null; } } + + private static long getFileTime( FileTime time ) + { + return time == null ? 0 : time.toMillis(); + } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index 2cf55a747..e2a1694e0 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -25,6 +25,7 @@ import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; +import java.time.Instant; import java.util.Enumeration; import java.util.HashMap; import java.util.List; @@ -290,19 +291,20 @@ public class JarMount implements IMount @Override public FileTime lastModifiedTime() { - return entry.getLastModifiedTime(); + return orEpoch( entry.getLastModifiedTime() ); } @Override public FileTime lastAccessTime() { - return entry.getLastAccessTime(); + return orEpoch( entry.getLastAccessTime() ); } @Override public FileTime creationTime() { - return entry.getCreationTime(); + FileTime time = entry.getCreationTime(); + return time == null ? lastModifiedTime() : time; } @Override @@ -340,5 +342,12 @@ public class JarMount implements IMount { return null; } + + private static final FileTime EPOCH = FileTime.from( Instant.EPOCH ); + + private static FileTime orEpoch( FileTime time ) + { + return time == null ? EPOCH : time; + } } } diff --git a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java index 31031c96c..4fedb95b5 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java @@ -15,20 +15,24 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import static org.junit.jupiter.api.Assertions.*; -@SuppressWarnings( "deprecation" ) public class JarMountTest { private static final File ZIP_FILE = new File( "test-files/jar-mount.zip" ); + private static final FileTime MODIFY_TIME = FileTime.from( Instant.EPOCH.plus( 2, ChronoUnit.DAYS ) ); + @BeforeAll public static void before() throws IOException { - if( ZIP_FILE.exists() ) return; ZIP_FILE.getParentFile().mkdirs(); try( ZipOutputStream stream = new ZipOutputStream( new FileOutputStream( ZIP_FILE ) ) ) @@ -36,7 +40,7 @@ public class JarMountTest stream.putNextEntry( new ZipEntry( "dir/" ) ); stream.closeEntry(); - stream.putNextEntry( new ZipEntry( "dir/file.lua" ) ); + stream.putNextEntry( new ZipEntry( "dir/file.lua" ).setLastModifiedTime( MODIFY_TIME ) ); stream.write( "print('testing')".getBytes( StandardCharsets.UTF_8 ) ); stream.closeEntry(); } @@ -63,7 +67,7 @@ public class JarMountTest { IMount mount = new JarMount( ZIP_FILE, "dir/file.lua" ); byte[] contents; - try( InputStream stream = mount.openForRead( "" ) ) + try( @SuppressWarnings( "deprecation" ) InputStream stream = mount.openForRead( "" ) ) { contents = ByteStreams.toByteArray( stream ); } @@ -76,11 +80,28 @@ public class JarMountTest { IMount mount = new JarMount( ZIP_FILE, "dir" ); byte[] contents; - try( InputStream stream = mount.openForRead( "file.lua" ) ) + try( @SuppressWarnings( "deprecation" ) InputStream stream = mount.openForRead( "file.lua" ) ) { contents = ByteStreams.toByteArray( stream ); } assertEquals( new String( contents, StandardCharsets.UTF_8 ), "print('testing')" ); } + + @Test + public void fileAttributes() throws IOException + { + BasicFileAttributes attributes = new JarMount( ZIP_FILE, "dir" ).getAttributes( "file.lua" ); + assertFalse( attributes.isDirectory() ); + assertEquals( "print('testing')".length(), attributes.size() ); + assertEquals( MODIFY_TIME, attributes.lastModifiedTime() ); + } + + @Test + public void directoryAttributes() throws IOException + { + BasicFileAttributes attributes = new JarMount( ZIP_FILE, "dir" ).getAttributes( "" ); + assertTrue( attributes.isDirectory() ); + assertEquals( 0, attributes.size() ); + } } From f4f71185aec32ea627f692cd763751400b52510c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 10 Apr 2020 21:17:31 +0100 Subject: [PATCH 164/711] Add back map rendering Closes #357. Also bump Forge and mappings versions - it includes a couple of bug fixes we need. --- build.gradle | 2 +- gradle.properties | 4 +- .../computercraft/client/ClientRegistry.java | 2 +- .../client/gui/FixedWidthFontRenderer.java | 29 +- .../proxy/ComputerCraftProxyClient.java | 8 +- .../client/render/CableHighlightRenderer.java | 4 +- .../client/render/ItemPocketRenderer.java | 193 +++++++++++++ .../client/render/ItemPrintoutRenderer.java | 5 +- .../render/MonitorHighlightRenderer.java | 4 +- .../client/render/PrintoutRenderer.java | 4 +- .../render/TileEntityMonitorRenderer.java | 12 +- .../render/TileEntityTurtleRenderer.java | 2 +- .../client/render/TurtleSmartItemModel.java | 7 +- .../client/render_old/ItemPocketRenderer.java | 260 ------------------ .../computercraft/shared/util/RecipeUtil.java | 5 +- 15 files changed, 244 insertions(+), 297 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java delete mode 100644 src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java diff --git a/build.gradle b/build.gradle index 98eb01cc3..3c0b386da 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.159' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.169' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } diff --git a/gradle.properties b/gradle.properties index ff2a4ac96..1cc272285 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,5 +3,5 @@ mod_version=1.86.2 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 -forge_version=31.0.13 -mappings_version=20200124-1.15.1 +forge_version=31.1.41 +mappings_version=20200410-1.15.1 diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 3fca61a07..7f0338538 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -76,7 +76,7 @@ public final class ClientRegistry @SubscribeEvent public static void onTextureStitchEvent( TextureStitchEvent.Pre event ) { - if( !event.getMap().getBasePath().equals( PlayerContainer.LOCATION_BLOCKS_TEXTURE ) ) return; + if( !event.getMap().getTextureLocation().equals( PlayerContainer.LOCATION_BLOCKS_TEXTURE ) ) return; for( String extra : EXTRA_TEXTURES ) { diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 93b8e59b9..af95acd67 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -254,7 +254,7 @@ public final class FixedWidthFontRenderer } public static void drawTerminal( - float x, float y, @Nonnull Terminal terminal, boolean greyscale, + @Nonnull Matrix4f transform, float x, float y, @Nonnull Terminal terminal, boolean greyscale, float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize ) { @@ -264,26 +264,39 @@ public final class FixedWidthFontRenderer IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); IVertexBuilder buffer = renderer.getBuffer( TYPE ); - drawTerminal( IDENTITY, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); renderer.finish( TYPE ); } + public static void drawTerminal( + float x, float y, @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + drawTerminal( IDENTITY, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + } + public static void drawEmptyTerminal( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height ) { Colour colour = Colour.BLACK; drawQuad( transform, renderer.getBuffer( TYPE ), x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); } - public static void drawEmptyTerminal( float x, float y, float width, float height ) + public static void drawEmptyTerminal( @Nonnull Matrix4f transform, float x, float y, float width, float height ) { Minecraft.getInstance().getTextureManager().bindTexture( FONT ); RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); - drawEmptyTerminal( IDENTITY, renderer, x, y, width, height ); + drawEmptyTerminal( transform, renderer, x, y, width, height ); renderer.finish(); } + public static void drawEmptyTerminal( float x, float y, float width, float height ) + { + drawEmptyTerminal( IDENTITY, x, y, width, height ); + } + public static void drawBlocker( @Nonnull Matrix4f transform, @Nonnull IRenderTypeBuffer renderer, float x, float y, float width, float height ) { Colour colour = Colour.BLACK; @@ -296,10 +309,10 @@ public final class FixedWidthFontRenderer private static final VertexFormat FORMAT = DefaultVertexFormats.POSITION_COLOR_TEX; - static final RenderType MAIN = RenderType.get( + static final RenderType MAIN = RenderType.makeType( "terminal_font", FORMAT, GL_MODE, 1024, false, false, // useDelegate, needsSorting - RenderType.State.builder() + RenderType.State.getBuilder() .texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap .alpha( DEFAULT_ALPHA ) .lightmap( LIGHTMAP_DISABLED ) @@ -307,10 +320,10 @@ public final class FixedWidthFontRenderer .build( false ) ); - static final RenderType BLOCKER = RenderType.get( + static final RenderType BLOCKER = RenderType.makeType( "terminal_blocker", FORMAT, GL_MODE, 256, false, false, // useDelegate, needsSorting - RenderType.State.builder() + RenderType.State.getBuilder() .texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap .alpha( DEFAULT_ALPHA ) .writeMask( DEPTH_WRITE ) diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index efdbd2e3e..086ebff27 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -38,12 +38,12 @@ public final class ComputerCraftProxyClient registerContainers(); // While turtles themselves are not transparent, their upgrades may be. - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleNormal, RenderType.translucent() ); - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleAdvanced, RenderType.translucent() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleNormal, RenderType.getTranslucent() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleAdvanced, RenderType.getTranslucent() ); // Monitors' textures have transparent fronts and so count as cutouts. - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.cutout() ); - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.cutout() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.getCutout() ); + RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.getCutout() ); // Setup TESRs ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_NORMAL, TileEntityMonitorRenderer::new ); diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index a780d5bdc..42b6c90c3 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -67,8 +67,8 @@ public final class CableHighlightRenderer double yOffset = pos.getY() - cameraPos.getY(); double zOffset = pos.getZ() - cameraPos.getZ(); - IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.lines() ); - Matrix4f matrix4f = event.getMatrix().getLast().getPositionMatrix(); + IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.getLines() ); + Matrix4f matrix4f = event.getMatrix().getLast().getMatrix(); shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> { buffer.pos( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) ) .color( 0, 0, 0, 0.4f ).endVertex(); diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java new file mode 100644 index 000000000..9e87d4e35 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -0,0 +1,193 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.render; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.core.ClientComputer; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.pocket.items.ItemPocketComputer; +import dan200.computercraft.shared.util.Colour; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.RenderHandEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import org.lwjgl.opengl.GL11; + +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; +import static dan200.computercraft.client.gui.GuiComputer.*; + +/** + * Emulates map rendering for pocket computers. + */ +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) +public final class ItemPocketRenderer extends ItemMapLikeRenderer +{ + private static final int MARGIN = 2; + private static final int FRAME = 12; + private static final int LIGHT_HEIGHT = 8; + + private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer(); + + private ItemPocketRenderer() + { + } + + @SubscribeEvent + public static void onRenderInHand( RenderHandEvent event ) + { + ItemStack stack = event.getItemStack(); + if( !(stack.getItem() instanceof ItemPocketComputer) ) return; + + event.setCanceled( true ); + INSTANCE.renderItemFirstPerson( + event.getMatrixStack(), event.getBuffers(), event.getLight(), + event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() + ); + } + + @Override + protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ) + { + ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); + Terminal terminal = computer == null ? null : computer.getTerminal(); + + int termWidth, termHeight; + if( terminal == null ) + { + termWidth = ComputerCraft.terminalWidth_pocketComputer; + termHeight = ComputerCraft.terminalHeight_pocketComputer; + } + else + { + termWidth = terminal.getWidth(); + termHeight = terminal.getHeight(); + } + + int width = termWidth * FONT_WIDTH + MARGIN * 2; + int height = termHeight * FONT_HEIGHT + MARGIN * 2; + + // Setup various transformations. Note that these are partially adapted from the corresponding method + // in ItemRenderer + transform.push(); + transform.rotate( Vector3f.YP.rotationDegrees( 180f ) ); + transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) ); + transform.scale( 0.5f, 0.5f, 0.5f ); + + float scale = 0.75f / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT ); + transform.scale( scale, scale, 0 ); + transform.translate( -0.5 * width, -0.5 * height, 0 ); + + // Render the main frame + ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); + ComputerFamily family = item.getFamily(); + int frameColour = item.getColour( stack ); + + Matrix4f matrix = transform.getLast().getMatrix(); + renderFrame( matrix, family, frameColour, width, height ); + + // Render the light + int lightColour = ItemPocketComputer.getLightState( stack ); + if( lightColour == -1 ) lightColour = Colour.BLACK.getHex(); + renderLight( matrix, lightColour, width, height ); + + if( computer != null && terminal != null ) + { + FixedWidthFontRenderer.drawTerminal( matrix, MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); + } + else + { + FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height ); + } + + transform.pop(); + } + + private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height ) + { + Minecraft.getInstance().getTextureManager().bindTexture( colour != -1 + ? BACKGROUND_COLOUR + : family == ComputerFamily.NORMAL ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED + ); + + float r = ((colour >>> 16) & 0xFF) / 255.0f; + float g = ((colour >>> 8) & 0xFF) / 255.0f; + float b = (colour & 0xFF) / 255.0f; + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX ); + + // Top left, middle, right + renderTexture( transform, buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b ); + renderTexture( transform, buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b ); + renderTexture( transform, buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b ); + + // Left and bright border + renderTexture( transform, buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b ); + renderTexture( transform, buffer, width, 0, 36, 28, FRAME, height, r, g, b ); + + // Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for + // lights, and then the bottom outer corners. + renderTexture( transform, buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b ); + renderTexture( transform, buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b ); + renderTexture( transform, buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b ); + + renderTexture( transform, buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); + renderTexture( transform, buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b ); + renderTexture( transform, buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); + + renderTexture( transform, buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); + renderTexture( transform, buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b ); + renderTexture( transform, buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); + + tessellator.draw(); + } + + private static void renderLight( Matrix4f transform, int colour, int width, int height ) + { + RenderSystem.enableBlend(); + RenderSystem.disableTexture(); + + float r = ((colour >>> 16) & 0xFF) / 255.0f; + float g = ((colour >>> 8) & 0xFF) / 255.0f; + float b = (colour & 0xFF) / 255.0f; + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); + buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width, height + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + + tessellator.draw(); + RenderSystem.enableTexture(); + } + + private static void renderTexture( Matrix4f transform, IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) + { + renderTexture( transform, builder, x, y, textureX, textureY, width, height, width, height, r, g, b ); + } + + private static void renderTexture( Matrix4f transform, IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b ) + { + float scale = 1 / 255.0f; + builder.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( textureX * scale, (textureY + textureHeight) * scale ).endVertex(); + builder.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).endVertex(); + builder.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( (textureX + textureWidth) * scale, textureY * scale ).endVertex(); + builder.pos( transform, x, y, 0 ).color( r, g, b, 1.0f ).tex( textureX * scale, textureY * scale ).endVertex(); + } +} diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index 65c2c8e99..5fa6ada5d 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -36,7 +36,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer { } - // TODO: @SubscribeEvent + @SubscribeEvent public static void onRenderInHand( RenderHandEvent event ) { ItemStack stack = event.getItemStack(); @@ -53,7 +53,6 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ) { transform.rotate( Vector3f.XP.rotationDegrees( 180f ) ); - transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) ); transform.scale( 0.42f, 0.42f, -0.42f ); transform.translate( -0.5f, -0.48f, 0.0f ); @@ -105,7 +104,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer transform.scale( scale, scale, scale ); transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 ); - Matrix4f matrix = transform.getLast().getPositionMatrix(); + Matrix4f matrix = transform.getLast().getMatrix(); drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book ); drawText( matrix, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack ) diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 7a5d7d0fd..54e8c80b9 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -66,8 +66,8 @@ public final class MonitorHighlightRenderer transformStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); // I wish I could think of a better way to do this - IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.lines() ); - Matrix4f transform = transformStack.getLast().getPositionMatrix(); + IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.getLines() ); + Matrix4f transform = transformStack.getLast().getMatrix(); if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 0, UP ); if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 1, UP ); if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, transform, 1, 0, 0, UP ); diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index bbe95c9c0..53f1c358e 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -167,10 +167,10 @@ public final class PrintoutRenderer private static final class Type extends RenderState { - static final RenderType TYPE = RenderType.get( + static final RenderType TYPE = RenderType.makeType( "printout_background", DefaultVertexFormats.POSITION_TEX, GL11.GL_QUADS, 1024, false, false, // useDelegate, needsSorting - RenderType.State.builder() + RenderType.State.getBuilder() .texture( new RenderState.TextureState( BG, false, false ) ) // blur, minimap .alpha( DEFAULT_ALPHA ) .lightmap( LIGHTMAP_DISABLED ) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 4562bf199..ed4827e52 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -106,13 +106,13 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer float xMargin = (float) (MARGIN / xScale); float yMargin = (float) (MARGIN / yScale); - Matrix4f matrix = transform.getLast().getPositionMatrix(); + Matrix4f matrix = transform.getLast().getMatrix(); if( redraw ) { Tessellator tessellator = Tessellator.getInstance(); BufferBuilder builder = tessellator.getBuffer(); - builder.begin( FixedWidthFontRenderer.TYPE.getGlMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() ); + builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() ); FixedWidthFontRenderer.drawTerminalWithoutCursor( IDENTITY, builder, 0, 0, terminal, !originTerminal.isColour(), yMargin, yMargin, xMargin, xMargin @@ -126,11 +126,11 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer // render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick // for now. IVertexBuilder buffer = renderer.getBuffer( FixedWidthFontRenderer.TYPE ); - FixedWidthFontRenderer.TYPE.enable(); + FixedWidthFontRenderer.TYPE.setupRenderState(); vbo.bindBuffer(); FixedWidthFontRenderer.TYPE.getVertexFormat().setupBufferState( 0L ); - vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getGlMode() ); + vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getDrawMode() ); VertexBuffer.unbindBuffer(); FixedWidthFontRenderer.TYPE.getVertexFormat().clearBufferState(); @@ -143,14 +143,14 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer else { FixedWidthFontRenderer.drawEmptyTerminal( - transform.getLast().getPositionMatrix(), renderer, + transform.getLast().getMatrix(), renderer, -MARGIN, MARGIN, (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) ); } FixedWidthFontRenderer.drawBlocker( - transform.getLast().getPositionMatrix(), renderer, + transform.getLast().getMatrix(), renderer, (float) -TileMonitor.RENDER_MARGIN, (float) TileMonitor.RENDER_MARGIN, (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) ); diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index b6eb8d6a8..91162280b 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -87,7 +87,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer transform.rotate( mc.getRenderManager().getCameraOrientation() ); transform.scale( -0.025f, -0.025f, 0.025f ); - Matrix4f matrix = transform.getLast().getPositionMatrix(); + Matrix4f matrix = transform.getLast().getMatrix(); int opacity = (int) (mc.gameSettings.getTextBackgroundOpacity( 0.25f ) * 255) << 24; float width = -font.getStringWidth( label ) / 2.0f; font.renderString( label, width, (float) 0, 0x20ffffff, false, matrix, renderer, true, opacity, lightmapCoord ); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 14d113fbb..f99b61264 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -42,7 +42,7 @@ public class TurtleSmartItemModel implements IBakedModel stack.translate( 0, 0, 1 ); identity = TransformationMatrix.identity(); - flip = new TransformationMatrix( stack.getLast().getPositionMatrix() ); + flip = new TransformationMatrix( stack.getLast().getMatrix() ); } private static class TurtleModelCombination @@ -97,15 +97,14 @@ public class TurtleSmartItemModel implements IBakedModel private final IBakedModel familyModel; private final IBakedModel colourModel; - private HashMap m_cachedModels; - private ItemOverrideList m_overrides; + private final HashMap m_cachedModels = new HashMap<>(); + private final ItemOverrideList m_overrides; public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel ) { this.familyModel = familyModel; this.colourModel = colourModel; - m_cachedModels = new HashMap<>(); m_overrides = new ItemOverrideList() { @Nonnull diff --git a/src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java deleted file mode 100644 index d3134d854..000000000 --- a/src/main/java/dan200/computercraft/client/render_old/ItemPocketRenderer.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.client.render; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.IVertexBuilder; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.client.FrameInfo; -import dan200.computercraft.client.gui.FixedWidthFontRenderer; -import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; -import dan200.computercraft.shared.computer.core.ClientComputer; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.pocket.items.ItemPocketComputer; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RenderSpecificHandEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.lwjgl.opengl.GL11; - -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; -import static dan200.computercraft.client.gui.GuiComputer.*; - -/** - * Emulates map rendering for pocket computers. - */ -@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) -public final class ItemPocketRenderer extends ItemMapLikeRenderer -{ - private static final int MARGIN = 2; - private static final int FRAME = 12; - private static final int LIGHT_HEIGHT = 8; - - private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer(); - - private ItemPocketRenderer() - { - } - - @SubscribeEvent - public static void renderItem( RenderSpecificHandEvent event ) - { - ItemStack stack = event.getItemStack(); - if( !(stack.getItem() instanceof ItemPocketComputer) ) return; - - event.setCanceled( true ); - Minecraft minecraft = Minecraft.getInstance(); - INSTANCE.renderItemFirstPerson( - event.getMatrixStack(), minecraft.func_228019_au_().func_228487_b_(), - minecraft.getRenderManager().func_229085_a_( minecraft.player, event.getPartialTicks() ), - event.getHand(), event.getInterpolatedPitch(), event.getEquipProgress(), event.getSwingProgress(), event.getItemStack() - ); - } - - @Override - protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack ) - { - ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); - Terminal terminal = computer == null ? null : computer.getTerminal(); - - int termWidth, termHeight; - if( terminal == null ) - { - termWidth = ComputerCraft.terminalWidth_pocketComputer; - termHeight = ComputerCraft.terminalHeight_pocketComputer; - } - else - { - termWidth = terminal.getWidth(); - termHeight = terminal.getHeight(); - } - - int width = termWidth * FONT_WIDTH + MARGIN * 2; - int height = termHeight * FONT_HEIGHT + MARGIN * 2; - - // Setup various transformations. Note that these are partially adapted from the corresponding method - // in ItemRenderer - transform.push(); - // TODO: RenderSystem.disableLighting(); - // TODO: RenderSystem.disableDepthTest(); - - RenderSystem.rotatef( 180f, 0f, 1f, 0f ); - RenderSystem.rotatef( 180f, 0f, 0f, 1f ); - transform.scale( 0.5f, 0.5f, 0.5f ); - - float scale = 0.75f / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT ); - transform.scale( scale, scale, 0 ); - transform.translate( -0.5 * width, -0.5 * height, 0 ); - - // Render the main frame - ItemPocketComputer item = (ItemPocketComputer) stack.getItem(); - ComputerFamily family = item.getFamily(); - int frameColour = item.getColour( stack ); - renderFrame( family, frameColour, width, height ); - - // Render the light - int lightColour = ItemPocketComputer.getLightState( stack ); - if( lightColour == -1 ) lightColour = Colour.Black.getHex(); - renderLight( lightColour, width, height ); - - if( computer != null && terminal != null ) - { - // If we've a computer and terminal then attempt to render it. - renderTerminal( terminal, !computer.isColour() ); - } - else - { - // Otherwise render a plain background - Minecraft.getInstance().getTextureManager().bindTexture( BACKGROUND ); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - Colour black = Colour.Black; - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION ); - renderTexture( buffer, 0, 0, 0, 0, width, height, black.getR(), black.getG(), black.getB() ); - tessellator.draw(); - } - - // TODO: RenderSystem.enableDepthTest(); - // TODO: RenderSystem.enableLighting(); - transform.pop(); - } - - private static void renderFrame( ComputerFamily family, int colour, int width, int height ) - { - - Minecraft.getInstance().getTextureManager().bindTexture( colour != -1 - ? BACKGROUND_COLOUR - : family == ComputerFamily.Normal ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED - ); - - float r = ((colour >>> 16) & 0xFF) / 255.0f; - float g = ((colour >>> 8) & 0xFF) / 255.0f; - float b = (colour & 0xFF) / 255.0f; - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR ); - - // Top left, middle, right - renderTexture( buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b ); - renderTexture( buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b ); - renderTexture( buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b ); - - // Left and bright border - renderTexture( buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b ); - renderTexture( buffer, width, 0, 36, 28, FRAME, height, r, g, b ); - - // Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for - // lights, and then the bottom outer corners. - renderTexture( buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b ); - renderTexture( buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b ); - renderTexture( buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b ); - - renderTexture( buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); - renderTexture( buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b ); - renderTexture( buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); - - renderTexture( buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); - renderTexture( buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b ); - renderTexture( buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); - - tessellator.draw(); - } - - private static void renderLight( int colour, int width, int height ) - { - RenderSystem.enableBlend(); - RenderSystem.disableTexture(); - - float r = ((colour >>> 16) & 0xFF) / 255.0f; - float g = ((colour >>> 8) & 0xFF) / 255.0f; - float b = (colour & 0xFF) / 255.0f; - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); - buffer.pos( width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); - buffer.pos( width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); - buffer.pos( width, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); - buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex(); - - tessellator.draw(); - RenderSystem.enableTexture(); - } - - private static void renderTerminal( Terminal terminal, boolean greyscale ) - { - synchronized( terminal ) - { - int termWidth = terminal.getWidth(); - int termHeight = terminal.getHeight(); - - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - Palette palette = terminal.getPalette(); - - // Render top/bottom borders - TextBuffer emptyLine = new TextBuffer( ' ', termWidth ); - fontRenderer.drawString( - emptyLine, MARGIN, 0, - terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), MARGIN, MARGIN, greyscale, palette - ); - fontRenderer.drawString( - emptyLine, MARGIN, 2 * MARGIN + (termHeight - 1) * FixedWidthFontRenderer.FONT_HEIGHT, - terminal.getTextColourLine( termHeight - 1 ), terminal.getBackgroundColourLine( termHeight - 1 ), MARGIN, MARGIN, greyscale, palette - ); - - // Render the actual text - for( int line = 0; line < termWidth; line++ ) - { - TextBuffer text = terminal.getLine( line ); - TextBuffer colour = terminal.getTextColourLine( line ); - TextBuffer backgroundColour = terminal.getBackgroundColourLine( line ); - fontRenderer.drawString( - text, MARGIN, MARGIN + line * FONT_HEIGHT, - colour, backgroundColour, MARGIN, MARGIN, greyscale, palette - ); - } - - // And render the cursor; - int tx = terminal.getCursorX(), ty = terminal.getCursorY(); - if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() && - tx >= 0 && ty >= 0 && tx < termWidth && ty < termHeight ) - { - TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); - fontRenderer.drawString( - new TextBuffer( '_', 1 ), MARGIN + FONT_WIDTH * tx, MARGIN + FONT_HEIGHT * ty, - cursorColour, null, 0, 0, greyscale, palette - ); - } - } - } - - private static void renderTexture( IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) - { - renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b ); - } - - private static void renderTexture( IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b ) - { - float scale = 1 / 255.0f; - builder.pos( x, y + height, 0 ).tex( textureX * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex(); - builder.pos( x + width, y + height, 0 ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex(); - builder.pos( x + width, y, 0 ).tex( (textureX + textureWidth) * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex(); - builder.pos( x, y, 0 ).tex( textureX * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex(); - } -} diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index f570adaec..156378cdd 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -7,7 +7,10 @@ package dan200.computercraft.shared.util; import com.google.common.collect.Maps; import com.google.common.collect.Sets; -import com.google.gson.*; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.JSONUtils; From 2360a6e951837173ae81cc71899468271b950bd1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 10 Apr 2020 21:26:11 +0100 Subject: [PATCH 165/711] Remove several deprecated methods --- .../core/apis/ArgumentHelper.java | 117 ------------------ .../computercraft/core/apis/ILuaAPI.java | 24 ---- .../core/filesystem/EmptyMount.java | 1 - .../computercraft/core/terminal/Terminal.java | 13 -- 4 files changed, 155 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java delete mode 100644 src/main/java/dan200/computercraft/core/apis/ILuaAPI.java diff --git a/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java b/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java deleted file mode 100644 index f4f9d0033..000000000 --- a/src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.core.apis; - -import dan200.computercraft.api.lua.LuaException; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Map; - -/** - * A stub for any mods which depended on this version of the argument helper. - * - * @deprecated Use {@link dan200.computercraft.api.lua.ArgumentHelper}. - */ -@Deprecated -public final class ArgumentHelper -{ - private ArgumentHelper() - { - } - - @Nonnull - public static String getType( @Nullable Object type ) - { - return dan200.computercraft.api.lua.ArgumentHelper.getType( type ); - } - - @Nonnull - public static LuaException badArgument( int index, @Nonnull String expected, @Nullable Object actual ) - { - return dan200.computercraft.api.lua.ArgumentHelper.badArgumentOf( index, expected, actual ); - } - - @Nonnull - public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual ) - { - return dan200.computercraft.api.lua.ArgumentHelper.badArgument( index, expected, actual ); - } - - public static double getNumber( @Nonnull Object[] args, int index ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.getDouble( args, index ); - } - - public static int getInt( @Nonnull Object[] args, int index ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.getInt( args, index ); - } - - public static long getLong( @Nonnull Object[] args, int index ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.getLong( args, index ); - } - - public static double getReal( @Nonnull Object[] args, int index ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.getFiniteDouble( args, index ); - } - - public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.getBoolean( args, index ); - } - - @Nonnull - public static String getString( @Nonnull Object[] args, int index ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.getString( args, index ); - } - - @Nonnull - @SuppressWarnings( "unchecked" ) - public static Map getTable( @Nonnull Object[] args, int index ) throws LuaException - { - return (Map) dan200.computercraft.api.lua.ArgumentHelper.getTable( args, index ); - } - - public static double optNumber( @Nonnull Object[] args, int index, double def ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.optDouble( args, index, def ); - } - - public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.optInt( args, index, def ); - } - - public static long optLong( @Nonnull Object[] args, int index, long def ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.optLong( args, index, def ); - } - - public static double optReal( @Nonnull Object[] args, int index, double def ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.optFiniteDouble( args, index, def ); - } - - public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.optBoolean( args, index, def ); - } - - public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException - { - return dan200.computercraft.api.lua.ArgumentHelper.optString( args, index, def ); - } - - @SuppressWarnings( "unchecked" ) - public static Map optTable( @Nonnull Object[] args, int index, Map def ) throws LuaException - { - return (Map) dan200.computercraft.api.lua.ArgumentHelper.optTable( args, index, def ); - } -} diff --git a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java b/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java deleted file mode 100644 index e623feb82..000000000 --- a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.core.apis; - -/** - * This exists purely to ensure binary compatibility. - * - * @see dan200.computercraft.api.lua.ILuaAPI - * @deprecated Use the version in the public API. Only exists for compatibility with CCEmuX. - */ -@Deprecated -public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI -{ - void advance( double v ); - - @Override - default void update() - { - advance( 0.05 ); - } -} diff --git a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java index 3fd2dd3b9..c3ba89855 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java @@ -40,7 +40,6 @@ public class EmptyMount implements IMount @Nonnull @Override - @Deprecated public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { throw new FileOperationException( path, "No such file" ); diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index f58af1a1c..54503a02f 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -312,19 +312,6 @@ public class Terminal return null; } - /** - * Determine whether this terminal has changed. - * - * @return If this terminal is dirty. - * @deprecated All {@code *Changed()} methods are deprecated: one should pass in a callback - * instead. - */ - @Deprecated - public final boolean getChanged() - { - return m_changed; - } - public final void setChanged() { m_changed = true; From 6a6a87489c4cb530772e3dc64bf1d8723fcb8f53 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Apr 2020 10:54:57 +0100 Subject: [PATCH 166/711] Add a separate CONTRIBUTING.md file Hopefully provides a /little/ more information about the build process. Hey, also means I only need to add a CoC to complete GH's community tab! In all seriousness, there's probably a lot more I need to flesh out here, such as some kind of vision and guides for issues/PRs. But this at least documents the local development process. Somewhat. --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++++ README.md | 16 +++++----------- 2 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..6d3b46feb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing to CC: Tweaked +As with many open source projects, CC: Tweaked thrives on contributions from other people! This document (hopefully) +provides an introduction as to how to get started in helping out. + +If you've any other questions, [just ask the community][community] or [open an issue][new-issue]. + +## Reporting issues +If you have a bug, suggestion, or other feedback, the best thing to do is [file an issue][new-issue]. When doing so, +do use the issue templates - they provide a useful hint on what information to provide. + +## Developing +In order to develop CC: Tweaked, you'll need to download the source code and then run it. This is a pretty simple +process. + + - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` + - **Setup Forge:** `./gradlew setupDecompWorkspace` + - **Run Minecraft:** `./gradlew runClient` (or run the `GradleStart` class from your IDE). + +If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`. +These commands may take a few minutes to run the first time, as the environment is set up, but should be much faster +afterwards. + +### Code linters +CC: Tweaked uses a couple of "linters" on its source code, to enforce a consistent style across the project. While these +are run whenever you submit a PR, it's often useful to + + - **[Checkstyle]:** Checks Java code to ensure it is consistently formatted. This can be run with `./gradlew build` or + `./gradle check`. + - **[illuaminate]:** Checks Lua code for semantic and styleistic issues. See [the usage section][illuaminate-usage] for + how to download and run it. + +[new-issue]: https://github.com/SquidDev-CC/CC-Tweaked/issues/new/choose "Create a new issue" +[community]: README.md#Community "Get in touch with the community." +[checkstyle]: https://checkstyle.org/ +[illuaminate]: https://github.com/SquidDev/illuaminate/ +[illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage diff --git a/README.md b/README.md index fd3003786..78a9cb32e 100644 --- a/README.md +++ b/README.md @@ -37,20 +37,14 @@ several features have been included, such as full block modems, the Cobalt runti computers. ## Contributing -Any contribution is welcome, be that using the mod, reporting bugs or contributing code. In order to start helping -develop CC:T, you'll need to follow these steps: - - - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` - - **Setup Forge:** `./gradlew setupDecompWorkspace` - - **Test your changes:** `./gradlew runClient` (or run the `GradleStart` class from your IDE). - -If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`. +Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to developing the +mod, [check out the instructions here](CONTRIBUTING.md#developing). ## Community If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about -ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.gg/H2UyJXe)! -There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=#computercraft), if -that's more your cup of tea. +ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.computercraft.cc)! +There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=computercraft), if that's +more your cup of tea. I'd generally recommend you don't contact me directly (email, DM, etc...) unless absolutely necessary (i.e. in order to report exploits). You'll get a far quicker response if you ask the whole community! From ef4b0a563295fc555ef5af73d651109a1daa396a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 13 Apr 2020 11:00:31 +0100 Subject: [PATCH 167/711] Fix config name for enabling http API It hasn't been http_enable for yonks - slightly worried I didn't notice this earlier. Also don't refer to ComputerCraft.cfg - the name has changed several times across versions, so let's leave it ambiguous. --- src/main/java/dan200/computercraft/shared/Config.java | 2 +- .../assets/computercraft/lua/rom/programs/http/pastebin.lua | 4 ++-- .../assets/computercraft/lua/rom/programs/http/wget.lua | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index a58cd1962..65819e69e 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -175,7 +175,7 @@ public final class Config "for more fine grained control than this)" ); httpWebsocketEnable = config.get( CATEGORY_HTTP, "websocket_enabled", ComputerCraft.http_websocket_enable ); - httpWebsocketEnable.setComment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ); + httpWebsocketEnable.setComment( "Enable use of http websockets. This requires the \"http.enabled\" option to also be true." ); httpAllowedDomains = config.get( CATEGORY_HTTP, "allowed_domains", DEFAULT_HTTP_WHITELIST ); httpAllowedDomains.setComment( "A list of wildcards for domains or IP ranges that can be accessed through the " + diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua index 3e28a2f7a..49266c20e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua @@ -13,8 +13,8 @@ if #tArgs < 2 then end if not http then - printError( "Pastebin requires http API" ) - printError( "Set http_enable to true in ComputerCraft.cfg" ) + printError( "Pastebin requires the http API" ) + printError( "Set http.enabled to true in CC: Tweaked's config" ) return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua index e05def30e..6c5894e77 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua @@ -21,8 +21,8 @@ end local url = table.remove( tArgs, 1 ) if not http then - printError( "wget requires http API" ) - printError( "Set http_enable to true in ComputerCraft.cfg" ) + printError( "wget requires the http API" ) + printError( "Set http.enabled to true in CC: Tweaked's config" ) return end From cb8135a0d1f3228a6df943254384c51ca0e551fc Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 16 Apr 2020 10:48:26 +0100 Subject: [PATCH 168/711] Bump Cobalt version - Remove stub for table.pack/table.unpack. - Remove Lua 5.3 bitlib stub. We're not on 5.3, there's no point emulating it. - Change peripheral.call to correctly adjust the error level. This is a terrible hack, but I believe the only good option. It'd be good to remove load as well, but it's a little more complex due to our injecting of _ENV. Closes #363 --- CONTRIBUTING.md | 2 +- build.gradle | 2 +- .../core/apis/FastLuaException.java | 35 ++++++++++ .../core/apis/PeripheralAPI.java | 30 +++++---- .../core/lua/CobaltLuaMachine.java | 1 + .../assets/computercraft/lua/bios.lua | 66 ------------------- .../core/ComputerTestDelegate.java | 36 ++++++++++ src/test/resources/test-rom/mcfly.lua | 20 +++++- .../test-rom/spec/apis/peripheral_spec.lua | 7 ++ .../spec/programs/peripherals_spec.lua | 1 + 10 files changed, 119 insertions(+), 81 deletions(-) create mode 100644 src/main/java/dan200/computercraft/core/apis/FastLuaException.java diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6d3b46feb..a5273632b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ afterwards. ### Code linters CC: Tweaked uses a couple of "linters" on its source code, to enforce a consistent style across the project. While these -are run whenever you submit a PR, it's often useful to +are run whenever you submit a PR, it's often useful to run this before committing. - **[Checkstyle]:** Checks Java code to ensure it is consistently formatted. This can be run with `./gradlew build` or `./gradle check`. diff --git a/build.gradle b/build.gradle index f2fa11e96..df2375cc5 100644 --- a/build.gradle +++ b/build.gradle @@ -77,7 +77,7 @@ dependencies { runtime "mezz.jei:jei_1.12.2:4.15.0.269" - shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT' + shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' diff --git a/src/main/java/dan200/computercraft/core/apis/FastLuaException.java b/src/main/java/dan200/computercraft/core/apis/FastLuaException.java new file mode 100644 index 000000000..6ef64f275 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/FastLuaException.java @@ -0,0 +1,35 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis; + +import dan200.computercraft.api.lua.LuaException; + +import javax.annotation.Nullable; + +/** + * A Lua exception which does not contain its stack trace. + */ +public class FastLuaException extends LuaException +{ + private static final long serialVersionUID = 5957864899303561143L; + + public FastLuaException( @Nullable String message ) + { + super( message ); + } + + public FastLuaException( @Nullable String message, int level ) + { + super( message, level ); + } + + @Override + public synchronized Throwable fillInStackTrace() + { + return this; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index c289c85a2..43dc63077 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -383,22 +383,30 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange String methodName = getString( args, 1 ); Object[] methodArgs = Arrays.copyOfRange( args, 2, args.length ); - if( side != null ) + if( side == null ) throw new LuaException( "No peripheral attached" ); + + PeripheralWrapper p; + synchronized( m_peripherals ) { - PeripheralWrapper p; - synchronized( m_peripherals ) - { - p = m_peripherals[side.ordinal()]; - } - if( p != null ) - { - return p.call( context, methodName, methodArgs ); - } + p = m_peripherals[side.ordinal()]; + } + if( p == null ) throw new LuaException( "No peripheral attached" ); + + try + { + return p.call( context, methodName, methodArgs ); + } + catch( LuaException e ) + { + // We increase the error level by one in order to shift the error level to where peripheral.call was + // invoked. It would be possible to do it in Lua code, but would add significantly more overhead. + if( e.getLevel() > 0 ) throw new FastLuaException( e.getMessage(), e.getLevel() + 1 ); + throw e; } - throw new LuaException( "No peripheral attached" ); } default: return null; } } + } diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 08c3231f0..8e5e88bb0 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -92,6 +92,7 @@ public class CobaltLuaMachine implements ILuaMachine m_globals.load( state, new MathLib() ); m_globals.load( state, new CoroutineLib() ); m_globals.load( state, new Bit32Lib() ); + m_globals.load( state, new Utf8Lib() ); if( ComputerCraft.debug_enable ) m_globals.load( state, new DebugLib() ); // Remove globals we don't want to expose diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 377255845..faffa2cea 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -70,8 +70,6 @@ if _VERSION == "Lua 5.1" then error( p1, 2 ) end end - table.unpack = unpack - table.pack = function( ... ) return { n = select( "#", ... ), ... } end if _CC_DISABLE_LUA51_FEATURES then -- Remove the Lua 5.1 features that will be removed when we update to Lua 5.2, for compatibility testing. @@ -98,70 +96,6 @@ if _VERSION == "Lua 5.1" then end end -if _VERSION == "Lua 5.3" and not bit32 then - -- If we're on Lua 5.3, install the bit32 api from Lua 5.2 - -- (Loaded from a string so this file will still parse on <5.3 lua) - load( [[ - bit32 = {} - - function bit32.arshift( n, bits ) - if type(n) ~= "number" or type(bits) ~= "number" then - error( "Expected number, number", 2 ) - end - return n >> bits - end - - function bit32.band( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return m & n - end - - function bit32.bnot( n ) - if type(n) ~= "number" then - error( "Expected number", 2 ) - end - return ~n - end - - function bit32.bor( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return m | n - end - - function bit32.btest( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return (m & n) ~= 0 - end - - function bit32.bxor( m, n ) - if type(m) ~= "number" or type(n) ~= "number" then - error( "Expected number, number", 2 ) - end - return m ~ n - end - - function bit32.lshift( n, bits ) - if type(n) ~= "number" or type(bits) ~= "number" then - error( "Expected number, number", 2 ) - end - return n << bits - end - - function bit32.rshift( n, bits ) - if type(n) ~= "number" or type(bits) ~= "number" then - error( "Expected number, number", 2 ) - end - return n >> bits - end - ]] )() -end - -- Install lua parts of the os api function os.version() return "CraftOS 1.8" diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 6413d5ef0..fec45a318 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -10,12 +10,18 @@ import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.BasicEnvironment; import dan200.computercraft.core.computer.Computer; +import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.filesystem.FileMount; import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.jupiter.api.*; @@ -94,6 +100,7 @@ public class ComputerTestDelegate } computer = new Computer( new BasicEnvironment( mount ), term, 0 ); + computer.getEnvironment().setPeripheral( ComputerSide.TOP, new FakeModem() ); computer.addApi( new ILuaAPI() { @Override @@ -417,4 +424,33 @@ public class ComputerTestDelegate { return name.replace( "\0", " -> " ); } + + private static class FakeModem extends WirelessModemPeripheral + { + FakeModem() + { + super( new ModemState(), true ); + } + + @Nonnull + @Override + @SuppressWarnings( "ConstantConditions" ) + public World getWorld() + { + return null; + } + + @Nonnull + @Override + public Vec3d getPosition() + { + return Vec3d.ZERO; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } } diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 2fe853b95..ecb01eaac 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -224,7 +224,7 @@ expect_mt.ne = expect_mt.not_equals function expect_mt:type(exp_type) local actual_type = type(self.value) if exp_type ~= actual_type then - fail(("Expected value of type %s\n got %s"):format(exp_type, actual_type)) + fail(("Expected value of type %s\nbut got %s"):format(exp_type, actual_type)) end return self @@ -273,7 +273,7 @@ end -- @throws If they are not equivalent function expect_mt:same(value) if not matches({}, true, self.value, value) then - fail(("Expected %s\n but got %s"):format(format(value), format(self.value))) + fail(("Expected %s\nbut got %s"):format(format(value), format(self.value))) end return self @@ -356,6 +356,22 @@ function expect_mt:called_with_matching(...) return called_with_check(matches, self, ...) end +--- Assert that this expectation matches a Lua pattern +-- +-- @tparam string pattern The pattern to match against +-- @throws If it does not match this pattern. +function expect_mt:str_match(pattern) + local actual_type = type(self.value) + if actual_type ~= "string" then + fail(("Expected value of type string\nbut got %s"):format(actual_type)) + end + if not self.value:find(pattern) then + fail(("Expected %q\n to match pattern %q"):format(self.value, pattern)) + end + + return self +end + local expect = {} setmetatable(expect, expect) diff --git a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua index 8fca583e1..c3fb5675f 100644 --- a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -1,4 +1,6 @@ describe("The peripheral library", function() + local it_modem = peripheral.getType("top") == "modem" and it or pending + describe("peripheral.isPresent", function() it("validates arguments", function() peripheral.isPresent("") @@ -26,6 +28,11 @@ describe("The peripheral library", function() expect.error(peripheral.call, nil):eq("bad argument #1 (expected string, got nil)") expect.error(peripheral.call, "", nil):eq("bad argument #2 (expected string, got nil)") end) + + it_modem("has the correct error location", function() + expect.error(function() peripheral.call("top", "isOpen", false) end) + :str_match("^peripheral_spec.lua:%d+: bad argument #1 %(number expected, got boolean%)$") + end) end) describe("peripheral.wrap", function() diff --git a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua index 6c9d433bd..68762e79f 100644 --- a/src/test/resources/test-rom/spec/programs/peripherals_spec.lua +++ b/src/test/resources/test-rom/spec/programs/peripherals_spec.lua @@ -2,6 +2,7 @@ local capture = require "test_helpers".capture_program describe("The peripherals program", function() it("says when there are no peripherals", function() + stub(peripheral, 'getNames', function() return {} end) expect(capture(stub, "peripherals")) :matches { ok = true, output = "Attached Peripherals:\nNone\n", error = "" } end) From f9f94b83046f531e6d87dc695cb021a95c462b3e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 16 Apr 2020 18:18:36 +0100 Subject: [PATCH 169/711] Rewrite our documentation index We're going to flesh this out a lot in the future, but this'll have to do for now. --- .gitignore | 1 + doc/index.md | 18 ++++++++---------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index cc7ddcea3..51cff3b7a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /build /out /doc/**/*.html +/doc/index.json # Runtime directories /run diff --git a/doc/index.md b/doc/index.md index efc2afafa..c22acd230 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,13 +1,11 @@ -# CC: Tweaked +# ![CC: Tweaked](logo.png) [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") -This is a small website to test documentation generation from Lua source code. +CC: Tweaked is a fork of [ComputerCraft], adding programmable computers, turtles and more to Minecraft. -This is still very much in the proof-of-concept stage. We've rolled own own documentation -generation tool, and there's a couple of missing features. Furthermore, Java-based APIs -(such as Lua builtins, or @{os}) are not documented. +This website contains documentation for all Lua libraries and APIs from the latest version of CC: Tweaked. This +documentation is still in development, so will most likely be incomplete. If you've found something you think is wrong, +or would like to help out [please get in touch on GitHub][gh]. -For more information, please check out [the GitHub issue][gh_issue] and [the -documented source][gh_branch]. - -[gh_issue]: https://github.com/SquidDev-CC/CC-Tweaked/issues/133 -[gh_branch]: https://github.com/SquidDev-CC/CC-Tweaked/tree/feature/doc-gen +[bug]: https://github.com/SquidDev-CC/CC-Tweaked/issues/new/choose +[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub" +[gh]: https://github.com/SquidDev-CC/CC-Tweaked "CC:Tweaked on GitHub" From 865fc239a0af201a99cff92df995a25cc6b727ef Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Apr 2020 10:09:40 +0100 Subject: [PATCH 170/711] Reformat bracketed expressions in Lua - Parenthesised expressions (function calls, arguments, etc...) should never have spaces in them. - Tables always will have spaces inside. --- illuaminate.sexp | 11 +- .../assets/computercraft/lua/bios.lua | 384 +++++++------- .../computercraft/lua/rom/apis/colors.lua | 28 +- .../lua/rom/apis/command/commands.lua | 30 +- .../computercraft/lua/rom/apis/disk.lua | 78 +-- .../assets/computercraft/lua/rom/apis/gps.lua | 66 +-- .../computercraft/lua/rom/apis/help.lua | 36 +- .../computercraft/lua/rom/apis/keys.lua | 6 +- .../computercraft/lua/rom/apis/paintutils.lua | 84 ++-- .../computercraft/lua/rom/apis/parallel.lua | 30 +- .../computercraft/lua/rom/apis/rednet.lua | 126 ++--- .../computercraft/lua/rom/apis/settings.lua | 34 +- .../computercraft/lua/rom/apis/term.lua | 24 +- .../computercraft/lua/rom/apis/textutils.lua | 226 ++++----- .../lua/rom/apis/turtle/turtle.lua | 26 +- .../computercraft/lua/rom/apis/vector.lua | 4 +- .../computercraft/lua/rom/apis/window.lua | 188 +++---- .../lua/rom/modules/main/cc/expect.lua | 4 +- .../lua/rom/modules/main/cc/pretty.lua | 10 +- .../lua/rom/programs/advanced/bg.lua | 6 +- .../lua/rom/programs/advanced/fg.lua | 10 +- .../lua/rom/programs/advanced/multishell.lua | 162 +++--- .../computercraft/lua/rom/programs/alias.lua | 14 +- .../computercraft/lua/rom/programs/apis.lua | 14 +- .../computercraft/lua/rom/programs/cd.lua | 10 +- .../computercraft/lua/rom/programs/clear.lua | 2 +- .../lua/rom/programs/command/commands.lua | 12 +- .../lua/rom/programs/command/exec.lua | 24 +- .../computercraft/lua/rom/programs/copy.lua | 32 +- .../computercraft/lua/rom/programs/drive.lua | 16 +- .../computercraft/lua/rom/programs/edit.lua | 296 +++++------ .../computercraft/lua/rom/programs/eject.lua | 8 +- .../lua/rom/programs/fun/advanced/paint.lua | 68 +-- .../rom/programs/fun/advanced/redirection.lua | 96 ++-- .../lua/rom/programs/fun/adventure.lua | 474 +++++++++--------- .../computercraft/lua/rom/programs/fun/dj.lua | 26 +- .../lua/rom/programs/fun/hello.lua | 6 +- .../lua/rom/programs/fun/worm.lua | 86 ++-- .../computercraft/lua/rom/programs/gps.lua | 36 +- .../computercraft/lua/rom/programs/help.lua | 12 +- .../lua/rom/programs/http/pastebin.lua | 72 +-- .../lua/rom/programs/http/wget.lua | 50 +- .../computercraft/lua/rom/programs/id.lua | 16 +- .../computercraft/lua/rom/programs/label.lua | 68 +-- .../computercraft/lua/rom/programs/list.lua | 30 +- .../computercraft/lua/rom/programs/lua.lua | 44 +- .../computercraft/lua/rom/programs/mkdir.lua | 16 +- .../lua/rom/programs/monitor.lua | 56 +-- .../computercraft/lua/rom/programs/motd.lua | 2 +- .../computercraft/lua/rom/programs/move.lua | 20 +- .../lua/rom/programs/peripherals.lua | 6 +- .../lua/rom/programs/pocket/equip.lua | 6 +- .../lua/rom/programs/pocket/falling.lua | 10 +- .../lua/rom/programs/pocket/unequip.lua | 6 +- .../lua/rom/programs/programs.lua | 4 +- .../computercraft/lua/rom/programs/reboot.lua | 8 +- .../lua/rom/programs/rednet/chat.lua | 254 +++++----- .../lua/rom/programs/rednet/repeat.lua | 56 +-- .../lua/rom/programs/redstone.lua | 76 +-- .../computercraft/lua/rom/programs/rename.lua | 20 +- .../computercraft/lua/rom/programs/set.lua | 16 +- .../computercraft/lua/rom/programs/shell.lua | 254 +++++----- .../lua/rom/programs/shutdown.lua | 8 +- .../computercraft/lua/rom/programs/time.lua | 2 +- .../lua/rom/programs/turtle/craft.lua | 20 +- .../lua/rom/programs/turtle/dance.lua | 18 +- .../lua/rom/programs/turtle/equip.lua | 26 +- .../lua/rom/programs/turtle/excavate.lua | 78 +-- .../lua/rom/programs/turtle/go.lua | 12 +- .../lua/rom/programs/turtle/refuel.lua | 16 +- .../lua/rom/programs/turtle/tunnel.lua | 32 +- .../lua/rom/programs/turtle/turn.lua | 12 +- .../lua/rom/programs/turtle/unequip.lua | 22 +- .../computercraft/lua/rom/programs/type.lua | 14 +- .../assets/computercraft/lua/rom/startup.lua | 162 +++--- src/test/resources/test-rom/mcfly.lua | 4 +- .../spec/programs/command/exec_spec.lua | 4 +- .../spec/programs/http/pastebin_spec.lua | 2 +- 78 files changed, 2168 insertions(+), 2159 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index 0a8fe626e..38ed350c5 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -25,6 +25,8 @@ (at / (linters + syntax:string-index + ;; It'd be nice to avoid this, but right now there's a lot of instances of ;; it. -var:set-loop @@ -36,7 +38,14 @@ ;; Suppress a couple of documentation comments warnings for now. We'll ;; hopefully be able to remove them in the future. -doc:undocumented -doc:undocumented-arg -doc:unresolved-reference - -var:unresolved-member)) + -var:unresolved-member) + (lint + (bracket-spaces + (call no-space) + (function-args no-space) + (parens no-space) + (table space) + (index no-space)))) ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index faffa2cea..39dd252c3 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -33,41 +33,41 @@ if _VERSION == "Lua 5.1" then end end - function load( x, name, mode, env ) + function load(x, name, mode, env) expect(1, x, "function", "string") expect(2, name, "string", "nil") expect(3, mode, "string", "nil") expect(4, env, "table", "nil") - local ok, p1, p2 = pcall( function() + local ok, p1, p2 = pcall(function() if type(x) == "string" then - local result, err = nativeloadstring( x, name ) + local result, err = nativeloadstring(x, name) if result then if env then env._ENV = env - nativesetfenv( result, env ) + nativesetfenv(result, env) end return result else return nil, err end else - local result, err = nativeload( x, name ) + local result, err = nativeload(x, name) if result then if env then env._ENV = env - nativesetfenv( result, env ) + nativesetfenv(result, env) end return result else return nil, err end end - end ) + end) if ok then return p1, p2 else - error( p1, 2 ) + error(p1, 2) end end @@ -81,7 +81,7 @@ if _VERSION == "Lua 5.1" then math.log10 = nil table.maxn = nil else - loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) end + loadstring = function(string, chunkname) return nativeloadstring(string, prefix(chunkname)) end -- Inject a stub for the old bit library _G.bit = { @@ -101,28 +101,28 @@ function os.version() return "CraftOS 1.8" end -function os.pullEventRaw( sFilter ) - return coroutine.yield( sFilter ) +function os.pullEventRaw(sFilter) + return coroutine.yield(sFilter) end -function os.pullEvent( sFilter ) - local eventData = table.pack( os.pullEventRaw( sFilter ) ) +function os.pullEvent(sFilter) + local eventData = table.pack(os.pullEventRaw(sFilter)) if eventData[1] == "terminate" then - error( "Terminated", 0 ) + error("Terminated", 0) end - return table.unpack( eventData, 1, eventData.n ) + return table.unpack(eventData, 1, eventData.n) end -- Install globals -function sleep( nTime ) +function sleep(nTime) expect(1, nTime, "number", "nil") - local timer = os.startTimer( nTime or 0 ) + local timer = os.startTimer(nTime or 0) repeat - local _, param = os.pullEvent( "timer" ) + local _, param = os.pullEvent("timer") until param == timer end -function write( sText ) +function write(sText) expect(1, sText, "string", "number") local w, h = term.getSize() @@ -143,32 +143,32 @@ function write( sText ) -- Print the line with proper word wrapping sText = tostring(sText) while #sText > 0 do - local whitespace = string.match( sText, "^[ \t]+" ) + local whitespace = string.match(sText, "^[ \t]+") if whitespace then -- Print whitespace - term.write( whitespace ) + term.write(whitespace) x, y = term.getCursorPos() - sText = string.sub( sText, #whitespace + 1 ) + sText = string.sub(sText, #whitespace + 1) end - local newline = string.match( sText, "^\n" ) + local newline = string.match(sText, "^\n") if newline then -- Print newlines newLine() - sText = string.sub( sText, 2 ) + sText = string.sub(sText, 2) end - local text = string.match( sText, "^[^ \t\n]+" ) + local text = string.match(sText, "^[^ \t\n]+") if text then - sText = string.sub( sText, #text + 1 ) + sText = string.sub(sText, #text + 1) if #text > w then -- Print a multiline word while #text > 0 do if x > w then newLine() end - term.write( text ) - text = string.sub( text, w - x + 2 ) + term.write(text) + text = string.sub(text, w - x + 2) x, y = term.getCursorPos() end else @@ -176,7 +176,7 @@ function write( sText ) if x + #text - 1 > w then newLine() end - term.write( text ) + term.write(text) x, y = term.getCursorPos() end end @@ -185,42 +185,42 @@ function write( sText ) return nLinesPrinted end -function print( ... ) +function print(...) local nLinesPrinted = 0 local nLimit = select("#", ...) for n = 1, nLimit do - local s = tostring( select( n, ... ) ) + local s = tostring(select(n, ...)) if n < nLimit then s = s .. "\t" end - nLinesPrinted = nLinesPrinted + write( s ) + nLinesPrinted = nLinesPrinted + write(s) end - nLinesPrinted = nLinesPrinted + write( "\n" ) + nLinesPrinted = nLinesPrinted + write("\n") return nLinesPrinted end -function printError( ... ) +function printError(...) local oldColour if term.isColour() then oldColour = term.getTextColour() - term.setTextColour( colors.red ) + term.setTextColour(colors.red) end - print( ... ) + print(...) if term.isColour() then - term.setTextColour( oldColour ) + term.setTextColour(oldColour) end end -function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) +function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) expect(1, _sReplaceChar, "string", "nil") expect(2, _tHistory, "table", "nil") expect(3, _fnComplete, "function", "nil") expect(4, _sDefault, "string", "nil") - term.setCursorBlink( true ) + term.setCursorBlink(true) local sLine - if type( _sDefault ) == "string" then + if type(_sDefault) == "string" then sLine = _sDefault else sLine = "" @@ -228,14 +228,14 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local nHistoryPos local nPos, nScroll = #sLine, 0 if _sReplaceChar then - _sReplaceChar = string.sub( _sReplaceChar, 1, 1 ) + _sReplaceChar = string.sub(_sReplaceChar, 1, 1) end local tCompletions local nCompletion local function recomplete() if _fnComplete and nPos == #sLine then - tCompletions = _fnComplete( sLine ) + tCompletions = _fnComplete(sLine) if tCompletions and #tCompletions > 0 then nCompletion = 1 else @@ -255,7 +255,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) local w = term.getSize() local sx = term.getCursorPos() - local function redraw( _bClear ) + local function redraw(_bClear) local cursor_pos = nPos - nScroll if sx + cursor_pos >= w then -- We've moved beyond the RHS, ensure we're on the edge. @@ -266,39 +266,39 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end local _, cy = term.getCursorPos() - term.setCursorPos( sx, cy ) + term.setCursorPos(sx, cy) local sReplace = _bClear and " " or _sReplaceChar if sReplace then - term.write( string.rep( sReplace, math.max( #sLine - nScroll, 0 ) ) ) + term.write(string.rep(sReplace, math.max(#sLine - nScroll, 0))) else - term.write( string.sub( sLine, nScroll + 1 ) ) + term.write(string.sub(sLine, nScroll + 1)) end if nCompletion then - local sCompletion = tCompletions[ nCompletion ] + local sCompletion = tCompletions[nCompletion] local oldText, oldBg if not _bClear then oldText = term.getTextColor() oldBg = term.getBackgroundColor() - term.setTextColor( colors.white ) - term.setBackgroundColor( colors.gray ) + term.setTextColor(colors.white) + term.setBackgroundColor(colors.gray) end if sReplace then - term.write( string.rep( sReplace, #sCompletion ) ) + term.write(string.rep(sReplace, #sCompletion)) else - term.write( sCompletion ) + term.write(sCompletion) end if not _bClear then - term.setTextColor( oldText ) - term.setBackgroundColor( oldBg ) + term.setTextColor(oldText) + term.setBackgroundColor(oldBg) end end - term.setCursorPos( sx + nPos - nScroll, cy ) + term.setCursorPos(sx + nPos - nScroll, cy) end local function clear() - redraw( true ) + redraw(true) end recomplete() @@ -310,7 +310,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) clear() -- Find the common prefix of all the other suggestions which start with the same letter as the current one - local sCompletion = tCompletions[ nCompletion ] + local sCompletion = tCompletions[nCompletion] sLine = sLine .. sCompletion nPos = #sLine @@ -324,7 +324,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) if sEvent == "char" then -- Typed key clear() - sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) + sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1) nPos = nPos + 1 recomplete() redraw() @@ -332,7 +332,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) elseif sEvent == "paste" then -- Pasted text clear() - sLine = string.sub( sLine, 1, nPos ) .. param .. string.sub( sLine, nPos + 1 ) + sLine = string.sub(sLine, 1, nPos) .. param .. string.sub(sLine, nPos + 1) nPos = nPos + #param recomplete() redraw() @@ -423,7 +423,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) -- Backspace if nPos > 0 then clear() - sLine = string.sub( sLine, 1, nPos - 1 ) .. string.sub( sLine, nPos + 1 ) + sLine = string.sub(sLine, 1, nPos - 1) .. string.sub(sLine, nPos + 1) nPos = nPos - 1 if nScroll > 0 then nScroll = nScroll - 1 end recomplete() @@ -443,7 +443,7 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) -- Delete if nPos < #sLine then clear() - sLine = string.sub( sLine, 1, nPos ) .. string.sub( sLine, nPos + 2 ) + sLine = string.sub(sLine, 1, nPos) .. string.sub(sLine, nPos + 2) recomplete() redraw() end @@ -480,14 +480,14 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault ) end local _, cy = term.getCursorPos() - term.setCursorBlink( false ) - term.setCursorPos( w + 1, cy ) + term.setCursorBlink(false) + term.setCursorPos(w + 1, cy) print() return sLine end -function loadfile( filename, mode, env ) +function loadfile(filename, mode, env) -- Support the previous `loadfile(filename, env)` form instead. if type(mode) == "table" and env == nil then mode, env = nil, mode @@ -497,81 +497,81 @@ function loadfile( filename, mode, env ) expect(2, mode, "string", "nil") expect(3, env, "table", "nil") - local file = fs.open( filename, "r" ) + local file = fs.open(filename, "r") if not file then return nil, "File not found" end - local func, err = load( file.readAll(), "@" .. fs.getName( filename ), mode, env ) + local func, err = load(file.readAll(), "@" .. fs.getName(filename), mode, env) file.close() return func, err end -function dofile( _sFile ) +function dofile(_sFile) expect(1, _sFile, "string") - local fnFile, e = loadfile( _sFile, nil, _G ) + local fnFile, e = loadfile(_sFile, nil, _G) if fnFile then return fnFile() else - error( e, 2 ) + error(e, 2) end end -- Install the rest of the OS api -function os.run( _tEnv, _sPath, ... ) +function os.run(_tEnv, _sPath, ...) expect(1, _tEnv, "table") expect(2, _sPath, "string") - local tArgs = table.pack( ... ) + local tArgs = table.pack(...) local tEnv = _tEnv - setmetatable( tEnv, { __index = _G } ) - local fnFile, err = loadfile( _sPath, nil, tEnv ) + setmetatable(tEnv, { __index = _G }) + local fnFile, err = loadfile(_sPath, nil, tEnv) if fnFile then - local ok, err = pcall( function() - fnFile( table.unpack( tArgs, 1, tArgs.n ) ) - end ) + local ok, err = pcall(function() + fnFile(table.unpack(tArgs, 1, tArgs.n)) + end) if not ok then if err and err ~= "" then - printError( err ) + printError(err) end return false end return true end if err and err ~= "" then - printError( err ) + printError(err) end return false end local tAPIsLoading = {} -function os.loadAPI( _sPath ) +function os.loadAPI(_sPath) expect(1, _sPath, "string") - local sName = fs.getName( _sPath ) + local sName = fs.getName(_sPath) if sName:sub(-4) == ".lua" then sName = sName:sub(1, -5) end if tAPIsLoading[sName] == true then - printError( "API " .. sName .. " is already being loaded" ) + printError("API " .. sName .. " is already being loaded") return false end tAPIsLoading[sName] = true local tEnv = {} - setmetatable( tEnv, { __index = _G } ) - local fnAPI, err = loadfile( _sPath, nil, tEnv ) + setmetatable(tEnv, { __index = _G }) + local fnAPI, err = loadfile(_sPath, nil, tEnv) if fnAPI then - local ok, err = pcall( fnAPI ) + local ok, err = pcall(fnAPI) if not ok then tAPIsLoading[sName] = nil - return error( "Failed to load API " .. sName .. " due to " .. err, 1 ) + return error("Failed to load API " .. sName .. " due to " .. err, 1) end else tAPIsLoading[sName] = nil - return error( "Failed to load API " .. sName .. " due to " .. err, 1 ) + return error("Failed to load API " .. sName .. " due to " .. err, 1) end local tAPI = {} - for k, v in pairs( tEnv ) do + for k, v in pairs(tEnv) do if k ~= "_ENV" then tAPI[k] = v end @@ -582,15 +582,15 @@ function os.loadAPI( _sPath ) return true end -function os.unloadAPI( _sName ) +function os.unloadAPI(_sName) expect(1, _sName, "string") if _sName ~= "_G" and type(_G[_sName]) == "table" then _G[_sName] = nil end end -function os.sleep( nTime ) - sleep( nTime ) +function os.sleep(nTime) + sleep(nTime) end local nativeShutdown = os.shutdown @@ -619,7 +619,7 @@ if http then PATCH = true, TRACE = true, } - local function checkKey( options, key, ty, opt ) + local function checkKey(options, key, ty, opt) local value = options[key] local valueTy = type(value) @@ -628,24 +628,24 @@ if http then end end - local function checkOptions( options, body ) - checkKey( options, "url", "string" ) + local function checkOptions(options, body) + checkKey(options, "url", "string") if body == false then - checkKey( options, "body", "nil" ) + checkKey(options, "body", "nil") else - checkKey( options, "body", "string", not body ) + checkKey(options, "body", "string", not body) end - checkKey( options, "headers", "table", true ) - checkKey( options, "method", "string", true ) - checkKey( options, "redirect", "boolean", true ) + checkKey(options, "headers", "table", true) + checkKey(options, "method", "string", true) + checkKey(options, "redirect", "boolean", true) if options.method and not methods[options.method] then - error( "Unsupported HTTP method", 3 ) + error("Unsupported HTTP method", 3) end end - local function wrapRequest( _url, ... ) - local ok, err = nativeHTTPRequest( ... ) + local function wrapRequest(_url, ...) + local ok, err = nativeHTTPRequest(...) if ok then while true do local event, param1, param2, param3 = os.pullEvent() @@ -660,34 +660,34 @@ if http then end http.get = function(_url, _headers, _binary) - if type( _url ) == "table" then - checkOptions( _url, false ) - return wrapRequest( _url.url, _url ) + if type(_url) == "table" then + checkOptions(_url, false) + return wrapRequest(_url.url, _url) end expect(1, _url, "string") expect(2, _headers, "table", "nil") expect(3, _binary, "boolean", "nil") - return wrapRequest( _url, _url, nil, _headers, _binary ) + return wrapRequest(_url, _url, nil, _headers, _binary) end http.post = function(_url, _post, _headers, _binary) - if type( _url ) == "table" then - checkOptions( _url, true ) - return wrapRequest( _url.url, _url ) + if type(_url) == "table" then + checkOptions(_url, true) + return wrapRequest(_url.url, _url) end expect(1, _url, "string") expect(2, _post, "string") expect(3, _headers, "table", "nil") expect(4, _binary, "boolean", "nil") - return wrapRequest( _url, _url, _post, _headers, _binary ) + return wrapRequest(_url, _url, _post, _headers, _binary) end - http.request = function( _url, _post, _headers, _binary ) + http.request = function(_url, _post, _headers, _binary) local url - if type( _url ) == "table" then - checkOptions( _url ) + if type(_url) == "table" then + checkOptions(_url) url = _url.url else expect(1, _url, "string") @@ -697,32 +697,32 @@ if http then url = _url.url end - local ok, err = nativeHTTPRequest( _url, _post, _headers, _binary ) + local ok, err = nativeHTTPRequest(_url, _post, _headers, _binary) if not ok then - os.queueEvent( "http_failure", url, err ) + os.queueEvent("http_failure", url, err) end return ok, err end local nativeCheckURL = http.checkURL http.checkURLAsync = nativeCheckURL - http.checkURL = function( _url ) - local ok, err = nativeCheckURL( _url ) + http.checkURL = function(_url) + local ok, err = nativeCheckURL(_url) if not ok then return ok, err end while true do - local _, url, ok, err = os.pullEvent( "http_check" ) + local _, url, ok, err = os.pullEvent("http_check") if url == _url then return ok, err end end end local nativeWebsocket = http.websocket http.websocketAsync = nativeWebsocket - http.websocket = function( _url, _headers ) + http.websocket = function(_url, _headers) expect(1, _url, "string") expect(2, _headers, "table", "nil") - local ok, err = nativeWebsocket( _url, _headers ) + local ok, err = nativeWebsocket(_url, _headers) if not ok then return ok, err end while true do @@ -738,7 +738,7 @@ end -- Install the lua part of the FS api local tEmpty = {} -function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) +function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) expect(1, sPath, "string") expect(2, sLocation, "string") expect(3, bIncludeFiles, "boolean", "nil") @@ -748,49 +748,49 @@ function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs ) bIncludeDirs = bIncludeDirs ~= false local sDir = sLocation local nStart = 1 - local nSlash = string.find( sPath, "[/\\]", nStart ) + local nSlash = string.find(sPath, "[/\\]", nStart) if nSlash == 1 then sDir = "" nStart = 2 end local sName while not sName do - local nSlash = string.find( sPath, "[/\\]", nStart ) + local nSlash = string.find(sPath, "[/\\]", nStart) if nSlash then - local sPart = string.sub( sPath, nStart, nSlash - 1 ) - sDir = fs.combine( sDir, sPart ) + local sPart = string.sub(sPath, nStart, nSlash - 1) + sDir = fs.combine(sDir, sPart) nStart = nSlash + 1 else - sName = string.sub( sPath, nStart ) + sName = string.sub(sPath, nStart) end end - if fs.isDir( sDir ) then + if fs.isDir(sDir) then local tResults = {} if bIncludeDirs and sPath == "" then - table.insert( tResults, "." ) + table.insert(tResults, ".") end if sDir ~= "" then if sPath == "" then - table.insert( tResults, bIncludeDirs and ".." or "../" ) + table.insert(tResults, bIncludeDirs and ".." or "../") elseif sPath == "." then - table.insert( tResults, bIncludeDirs and "." or "./" ) + table.insert(tResults, bIncludeDirs and "." or "./") end end - local tFiles = fs.list( sDir ) + local tFiles = fs.list(sDir) for n = 1, #tFiles do local sFile = tFiles[n] - if #sFile >= #sName and string.sub( sFile, 1, #sName ) == sName then - local bIsDir = fs.isDir( fs.combine( sDir, sFile ) ) - local sResult = string.sub( sFile, #sName + 1 ) + if #sFile >= #sName and string.sub(sFile, 1, #sName) == sName then + local bIsDir = fs.isDir(fs.combine(sDir, sFile)) + local sResult = string.sub(sFile, #sName + 1) if bIsDir then - table.insert( tResults, sResult .. "/" ) + table.insert(tResults, sResult .. "/") if bIncludeDirs and #sResult > 0 then - table.insert( tResults, sResult ) + table.insert(tResults, sResult) end else if bIncludeFiles and #sResult > 0 then - table.insert( tResults, sResult ) + table.insert(tResults, sResult) end end end @@ -802,26 +802,26 @@ end -- Load APIs local bAPIError = false -local tApis = fs.list( "rom/apis" ) -for _, sFile in ipairs( tApis ) do - if string.sub( sFile, 1, 1 ) ~= "." then - local sPath = fs.combine( "rom/apis", sFile ) - if not fs.isDir( sPath ) then - if not os.loadAPI( sPath ) then +local tApis = fs.list("rom/apis") +for _, sFile in ipairs(tApis) do + if string.sub(sFile, 1, 1) ~= "." then + local sPath = fs.combine("rom/apis", sFile) + if not fs.isDir(sPath) then + if not os.loadAPI(sPath) then bAPIError = true end end end end -if turtle and fs.isDir( "rom/apis/turtle" ) then +if turtle and fs.isDir("rom/apis/turtle") then -- Load turtle APIs - local tApis = fs.list( "rom/apis/turtle" ) - for _, sFile in ipairs( tApis ) do - if string.sub( sFile, 1, 1 ) ~= "." then - local sPath = fs.combine( "rom/apis/turtle", sFile ) - if not fs.isDir( sPath ) then - if not os.loadAPI( sPath ) then + local tApis = fs.list("rom/apis/turtle") + for _, sFile in ipairs(tApis) do + if string.sub(sFile, 1, 1) ~= "." then + local sPath = fs.combine("rom/apis/turtle", sFile) + if not fs.isDir(sPath) then + if not os.loadAPI(sPath) then bAPIError = true end end @@ -829,14 +829,14 @@ if turtle and fs.isDir( "rom/apis/turtle" ) then end end -if pocket and fs.isDir( "rom/apis/pocket" ) then +if pocket and fs.isDir("rom/apis/pocket") then -- Load pocket APIs - local tApis = fs.list( "rom/apis/pocket" ) - for _, sFile in ipairs( tApis ) do - if string.sub( sFile, 1, 1 ) ~= "." then - local sPath = fs.combine( "rom/apis/pocket", sFile ) - if not fs.isDir( sPath ) then - if not os.loadAPI( sPath ) then + local tApis = fs.list("rom/apis/pocket") + for _, sFile in ipairs(tApis) do + if string.sub(sFile, 1, 1) ~= "." then + local sPath = fs.combine("rom/apis/pocket", sFile) + if not fs.isDir(sPath) then + if not os.loadAPI(sPath) then bAPIError = true end end @@ -844,18 +844,18 @@ if pocket and fs.isDir( "rom/apis/pocket" ) then end end -if commands and fs.isDir( "rom/apis/command" ) then +if commands and fs.isDir("rom/apis/command") then -- Load command APIs - if os.loadAPI( "rom/apis/command/commands.lua" ) then + if os.loadAPI("rom/apis/command/commands.lua") then -- Add a special case-insensitive metatable to the commands api local tCaseInsensitiveMetatable = { - __index = function( table, key ) - local value = rawget( table, key ) + __index = function(table, key) + local value = rawget(table, key) if value ~= nil then return value end if type(key) == "string" then - local value = rawget( table, string.lower(key) ) + local value = rawget(table, string.lower(key)) if value ~= nil then return value end @@ -863,8 +863,8 @@ if commands and fs.isDir( "rom/apis/command" ) then return nil end, } - setmetatable( commands, tCaseInsensitiveMetatable ) - setmetatable( commands.async, tCaseInsensitiveMetatable ) + setmetatable(commands, tCaseInsensitiveMetatable) + setmetatable(commands.async, tCaseInsensitiveMetatable) -- Add global "exec" function exec = commands.exec @@ -874,29 +874,29 @@ if commands and fs.isDir( "rom/apis/command" ) then end if bAPIError then - print( "Press any key to continue" ) - os.pullEvent( "key" ) + print("Press any key to continue") + os.pullEvent("key") term.clear() - term.setCursorPos( 1, 1 ) + term.setCursorPos(1, 1) end -- Set default settings -settings.set( "shell.allow_startup", true ) -settings.set( "shell.allow_disk_startup", commands == nil ) -settings.set( "shell.autocomplete", true ) -settings.set( "edit.autocomplete", true ) -settings.set( "edit.default_extension", "lua" ) -settings.set( "paint.default_extension", "nfp" ) -settings.set( "lua.autocomplete", true ) -settings.set( "list.show_hidden", false ) -settings.set( "motd.enable", false ) -settings.set( "motd.path", "/rom/motd.txt:/motd.txt" ) +settings.set("shell.allow_startup", true) +settings.set("shell.allow_disk_startup", commands == nil) +settings.set("shell.autocomplete", true) +settings.set("edit.autocomplete", true) +settings.set("edit.default_extension", "lua") +settings.set("paint.default_extension", "nfp") +settings.set("lua.autocomplete", true) +settings.set("list.show_hidden", false) +settings.set("motd.enable", false) +settings.set("motd.path", "/rom/motd.txt:/motd.txt") if term.isColour() then - settings.set( "bios.use_multishell", true ) + settings.set("bios.use_multishell", true) end if _CC_DEFAULT_SETTINGS then - for sPair in string.gmatch( _CC_DEFAULT_SETTINGS, "[^,]+" ) do - local sName, sValue = string.match( sPair, "([^=]*)=(.*)" ) + for sPair in string.gmatch(_CC_DEFAULT_SETTINGS, "[^,]+") do + local sName, sValue = string.match(sPair, "([^=]*)=(.*)") if sName and sValue then local value if sValue == "true" then @@ -911,43 +911,43 @@ if _CC_DEFAULT_SETTINGS then value = sValue end if value ~= nil then - settings.set( sName, value ) + settings.set(sName, value) else - settings.unset( sName ) + settings.unset(sName) end end end end -- Load user settings -if fs.exists( ".settings" ) then - settings.load( ".settings" ) +if fs.exists(".settings") then + settings.load(".settings") end -- Run the shell local ok, err = pcall(parallel.waitForAny, function() local sShell - if term.isColour() and settings.get( "bios.use_multishell" ) then + if term.isColour() and settings.get("bios.use_multishell") then sShell = "rom/programs/advanced/multishell.lua" else sShell = "rom/programs/shell.lua" end - os.run( {}, sShell ) - os.run( {}, "rom/programs/shutdown.lua" ) + os.run({}, sShell) + os.run({}, "rom/programs/shutdown.lua") end, rednet.run ) -- If the shell errored, let the user read it. -term.redirect( term.native() ) +term.redirect(term.native()) if not ok then - printError( err ) - pcall( function() - term.setCursorBlink( false ) - print( "Press any key to continue" ) - os.pullEvent( "key" ) - end ) + printError(err) + pcall(function() + term.setCursorBlink(false) + print("Press any key to continue") + os.pullEvent("key") + end) end -- End diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua index 8754b1929..b821c38d3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua @@ -86,7 +86,7 @@ black = 0x8000 -- colors.combine(colors.white, colors.magenta, colours.lightBlue) -- -- => 13 -- ``` -function combine( ... ) +function combine(...) local r = 0 for i = 1, select('#', ...) do local c = select(i, ...) @@ -110,7 +110,7 @@ end -- colours.subtract(colours.lime, colours.orange, colours.white) -- -- => 32 -- ``` -function subtract( colors, ... ) +function subtract(colors, ...) expect(1, colors, "number") local r = colors for i = 1, select('#', ...) do @@ -131,7 +131,7 @@ end -- colors.test(colors.combine(colors.white, colors.magenta, colours.lightBlue), colors.lightBlue) -- -- => true -- ``` -function test( colors, color ) +function test(colors, color) expect(1, colors, "number") expect(2, color, "number") return bit32.band(colors, color) == color @@ -148,14 +148,14 @@ end -- colors.rgb(0.7, 0.2, 0.6) -- -- => 0xb23399 -- ``` -function packRGB( r, g, b ) +function packRGB(r, g, b) expect(1, r, "number") expect(2, g, "number") expect(3, b, "number") return - bit32.band( r * 255, 0xFF ) * 2 ^ 16 + - bit32.band( g * 255, 0xFF ) * 2 ^ 8 + - bit32.band( b * 255, 0xFF ) + bit32.band(r * 255, 0xFF) * 2 ^ 16 + + bit32.band(g * 255, 0xFF) * 2 ^ 8 + + bit32.band(b * 255, 0xFF) end --- Separate a hexadecimal RGB colour into its three constituent channels. @@ -170,12 +170,12 @@ end -- -- => 0.7, 0.2, 0.6 -- ``` -- @see colors.packRGB -function unpackRGB( rgb ) +function unpackRGB(rgb) expect(1, rgb, "number") return - bit32.band( bit32.rshift( rgb, 16 ), 0xFF ) / 255, - bit32.band( bit32.rshift( rgb, 8 ), 0xFF ) / 255, - bit32.band( rgb, 0xFF ) / 255 + bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255, + bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255, + bit32.band(rgb, 0xFF) / 255 end --- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many @@ -202,10 +202,10 @@ end -- colors.rgb(0.7, 0.2, 0.6) -- -- => 0xb23399 -- ``` -function rgb8( r, g, b ) +function rgb8(r, g, b) if g == nil and b == nil then - return unpackRGB( r ) + return unpackRGB(r) else - return packRGB( r, g, b ) + return packRGB(r, g, b) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua index d0c02b304..7f5c4b824 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua @@ -14,7 +14,7 @@ -- @module commands if not commands then - error( "Cannot load command API on normal computer", 2 ) + error("Cannot load command API on normal computer", 2) end --- The builtin commands API, without any generated command helper functions @@ -23,16 +23,16 @@ end -- overwritten by a command. native = commands.native or commands -local function collapseArgs( bJSONIsNBT, ... ) +local function collapseArgs(bJSONIsNBT, ...) local args = table.pack(...) for i = 1, #args do local arg = args[i] if type(arg) == "boolean" or type(arg) == "number" or type(arg) == "string" then args[i] = tostring(arg) elseif type(arg) == "table" then - args[i] = textutils.serialiseJSON( arg, bJSONIsNBT ) + args[i] = textutils.serialiseJSON(arg, bJSONIsNBT) else - error( "Expected string, number, boolean or table", 3 ) + error("Expected string, number, boolean or table", 3) end end @@ -41,27 +41,27 @@ end -- Put native functions into the environment local env = _ENV -for k, v in pairs( native ) do +for k, v in pairs(native) do env[k] = v end -- Create wrapper functions for all the commands local tAsync = {} local tNonNBTJSONCommands = { - [ "tellraw" ] = true, - [ "title" ] = true, + ["tellraw"] = true, + ["title"] = true, } local tCommands = native.list() for _, sCommandName in ipairs(tCommands) do - if env[ sCommandName ] == nil then - local bJSONIsNBT = tNonNBTJSONCommands[ sCommandName ] == nil - env[ sCommandName ] = function( ... ) - local sCommand = collapseArgs( bJSONIsNBT, sCommandName, ... ) - return native.exec( sCommand ) + if env[sCommandName] == nil then + local bJSONIsNBT = tNonNBTJSONCommands[sCommandName] == nil + env[sCommandName] = function(...) + local sCommand = collapseArgs(bJSONIsNBT, sCommandName, ...) + return native.exec(sCommand) end - tAsync[ sCommandName ] = function( ... ) - local sCommand = collapseArgs( bJSONIsNBT, sCommandName, ... ) - return native.execAsync( sCommand ) + tAsync[sCommandName] = function(...) + local sCommand = collapseArgs(bJSONIsNBT, sCommandName, ...) + return native.execAsync(sCommand) end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua index 502989008..fcc907121 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua @@ -11,11 +11,11 @@ -- -- @module disk -local function isDrive( name ) - if type( name ) ~= "string" then - error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 3 ) +local function isDrive(name) + if type(name) ~= "string" then + error("bad argument #1 (expected string, got " .. type(name) .. ")", 3) end - return peripheral.getType( name ) == "drive" + return peripheral.getType(name) == "drive" end --- Checks whether any item at all is in the disk drive @@ -23,9 +23,9 @@ end -- @tparam string name The name of the disk drive. -- @treturn boolean If something is in the disk drive. -- @usage disk.isPresent(false) -function isPresent( name ) - if isDrive( name ) then - return peripheral.call( name, "isDiskPresent" ) +function isPresent(name) + if isDrive(name) then + return peripheral.call(name, "isDiskPresent") end return false end @@ -40,9 +40,9 @@ end -- @treturn string|nil The name of the current media, or `nil` if the drive is -- not present or empty. -- @see disk.setLabel -function getLabel( name ) - if isDrive( name ) then - return peripheral.call( name, "getDiskLabel" ) +function getLabel(name) + if isDrive(name) then + return peripheral.call(name, "getDiskLabel") end return nil end @@ -51,9 +51,9 @@ end -- -- @tparam string name The name of the disk drive. -- @tparam string|nil label The new label of the disk -function setLabel( name, label ) - if isDrive( name ) then - peripheral.call( name, "setDiskLabel", label ) +function setLabel(name, label) + if isDrive(name) then + peripheral.call(name, "setDiskLabel", label) end end @@ -64,9 +64,9 @@ end -- @tparam string name The name of the disk drive. -- @treturn boolean If the disk is present and provides a mount. -- @see disk.getMountPath -function hasData( name ) - if isDrive( name ) then - return peripheral.call( name, "hasData" ) +function hasData(name) + if isDrive(name) then + return peripheral.call(name, "hasData") end return false end @@ -78,9 +78,9 @@ end -- @treturn string|nil The mount's directory, or `nil` if the drive does not -- contain a floppy or computer. -- @see disk.hasData -function getMountPath( name ) - if isDrive( name ) then - return peripheral.call( name, "getMountPath" ) +function getMountPath(name) + if isDrive(name) then + return peripheral.call(name, "getMountPath") end return nil end @@ -94,9 +94,9 @@ end -- -- @tparam string name The name of the disk drive. -- @treturn boolean If the disk is present and has audio saved on it. -function hasAudio( name ) - if isDrive( name ) then - return peripheral.call( name, "hasAudio" ) +function hasAudio(name) + if isDrive(name) then + return peripheral.call(name, "hasAudio") end return false end @@ -108,9 +108,9 @@ end -- @tparam string name The name of the disk drive. -- @treturn string|false|nil The track title, `false` if there is not a music -- record in the drive or `nil` if no drive is present. -function getAudioTitle( name ) - if isDrive( name ) then - return peripheral.call( name, "getAudioTitle" ) +function getAudioTitle(name) + if isDrive(name) then + return peripheral.call(name, "getAudioTitle") end return nil end @@ -124,9 +124,9 @@ end -- -- @tparam string name The name of the disk drive. -- @usage disk.playAudio("bottom") -function playAudio( name ) - if isDrive( name ) then - peripheral.call( name, "playAudio" ) +function playAudio(name) + if isDrive(name) then + peripheral.call(name, "playAudio") end end @@ -134,14 +134,14 @@ end -- @{disk.playAudio}. -- -- @tparam string name The name o the disk drive. -function stopAudio( name ) +function stopAudio(name) if not name then - for _, sName in ipairs( peripheral.getNames() ) do - stopAudio( sName ) + for _, sName in ipairs(peripheral.getNames()) do + stopAudio(sName) end else - if isDrive( name ) then - peripheral.call( name, "stopAudio" ) + if isDrive(name) then + peripheral.call(name, "stopAudio") end end end @@ -150,9 +150,9 @@ end -- -- @tparam string name The name of the disk drive. -- @usage disk.eject("bottom") -function eject( name ) - if isDrive( name ) then - peripheral.call( name, "ejectDisk" ) +function eject(name) + if isDrive(name) then + peripheral.call(name, "ejectDisk") end end @@ -163,9 +163,9 @@ end -- -- @tparam string name The name of the disk drive. -- @treturn string|nil The disk ID, or `nil` if the drive does not contain a floppy disk. -function getID( name ) - if isDrive( name ) then - return peripheral.call( name, "getDiskID" ) +function getID(name) + if isDrive(name) then + return peripheral.call(name, "getDiskID") end return nil end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua index 7a4d03af0..3be8906a5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/gps.lua @@ -27,20 +27,20 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect --- The channel which GPS requests and responses are broadcast on. CHANNEL_GPS = 65534 -local function trilaterate( A, B, C ) +local function trilaterate(A, B, C) local a2b = B.vPosition - A.vPosition local a2c = C.vPosition - A.vPosition - if math.abs( a2b:normalize():dot( a2c:normalize() ) ) > 0.999 then + if math.abs(a2b:normalize():dot(a2c:normalize())) > 0.999 then return nil end local d = a2b:length() local ex = a2b:normalize( ) - local i = ex:dot( a2c ) + local i = ex:dot(a2c) local ey = (a2c - ex * i):normalize() - local j = ey:dot( a2c ) - local ez = ex:cross( ey ) + local j = ey:dot(a2c) + local ez = ex:cross(ey) local r1 = A.nDistance local r2 = B.nDistance @@ -53,31 +53,31 @@ local function trilaterate( A, B, C ) local zSquared = r1 * r1 - x * x - y * y if zSquared > 0 then - local z = math.sqrt( zSquared ) + local z = math.sqrt(zSquared) local result1 = result + ez * z local result2 = result - ez * z - local rounded1, rounded2 = result1:round( 0.01 ), result2:round( 0.01 ) + local rounded1, rounded2 = result1:round(0.01), result2:round(0.01) if rounded1.x ~= rounded2.x or rounded1.y ~= rounded2.y or rounded1.z ~= rounded2.z then return rounded1, rounded2 else return rounded1 end end - return result:round( 0.01 ) + return result:round(0.01) end -local function narrow( p1, p2, fix ) - local dist1 = math.abs( (p1 - fix.vPosition):length() - fix.nDistance ) - local dist2 = math.abs( (p2 - fix.vPosition):length() - fix.nDistance ) +local function narrow(p1, p2, fix) + local dist1 = math.abs((p1 - fix.vPosition):length() - fix.nDistance) + local dist2 = math.abs((p2 - fix.vPosition):length() - fix.nDistance) if math.abs(dist1 - dist2) < 0.01 then return p1, p2 elseif dist1 < dist2 then - return p1:round( 0.01 ) + return p1:round(0.01) else - return p2:round( 0.01 ) + return p2:round(0.01) end end @@ -90,7 +90,7 @@ end -- @treturn[1] number This computer's `y` position. -- @treturn[1] number This computer's `z` position. -- @treturn[2] nil If the position could not be established. -function locate( _nTimeout, _bDebug ) +function locate(_nTimeout, _bDebug) expect(1, _nTimeout, "number", "nil") expect(2, _bDebug, "boolean", "nil") -- Let command computers use their magic fourth-wall-breaking special abilities @@ -100,8 +100,8 @@ function locate( _nTimeout, _bDebug ) -- Find a modem local sModemSide = nil - for _, sSide in ipairs( rs.getSides() ) do - if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then + for _, sSide in ipairs(rs.getSides()) do + if peripheral.getType(sSide) == "modem" and peripheral.call(sSide, "isWireless") then sModemSide = sSide break end @@ -109,30 +109,30 @@ function locate( _nTimeout, _bDebug ) if sModemSide == nil then if _bDebug then - print( "No wireless modem attached" ) + print("No wireless modem attached") end return nil end if _bDebug then - print( "Finding position..." ) + print("Finding position...") end -- Open GPS channel to listen for ping responses - local modem = peripheral.wrap( sModemSide ) + local modem = peripheral.wrap(sModemSide) local bCloseChannel = false - if not modem.isOpen( CHANNEL_GPS ) then - modem.open( CHANNEL_GPS ) + if not modem.isOpen(CHANNEL_GPS) then + modem.open(CHANNEL_GPS) bCloseChannel = true end -- Send a ping to listening GPS hosts - modem.transmit( CHANNEL_GPS, CHANNEL_GPS, "PING" ) + modem.transmit(CHANNEL_GPS, CHANNEL_GPS, "PING") -- Wait for the responses local tFixes = {} local pos1, pos2 = nil, nil - local timeout = os.startTimer( _nTimeout or 2 ) + local timeout = os.startTimer(_nTimeout or 2) while true do local e, p1, p2, p3, p4, p5 = os.pullEvent() if e == "modem_message" then @@ -141,19 +141,19 @@ function locate( _nTimeout, _bDebug ) if sSide == sModemSide and sChannel == CHANNEL_GPS and sReplyChannel == CHANNEL_GPS and nDistance then -- Received the correct message from the correct modem: use it to determine position if type(tMessage) == "table" and #tMessage == 3 and tonumber(tMessage[1]) and tonumber(tMessage[2]) and tonumber(tMessage[3]) then - local tFix = { vPosition = vector.new( tMessage[1], tMessage[2], tMessage[3] ), nDistance = nDistance } + local tFix = { vPosition = vector.new(tMessage[1], tMessage[2], tMessage[3]), nDistance = nDistance } if _bDebug then - print( tFix.nDistance .. " metres from " .. tostring( tFix.vPosition ) ) + print(tFix.nDistance .. " metres from " .. tostring(tFix.vPosition)) end if tFix.nDistance == 0 then pos1, pos2 = tFix.vPosition, nil else - table.insert( tFixes, tFix ) + table.insert(tFixes, tFix) if #tFixes >= 3 then if not pos1 then - pos1, pos2 = trilaterate( tFixes[1], tFixes[2], tFixes[#tFixes] ) + pos1, pos2 = trilaterate(tFixes[1], tFixes[2], tFixes[#tFixes]) else - pos1, pos2 = narrow( pos1, pos2, tFixes[#tFixes] ) + pos1, pos2 = narrow(pos1, pos2, tFixes[#tFixes]) end end end @@ -175,24 +175,24 @@ function locate( _nTimeout, _bDebug ) -- Close the channel, if we opened one if bCloseChannel then - modem.close( CHANNEL_GPS ) + modem.close(CHANNEL_GPS) end -- Return the response if pos1 and pos2 then if _bDebug then - print( "Ambiguous position" ) - print( "Could be " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z .. " or " .. pos2.x .. "," .. pos2.y .. "," .. pos2.z ) + print("Ambiguous position") + print("Could be " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z .. " or " .. pos2.x .. "," .. pos2.y .. "," .. pos2.z) end return nil elseif pos1 then if _bDebug then - print( "Position is " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z ) + print("Position is " .. pos1.x .. "," .. pos1.y .. "," .. pos1.z) end return pos1.x, pos1.y, pos1.z else if _bDebug then - print( "Could not determine position" ) + print("Could not determine position") end return nil end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua index 1b3088c4b..438af474f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/help.lua @@ -22,7 +22,7 @@ end -- @usage help.setPath( "/disk/help/" ) -- @usage help.setPath( help.path() .. ":/myfolder/help/" ) -- @see help.path -function setPath( _sPath ) +function setPath(_sPath) expect(1, _sPath, "string") sPath = _sPath end @@ -33,14 +33,14 @@ end -- @treturn string|nil The path to the given topic's help file, or `nil` if it -- cannot be found. -- @usage print(help.lookup("disk")) -function lookup( _sTopic ) +function lookup(_sTopic) expect(1, _sTopic, "string") -- Look on the path variable for sPath in string.gmatch(sPath, "[^:]+") do - sPath = fs.combine( sPath, _sTopic ) - if fs.exists( sPath ) and not fs.isDir( sPath ) then + sPath = fs.combine(sPath, _sTopic) + if fs.exists(sPath) and not fs.isDir(sPath) then return sPath - elseif fs.exists( sPath .. ".txt" ) and not fs.isDir( sPath .. ".txt" ) then + elseif fs.exists(sPath .. ".txt") and not fs.isDir(sPath .. ".txt") then return sPath .. ".txt" end end @@ -55,20 +55,20 @@ end function topics() -- Add index local tItems = { - [ "index" ] = true, + ["index"] = true, } -- Add topics from the path for sPath in string.gmatch(sPath, "[^:]+") do - if fs.isDir( sPath ) then - local tList = fs.list( sPath ) - for _, sFile in pairs( tList ) do - if string.sub( sFile, 1, 1 ) ~= "." then - if not fs.isDir( fs.combine( sPath, sFile ) ) then + if fs.isDir(sPath) then + local tList = fs.list(sPath) + for _, sFile in pairs(tList) do + if string.sub(sFile, 1, 1) ~= "." then + if not fs.isDir(fs.combine(sPath, sFile)) then if #sFile > 4 and sFile:sub(-4) == ".txt" then sFile = sFile:sub(1, -5) end - tItems[ sFile ] = true + tItems[sFile] = true end end end @@ -77,10 +77,10 @@ function topics() -- Sort and return local tItemList = {} - for sItem in pairs( tItems ) do - table.insert( tItemList, sItem ) + for sItem in pairs(tItems) do + table.insert(tItemList, sItem) end - table.sort( tItemList ) + table.sort(tItemList) return tItemList end @@ -89,14 +89,14 @@ end -- -- @tparam string prefix The prefix to match -- @treturn table A list of matching topics. -function completeTopic( sText ) +function completeTopic(sText) expect(1, sText, "string") local tTopics = topics() local tResults = {} for n = 1, #tTopics do local sTopic = tTopics[n] - if #sTopic > #sText and string.sub( sTopic, 1, #sText ) == sText then - table.insert( tResults, string.sub( sTopic, #sText + 1 ) ) + if #sTopic > #sText and string.sub(sTopic, 1, #sText) == sText then + table.insert(tResults, string.sub(sTopic, #sText + 1)) end end return tResults diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua index d303a8087..14bd98a8a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/keys.lua @@ -57,7 +57,7 @@ local tKeys = { } local keys = _ENV -for nKey, sKey in pairs( tKeys ) do +for nKey, sKey in pairs(tKeys) do keys[sKey] = nKey end @@ -71,7 +71,7 @@ keys.cimcumflex = keys.circumflex --- @local -- -- @tparam number code The key code to look up. -- @treturn string|nil The name of the key, or `nil` if not a valid key code. -function getName( code ) +function getName(code) expect(1, code, "number") - return tKeys[ code ] + return tKeys[code] end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua index 4a5630034..1af17ee6c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua @@ -5,22 +5,22 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect -local function drawPixelInternal( xPos, yPos ) - term.setCursorPos( xPos, yPos ) +local function drawPixelInternal(xPos, yPos) + term.setCursorPos(xPos, yPos) term.write(" ") end local tColourLookup = {} for n = 1, 16 do - tColourLookup[ string.byte( "0123456789abcdef", n, n ) ] = 2 ^ (n - 1) + tColourLookup[string.byte("0123456789abcdef", n, n)] = 2 ^ (n - 1) end -local function parseLine( tImageArg, sLine ) +local function parseLine(tImageArg, sLine) local tLine = {} for x = 1, sLine:len() do - tLine[x] = tColourLookup[ string.byte(sLine, x, x) ] or 0 + tLine[x] = tColourLookup[string.byte(sLine, x, x)] or 0 end - table.insert( tImageArg, tLine ) + table.insert(tImageArg, tLine) end --- Parses an image from a multi-line string @@ -28,11 +28,11 @@ end -- @tparam string image The string containing the raw-image data. -- @treturn table The parsed image data, suitable for use with -- @{paintutils.drawImage}. -function parseImage( image ) +function parseImage(image) expect(1, image, "string") local tImage = {} - for sLine in ( image .. "\n" ):gmatch( "(.-)\n" ) do - parseLine( tImage, sLine ) + for sLine in (image .. "\n"):gmatch("(.-)\n") do + parseLine(tImage, sLine) end return tImage end @@ -45,14 +45,14 @@ end -- -- @treturn table|nil The parsed image data, suitable for use with -- @{paintutils.drawImage}, or `nil` if the file does not exist. -function loadImage( path ) +function loadImage(path) expect(1, path, "string") - if fs.exists( path ) then - local file = io.open( path, "r" ) + if fs.exists(path) then + local file = io.open(path, "r") local sContent = file:read("*a") file:close() - return parseImage( sContent ) + return parseImage(sContent) end return nil end @@ -66,18 +66,18 @@ end -- @tparam number yPos The y position to draw at, where 1 is the very top. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. -function drawPixel( xPos, yPos, colour ) +function drawPixel(xPos, yPos, colour) expect(1, xPos, "number") expect(2, yPos, "number") expect(3, colour, "number", "nil") - if type( xPos ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( xPos ) .. ")", 2 ) end - if type( yPos ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( yPos ) .. ")", 2 ) end - if colour ~= nil and type( colour ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( colour ) .. ")", 2 ) end + if type(xPos) ~= "number" then error("bad argument #1 (expected number, got " .. type(xPos) .. ")", 2) end + if type(yPos) ~= "number" then error("bad argument #2 (expected number, got " .. type(yPos) .. ")", 2) end + if colour ~= nil and type(colour) ~= "number" then error("bad argument #3 (expected number, got " .. type(colour) .. ")", 2) end if colour then - term.setBackgroundColor( colour ) + term.setBackgroundColor(colour) end - return drawPixelInternal( xPos, yPos ) + return drawPixelInternal(xPos, yPos) end --- Draws a straight line from the start to end position. @@ -91,7 +91,7 @@ end -- @tparam number endY The end y position of the line. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. -function drawLine( startX, startY, endX, endY, colour ) +function drawLine(startX, startY, endX, endY, colour) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") @@ -104,14 +104,14 @@ function drawLine( startX, startY, endX, endY, colour ) endY = math.floor(endY) if colour then - term.setBackgroundColor( colour ) + term.setBackgroundColor(colour) end if startX == endX and startY == endY then - drawPixelInternal( startX, startY ) + drawPixelInternal(startX, startY) return end - local minX = math.min( startX, endX ) + local minX = math.min(startX, endX) local maxX, minY, maxY if minX == startX then minY = startY @@ -132,7 +132,7 @@ function drawLine( startX, startY, endX, endY, colour ) local y = minY local dy = yDiff / xDiff for x = minX, maxX do - drawPixelInternal( x, math.floor( y + 0.5 ) ) + drawPixelInternal(x, math.floor(y + 0.5)) y = y + dy end else @@ -140,12 +140,12 @@ function drawLine( startX, startY, endX, endY, colour ) local dx = xDiff / yDiff if maxY >= minY then for y = minY, maxY do - drawPixelInternal( math.floor( x + 0.5 ), y ) + drawPixelInternal(math.floor(x + 0.5), y) x = x + dx end else for y = minY, maxY, -1 do - drawPixelInternal( math.floor( x + 0.5 ), y ) + drawPixelInternal(math.floor(x + 0.5), y) x = x - dx end end @@ -164,7 +164,7 @@ end -- @tparam number endY The end y position of the line. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. -function drawBox( startX, startY, endX, endY, nColour ) +function drawBox(startX, startY, endX, endY, nColour) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") @@ -177,14 +177,14 @@ function drawBox( startX, startY, endX, endY, nColour ) endY = math.floor(endY) if nColour then - term.setBackgroundColor( nColour ) + term.setBackgroundColor(nColour) end if startX == endX and startY == endY then - drawPixelInternal( startX, startY ) + drawPixelInternal(startX, startY) return end - local minX = math.min( startX, endX ) + local minX = math.min(startX, endX) local maxX, minY, maxY if minX == startX then minY = startY @@ -197,14 +197,14 @@ function drawBox( startX, startY, endX, endY, nColour ) end for x = minX, maxX do - drawPixelInternal( x, minY ) - drawPixelInternal( x, maxY ) + drawPixelInternal(x, minY) + drawPixelInternal(x, maxY) end if maxY - minY >= 2 then for y = minY + 1, maxY - 1 do - drawPixelInternal( minX, y ) - drawPixelInternal( maxX, y ) + drawPixelInternal(minX, y) + drawPixelInternal(maxX, y) end end end @@ -220,7 +220,7 @@ end -- @tparam number endY The end y position of the line. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. -function drawFilledBox( startX, startY, endX, endY, nColour ) +function drawFilledBox(startX, startY, endX, endY, nColour) expect(1, startX, "number") expect(2, startY, "number") expect(3, endX, "number") @@ -233,14 +233,14 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) endY = math.floor(endY) if nColour then - term.setBackgroundColor( nColour ) + term.setBackgroundColor(nColour) end if startX == endX and startY == endY then - drawPixelInternal( startX, startY ) + drawPixelInternal(startX, startY) return end - local minX = math.min( startX, endX ) + local minX = math.min(startX, endX) local maxX, minY, maxY if minX == startX then minY = startY @@ -254,7 +254,7 @@ function drawFilledBox( startX, startY, endX, endY, nColour ) for x = minX, maxX do for y = minY, maxY do - drawPixelInternal( x, y ) + drawPixelInternal(x, y) end end end @@ -264,7 +264,7 @@ end -- @tparam table image The parsed image data. -- @tparam number xPos The x position to start drawing at. -- @tparam number xPos The y position to start drawing at. -function drawImage( image, xPos, yPos ) +function drawImage(image, xPos, yPos) expect(1, image, "table") expect(2, xPos, "number") expect(3, yPos, "number") @@ -272,8 +272,8 @@ function drawImage( image, xPos, yPos ) local tLine = image[y] for x = 1, #tLine do if tLine[x] > 0 then - term.setBackgroundColor( tLine[x] ) - drawPixelInternal( x + xPos - 1, y + yPos - 1 ) + term.setBackgroundColor(tLine[x]) + drawPixelInternal(x + xPos - 1, y + yPos - 1) end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua b/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua index ea4f8d43a..c787eff41 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua @@ -14,13 +14,13 @@ -- -- @module parallel -local function create( ... ) +local function create(...) local tFns = table.pack(...) local tCos = {} for i = 1, tFns.n, 1 do local fn = tFns[i] - if type( fn ) ~= "function" then - error( "bad argument #" .. i .. " (expected function, got " .. type( fn ) .. ")", 3 ) + if type(fn) ~= "function" then + error("bad argument #" .. i .. " (expected function, got " .. type(fn) .. ")", 3) end tCos[i] = coroutine.create(fn) @@ -29,7 +29,7 @@ local function create( ... ) return tCos end -local function runUntilLimit( _routines, _limit ) +local function runUntilLimit(_routines, _limit) local count = #_routines local living = count @@ -40,13 +40,13 @@ local function runUntilLimit( _routines, _limit ) local r = _routines[n] if r then if tFilters[r] == nil or tFilters[r] == eventData[1] or eventData[1] == "terminate" then - local ok, param = coroutine.resume( r, table.unpack( eventData, 1, eventData.n ) ) + local ok, param = coroutine.resume(r, table.unpack(eventData, 1, eventData.n)) if not ok then - error( param, 0 ) + error(param, 0) else tFilters[r] = param end - if coroutine.status( r ) == "dead" then + if coroutine.status(r) == "dead" then _routines[n] = nil living = living - 1 if living <= _limit then @@ -58,7 +58,7 @@ local function runUntilLimit( _routines, _limit ) end for n = 1, count do local r = _routines[n] - if r and coroutine.status( r ) == "dead" then + if r and coroutine.status(r) == "dead" then _routines[n] = nil living = living - 1 if living <= _limit then @@ -66,7 +66,7 @@ local function runUntilLimit( _routines, _limit ) end end end - eventData = table.pack( os.pullEventRaw() ) + eventData = table.pack(os.pullEventRaw()) end end @@ -75,9 +75,9 @@ end -- from the @{parallel.waitForAny} call. -- -- @tparam function ... The functions this task will run -function waitForAny( ... ) - local routines = create( ... ) - return runUntilLimit( routines, #routines - 1 ) +function waitForAny(...) + local routines = create(...) + return runUntilLimit(routines, #routines - 1) end --- Switches between execution of the functions, until all of them are @@ -85,7 +85,7 @@ end -- from the @{parallel.waitForAll} call. -- -- @tparam function ... The functions this task will run -function waitForAll( ... ) - local routines = create( ... ) - return runUntilLimit( routines, 0 ) +function waitForAll(...) + local routines = create(...) + return runUntilLimit(routines, 0) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index 9152aa647..ab68db4b6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -37,13 +37,13 @@ local tHostnames = {} -- -- @tparam string modem The name of the modem to open. -- @throws If there is no such modem with the given name -function open( modem ) +function open(modem) expect(1, modem, "string") - if peripheral.getType( modem ) ~= "modem" then - error( "No such modem: " .. modem, 2 ) + if peripheral.getType(modem) ~= "modem" then + error("No such modem: " .. modem, 2) end - peripheral.call( modem, "open", os.getComputerID() ) - peripheral.call( modem, "open", CHANNEL_BROADCAST ) + peripheral.call(modem, "open", os.getComputerID()) + peripheral.call(modem, "open", CHANNEL_BROADCAST) end --- Close a modem with the given @{peripheral} name, meaning it can no longer @@ -52,20 +52,20 @@ end -- @tparam[opt] string modem The side the modem exists on. If not given, all -- open modems will be closed. -- @throws If there is no such modem with the given name -function close( modem ) +function close(modem) expect(1, modem, "string", "nil") if modem then -- Close a specific modem - if peripheral.getType( modem ) ~= "modem" then - error( "No such modem: " .. modem, 2 ) + if peripheral.getType(modem) ~= "modem" then + error("No such modem: " .. modem, 2) end - peripheral.call( modem, "close", os.getComputerID() ) - peripheral.call( modem, "close", CHANNEL_BROADCAST ) + peripheral.call(modem, "close", os.getComputerID()) + peripheral.call(modem, "close", CHANNEL_BROADCAST) else -- Close all modems - for _, modem in ipairs( peripheral.getNames() ) do - if isOpen( modem ) then - close( modem ) + for _, modem in ipairs(peripheral.getNames()) do + if isOpen(modem) then + close(modem) end end end @@ -76,17 +76,17 @@ end -- @tparam[opt] string modem Which modem to check. If not given, all connected -- modems will be checked. -- @treturn boolean If the given modem is open. -function isOpen( modem ) +function isOpen(modem) expect(1, modem, "string", "nil") if modem then -- Check if a specific modem is open - if peripheral.getType( modem ) == "modem" then - return peripheral.call( modem, "isOpen", os.getComputerID() ) and peripheral.call( modem, "isOpen", CHANNEL_BROADCAST ) + if peripheral.getType(modem) == "modem" then + return peripheral.call(modem, "isOpen", os.getComputerID()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST) end else -- Check if any modem is open - for _, modem in ipairs( peripheral.getNames() ) do - if isOpen( modem ) then + for _, modem in ipairs(peripheral.getNames()) do + if isOpen(modem) then return true end end @@ -111,15 +111,15 @@ end -- currently @{rednet.open|open}). Note, this does not guarantee the message was -- actually _received_. -- @see rednet.receive -function send( nRecipient, message, sProtocol ) +function send(nRecipient, message, sProtocol) expect(1, nRecipient, "number") expect(3, sProtocol, "string", "nil") -- Generate a (probably) unique message ID -- We could do other things to guarantee uniqueness, but we really don't need to -- Store it to ensure we don't get our own messages back - local nMessageID = math.random( 1, 2147483647 ) - tReceivedMessages[ nMessageID ] = true - tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID + local nMessageID = math.random(1, 2147483647) + tReceivedMessages[nMessageID] = true + tReceivedMessageTimeouts[os.startTimer(30)] = nMessageID -- Create the message local nReplyChannel = os.getComputerID() @@ -133,14 +133,14 @@ function send( nRecipient, message, sProtocol ) local sent = false if nRecipient == os.getComputerID() then -- Loopback to ourselves - os.queueEvent( "rednet_message", nReplyChannel, message, sProtocol ) + os.queueEvent("rednet_message", nReplyChannel, message, sProtocol) sent = true else -- Send on all open modems, to the target and to repeaters - for _, sModem in ipairs( peripheral.getNames() ) do - if isOpen( sModem ) then - peripheral.call( sModem, "transmit", nRecipient, nReplyChannel, tMessage ) - peripheral.call( sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage ) + for _, sModem in ipairs(peripheral.getNames()) do + if isOpen(sModem) then + peripheral.call(sModem, "transmit", nRecipient, nReplyChannel, tMessage) + peripheral.call(sModem, "transmit", CHANNEL_REPEAT, nReplyChannel, tMessage) sent = true end end @@ -158,9 +158,9 @@ end -- using @{rednet.receive} one can filter to only receive messages sent under a -- particular protocol. -- @see rednet.receive -function broadcast( message, sProtocol ) +function broadcast(message, sProtocol) expect(2, sProtocol, "string", "nil") - send( CHANNEL_BROADCAST, message, sProtocol ) + send(CHANNEL_BROADCAST, message, sProtocol) end --- Wait for a rednet message to be received, or until `nTimeout` seconds have @@ -177,7 +177,7 @@ end -- @treturn[2] nil If the timeout elapsed and no message was received. -- @see rednet.broadcast -- @see rednet.send -function receive( sProtocolFilter, nTimeout ) +function receive(sProtocolFilter, nTimeout) -- The parameters used to be ( nTimeout ), detect this case for backwards compatibility if type(sProtocolFilter) == "number" and nTimeout == nil then sProtocolFilter, nTimeout = nil, sProtocolFilter @@ -189,7 +189,7 @@ function receive( sProtocolFilter, nTimeout ) local timer = nil local sFilter = nil if nTimeout then - timer = os.startTimer( nTimeout ) + timer = os.startTimer(nTimeout) sFilter = nil else sFilter = "rednet_message" @@ -197,7 +197,7 @@ function receive( sProtocolFilter, nTimeout ) -- Wait for events while true do - local sEvent, p1, p2, p3 = os.pullEvent( sFilter ) + local sEvent, p1, p2, p3 = os.pullEvent(sFilter) if sEvent == "rednet_message" then -- Return the first matching rednet_message local nSenderID, message, sProtocol = p1, p2, p3 @@ -231,17 +231,17 @@ end -- @throws If trying to register a hostname which is reserved, or currently in use. -- @see rednet.unhost -- @see rednet.lookup -function host( sProtocol, sHostname ) +function host(sProtocol, sHostname) expect(1, sProtocol, "string") expect(2, sHostname, "string") if sHostname == "localhost" then - error( "Reserved hostname", 2 ) + error("Reserved hostname", 2) end - if tHostnames[ sProtocol ] ~= sHostname then - if lookup( sProtocol, sHostname ) ~= nil then - error( "Hostname in use", 2 ) + if tHostnames[sProtocol] ~= sHostname then + if lookup(sProtocol, sHostname) ~= nil then + error("Hostname in use", 2) end - tHostnames[ sProtocol ] = sHostname + tHostnames[sProtocol] = sHostname end end @@ -249,9 +249,9 @@ end --- respond to @{rednet.lookup} requests. -- -- @tparam string sProtocol The protocol to unregister your self from. -function unhost( sProtocol ) +function unhost(sProtocol) expect(1, sProtocol, "string") - tHostnames[ sProtocol ] = nil + tHostnames[sProtocol] = nil end --- Search the local rednet network for systems @{rednet.host|hosting} the @@ -268,7 +268,7 @@ end -- protocol, or @{nil} if none exist. -- @treturn[2] number|nil The computer ID with the provided hostname and protocol, -- or @{nil} if none exists. -function lookup( sProtocol, sHostname ) +function lookup(sProtocol, sHostname) expect(1, sProtocol, "string") expect(2, sHostname, "string", "nil") @@ -279,30 +279,30 @@ function lookup( sProtocol, sHostname ) end -- Check localhost first - if tHostnames[ sProtocol ] then + if tHostnames[sProtocol] then if sHostname == nil then - table.insert( tResults, os.getComputerID() ) - elseif sHostname == "localhost" or sHostname == tHostnames[ sProtocol ] then + table.insert(tResults, os.getComputerID()) + elseif sHostname == "localhost" or sHostname == tHostnames[sProtocol] then return os.getComputerID() end end if not isOpen() then if tResults then - return table.unpack( tResults ) + return table.unpack(tResults) end return nil end -- Broadcast a lookup packet - broadcast( { + broadcast({ sType = "lookup", sProtocol = sProtocol, sHostname = sHostname, - }, "dns" ) + }, "dns") -- Start a timer - local timer = os.startTimer( 2 ) + local timer = os.startTimer(2) -- Wait for events while true do @@ -313,7 +313,7 @@ function lookup( sProtocol, sHostname ) if sMessageProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup response" then if tMessage.sProtocol == sProtocol then if sHostname == nil then - table.insert( tResults, nSenderID ) + table.insert(tResults, nSenderID) elseif tMessage.sHostname == sHostname then return nSenderID end @@ -327,7 +327,7 @@ function lookup( sProtocol, sHostname ) end end if tResults then - return table.unpack( tResults ) + return table.unpack(tResults) end return nil end @@ -337,7 +337,7 @@ local bRunning = false --- @local function run() if bRunning then - error( "rednet is already running", 2 ) + error("rednet is already running", 2) end bRunning = true @@ -346,12 +346,12 @@ function run() if sEvent == "modem_message" then -- Got a modem message, process it and add it to the rednet event queue local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4 - if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then - if type( tMessage ) == "table" and tMessage.nMessageID then - if not tReceivedMessages[ tMessage.nMessageID ] then - tReceivedMessages[ tMessage.nMessageID ] = true - tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID - os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol ) + if isOpen(sModem) and (nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST) then + if type(tMessage) == "table" and tMessage.nMessageID then + if not tReceivedMessages[tMessage.nMessageID] then + tReceivedMessages[tMessage.nMessageID] = true + tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID + os.queueEvent("rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol) end end end @@ -360,23 +360,23 @@ function run() -- Got a rednet message (queued from above), respond to dns lookup local nSenderID, tMessage, sProtocol = p1, p2, p3 if sProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup" then - local sHostname = tHostnames[ tMessage.sProtocol ] + local sHostname = tHostnames[tMessage.sProtocol] if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then - rednet.send( nSenderID, { + rednet.send(nSenderID, { sType = "lookup response", sHostname = sHostname, sProtocol = tMessage.sProtocol, - }, "dns" ) + }, "dns") end end elseif sEvent == "timer" then -- Got a timer event, use it to clear the event queue local nTimer = p1 - local nMessage = tReceivedMessageTimeouts[ nTimer ] + local nMessage = tReceivedMessageTimeouts[nTimer] if nMessage then - tReceivedMessageTimeouts[ nTimer ] = nil - tReceivedMessages[ nMessage ] = nil + tReceivedMessageTimeouts[nTimer] = nil + tReceivedMessages[nMessage] = nil end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 50501bbaf..40044c1a0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -17,19 +17,19 @@ local tSettings = {} -- serialisable by @{textutils.serialize}. -- @throws If this value cannot be serialised -- @see settings.unset -function set( name, value ) +function set(name, value) expect(1, name, "string") expect(2, value, "number", "string", "boolean", "table") if type(value) == "table" then -- Ensure value is serializeable - value = textutils.unserialize( textutils.serialize(value) ) + value = textutils.unserialize(textutils.serialize(value)) end - tSettings[ name ] = value + tSettings[name] = value end local copy -function copy( value ) +function copy(value) if type(value) == "table" then local result = {} for k, v in pairs(value) do @@ -47,9 +47,9 @@ end -- @param[opt] default The value to use should there be pre-existing value for -- this setting. Defaults to `nil`. -- @return The setting's, or `default` if the setting has not been set. -function get( name, default ) +function get(name, default) expect(1, name, "string") - local result = tSettings[ name ] + local result = tSettings[name] if result ~= nil then return copy(result) else @@ -65,9 +65,9 @@ end -- @tparam string name The name of the setting to unset. -- @see settings.set -- @see settings.clear -function unset( name ) +function unset(name) expect(1, name, "string") - tSettings[ name ] = nil + tSettings[name] = nil end --- Removes the value of all settings. Equivalent to calling @{settings.unset} @@ -84,8 +84,8 @@ end -- settings. function getNames() local result = {} - for k in pairs( tSettings ) do - result[ #result + 1 ] = k + for k in pairs(tSettings) do + result[#result + 1] = k end table.sort(result) return result @@ -102,9 +102,9 @@ end -- corrupted. -- -- @see settings.save -function load( sPath ) +function load(sPath) expect(1, sPath, "string") - local file = fs.open( sPath, "r" ) + local file = fs.open(sPath, "r") if not file then return false end @@ -112,7 +112,7 @@ function load( sPath ) local sText = file.readAll() file.close() - local tFile = textutils.unserialize( sText ) + local tFile = textutils.unserialize(sText) if type(tFile) ~= "table" then return false end @@ -120,7 +120,7 @@ function load( sPath ) for k, v in pairs(tFile) do if type(k) == "string" and (type(v) == "string" or type(v) == "number" or type(v) == "boolean" or type(v) == "table") then - set( k, v ) + set(k, v) end end @@ -136,14 +136,14 @@ end -- @treturn boolean If the settings were successfully saved. -- -- @see settings.load -function save( sPath ) +function save(sPath) expect(1, sPath, "string") - local file = fs.open( sPath, "w" ) + local file = fs.open(sPath, "w") if not file then return false end - file.write( textutils.serialize( tSettings ) ) + file.write(textutils.serialize(tSettings)) file.close() return true diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua index 095fe1e9f..7461a137c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/term.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/term.lua @@ -8,9 +8,9 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect local native = term.native and term.native() or term local redirectTarget = native -local function wrap( _sFunction ) - return function( ... ) - return redirectTarget[ _sFunction ]( ... ) +local function wrap(_sFunction) + return function(...) + return redirectTarget[_sFunction](...) end end @@ -34,16 +34,16 @@ local term = _ENV -- @usage -- Redirect to a monitor on the right of the computer. -- term.redirect(peripheral.wrap("right")) -term.redirect = function( target ) +term.redirect = function(target) expect(1, target, "table") if target == term or target == _G.term then - error( "term is not a recommended redirect target, try term.current() instead", 2 ) + error("term is not a recommended redirect target, try term.current() instead", 2) end - for k, v in pairs( native ) do - if type( k ) == "string" and type( v ) == "function" then - if type( target[k] ) ~= "function" then + for k, v in pairs(native) do + if type(k) == "string" and type(v) == "function" then + if type(target[k]) ~= "function" then target[k] = function() - error( "Redirect object is missing method " .. k .. ".", 2 ) + error("Redirect object is missing method " .. k .. ".", 2) end end end @@ -81,8 +81,8 @@ for _, method in ipairs { "nativePaletteColor", "nativePaletteColour" } do native[method] = nil end -for k, v in pairs( native ) do - if type( k ) == "string" and type( v ) == "function" and rawget(term, k) == nil then - term[k] = wrap( k ) +for k, v in pairs(native) do + if type(k) == "string" and type(v) == "function" and rawget(term, k) == nil then + term[k] = wrap(k) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 4be4388f7..1ef4fb1ae 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -15,22 +15,22 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect -- Defaults to 20. -- @usage textutils.slowWrite("Hello, world!") -- @usage textutils.slowWrite("Hello, world!", 5) -function slowWrite( sText, nRate ) +function slowWrite(sText, nRate) expect(2, nRate, "number", "nil") nRate = nRate or 20 if nRate < 0 then - error( "Rate must be positive", 2 ) + error("Rate must be positive", 2) end local nSleep = 1 / nRate - sText = tostring( sText ) + sText = tostring(sText) local x, y = term.getCursorPos() local len = #sText for n = 1, len do - term.setCursorPos( x, y ) - sleep( nSleep ) - local nLines = write( string.sub( sText, 1, n ) ) + term.setCursorPos(x, y) + sleep(nSleep) + local nLines = write(string.sub(sText, 1, n)) local _, newY = term.getCursorPos() y = newY - nLines end @@ -46,8 +46,8 @@ end -- Defaults to 20. -- @usage textutils.slowPrint("Hello, world!") -- @usage textutils.slowPrint("Hello, world!", 5) -function slowPrint( sText, nRate ) - slowWrite( sText, nRate ) +function slowPrint(sText, nRate) + slowWrite(sText, nRate) print() end @@ -58,7 +58,7 @@ end -- clock (`18:30`) rather than a 12-hour one (`6:30 AM`) -- @treturn string The formatted time -- @usage textutils.formatTime(os.time()) -function formatTime( nTime, bTwentyFourHour ) +function formatTime(nTime, bTwentyFourHour) expect(1, nTime, "number") expect(2, bTwentyFourHour, "boolean", "nil") local sTOD = nil @@ -76,26 +76,26 @@ function formatTime( nTime, bTwentyFourHour ) local nHour = math.floor(nTime) local nMinute = math.floor((nTime - nHour) * 60) if sTOD then - return string.format( "%d:%02d %s", nHour, nMinute, sTOD ) + return string.format("%d:%02d %s", nHour, nMinute, sTOD) else - return string.format( "%d:%02d", nHour, nMinute ) + return string.format("%d:%02d", nHour, nMinute) end end -local function makePagedScroll( _term, _nFreeLines ) +local function makePagedScroll(_term, _nFreeLines) local nativeScroll = _term.scroll local nFreeLines = _nFreeLines or 0 - return function( _n ) + return function(_n) for _ = 1, _n do - nativeScroll( 1 ) + nativeScroll(1) if nFreeLines <= 0 then local _, h = _term.getSize() - _term.setCursorPos( 1, h ) - _term.write( "Press any key to continue" ) - os.pullEvent( "key" ) + _term.setCursorPos(1, h) + _term.write("Press any key to continue") + os.pullEvent("key") _term.clearLine() - _term.setCursorPos( 1, h ) + _term.setCursorPos(1, h) else nFreeLines = nFreeLines - 1 end @@ -120,38 +120,38 @@ end -- @usage -- local width, height = term.getSize() -- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2) -function pagedPrint( _sText, _nFreeLines ) +function pagedPrint(_sText, _nFreeLines) expect(2, _nFreeLines, "number", "nil") -- Setup a redirector local oldTerm = term.current() local newTerm = {} - for k, v in pairs( oldTerm ) do + for k, v in pairs(oldTerm) do newTerm[k] = v end - newTerm.scroll = makePagedScroll( oldTerm, _nFreeLines ) - term.redirect( newTerm ) + newTerm.scroll = makePagedScroll(oldTerm, _nFreeLines) + term.redirect(newTerm) -- Print the text local result - local ok, err = pcall( function() + local ok, err = pcall(function() if _sText ~= nil then - result = print( _sText ) + result = print(_sText) else result = print() end - end ) + end) -- Removed the redirector - term.redirect( oldTerm ) + term.redirect(oldTerm) -- Propogate errors if not ok then - error( err, 0 ) + error(err, 0) end return result end -local function tabulateCommon( bPaged, ... ) +local function tabulateCommon(bPaged, ...) local tAll = table.pack(...) for i = 1, tAll.n do expect(i, tAll[i], "number", "table") @@ -159,17 +159,17 @@ local function tabulateCommon( bPaged, ... ) local w, h = term.getSize() local nMaxLen = w / 8 - for n, t in ipairs( tAll ) do + for n, t in ipairs(tAll) do if type(t) == "table" then for nu, sItem in pairs(t) do - if type( sItem ) ~= "string" then - error( "bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type( sItem ) .. ")", 3 ) + if type(sItem) ~= "string" then + error("bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type(sItem) .. ")", 3) end - nMaxLen = math.max( #sItem + 1, nMaxLen ) + nMaxLen = math.max(#sItem + 1, nMaxLen) end end end - local nCols = math.floor( w / nMaxLen ) + local nCols = math.floor(w / nMaxLen) local nLines = 0 local function newLine() if bPaged and nLines >= h - 3 then @@ -180,9 +180,9 @@ local function tabulateCommon( bPaged, ... ) nLines = nLines + 1 end - local function drawCols( _t ) + local function drawCols(_t) local nCol = 1 - for _, s in ipairs( _t ) do + for _, s in ipairs(_t) do if nCol > nCols then nCol = 1 newLine() @@ -190,20 +190,20 @@ local function tabulateCommon( bPaged, ... ) local cx, cy = term.getCursorPos() cx = 1 + (nCol - 1) * nMaxLen - term.setCursorPos( cx, cy ) - term.write( s ) + term.setCursorPos(cx, cy) + term.write(s) nCol = nCol + 1 end print() end - for _, t in ipairs( tAll ) do + for _, t in ipairs(tAll) do if type(t) == "table" then if #t > 0 then - drawCols( t ) + drawCols(t) end elseif type(t) == "number" then - term.setTextColor( t ) + term.setTextColor(t) end end end @@ -218,8 +218,8 @@ end -- -- @tparam {string...}|number ... The rows and text colors to display. -- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" }) -function tabulate( ... ) - return tabulateCommon( false, ... ) +function tabulate(...) + return tabulateCommon(false, ...) end --- Prints tables in a structured form, stopping and prompting for input should @@ -232,39 +232,39 @@ end -- @usage textutils.tabulate(colors.orange, { "1", "2", "3" }, colors.lightBlue, { "A", "B", "C" }) -- @see textutils.tabulate -- @see textutils.pagedPrint -function pagedTabulate( ... ) - return tabulateCommon( true, ... ) +function pagedTabulate(...) + return tabulateCommon(true, ...) end local g_tLuaKeywords = { - [ "and" ] = true, - [ "break" ] = true, - [ "do" ] = true, - [ "else" ] = true, - [ "elseif" ] = true, - [ "end" ] = true, - [ "false" ] = true, - [ "for" ] = true, - [ "function" ] = true, - [ "if" ] = true, - [ "in" ] = true, - [ "local" ] = true, - [ "nil" ] = true, - [ "not" ] = true, - [ "or" ] = true, - [ "repeat" ] = true, - [ "return" ] = true, - [ "then" ] = true, - [ "true" ] = true, - [ "until" ] = true, - [ "while" ] = true, + ["and"] = true, + ["break"] = true, + ["do"] = true, + ["else"] = true, + ["elseif"] = true, + ["end"] = true, + ["false"] = true, + ["for"] = true, + ["function"] = true, + ["if"] = true, + ["in"] = true, + ["local"] = true, + ["nil"] = true, + ["not"] = true, + ["or"] = true, + ["repeat"] = true, + ["return"] = true, + ["then"] = true, + ["true"] = true, + ["until"] = true, + ["while"] = true, } -local function serializeImpl( t, tTracking, sIndent ) +local function serializeImpl(t, tTracking, sIndent) local sType = type(t) if sType == "table" then if tTracking[t] ~= nil then - error( "Cannot serialize table with recursive entries", 0 ) + error("Cannot serialize table with recursive entries", 0) end tTracking[t] = true @@ -278,15 +278,15 @@ local function serializeImpl( t, tTracking, sIndent ) local tSeen = {} for k, v in ipairs(t) do tSeen[k] = true - sResult = sResult .. sSubIndent .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" + sResult = sResult .. sSubIndent .. serializeImpl(v, tTracking, sSubIndent) .. ",\n" end for k, v in pairs(t) do if not tSeen[k] then local sEntry - if type(k) == "string" and not g_tLuaKeywords[k] and string.match( k, "^[%a_][%a%d_]*$" ) then - sEntry = k .. " = " .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" + if type(k) == "string" and not g_tLuaKeywords[k] and string.match(k, "^[%a_][%a%d_]*$") then + sEntry = k .. " = " .. serializeImpl(v, tTracking, sSubIndent) .. ",\n" else - sEntry = "[ " .. serializeImpl( k, tTracking, sSubIndent ) .. " ] = " .. serializeImpl( v, tTracking, sSubIndent ) .. ",\n" + sEntry = "[ " .. serializeImpl(k, tTracking, sSubIndent) .. " ] = " .. serializeImpl(v, tTracking, sSubIndent) .. ",\n" end sResult = sResult .. sSubIndent .. sEntry end @@ -296,13 +296,13 @@ local function serializeImpl( t, tTracking, sIndent ) end elseif sType == "string" then - return string.format( "%q", t ) + return string.format("%q", t) elseif sType == "number" or sType == "boolean" or sType == "nil" then return tostring(t) else - error( "Cannot serialize type " .. sType, 0 ) + error("Cannot serialize type " .. sType, 0) end end @@ -320,14 +320,14 @@ empty_json_array = setmetatable({}, { end, }) -local function serializeJSONImpl( t, tTracking, bNBTStyle ) +local function serializeJSONImpl(t, tTracking, bNBTStyle) local sType = type(t) if t == empty_json_array then return "[]" elseif sType == "table" then if tTracking[t] ~= nil then - error( "Cannot serialize table with recursive entries", 0 ) + error("Cannot serialize table with recursive entries", 0) end tTracking[t] = true @@ -344,9 +344,9 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) if type(k) == "string" then local sEntry if bNBTStyle then - sEntry = tostring(k) .. ":" .. serializeJSONImpl( v, tTracking, bNBTStyle ) + sEntry = tostring(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) else - sEntry = string.format( "%q", k ) .. ":" .. serializeJSONImpl( v, tTracking, bNBTStyle ) + sEntry = string.format("%q", k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) end if nObjectSize == 0 then sObjectResult = sObjectResult .. sEntry @@ -357,7 +357,7 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) end end for _, v in ipairs(t) do - local sEntry = serializeJSONImpl( v, tTracking, bNBTStyle ) + local sEntry = serializeJSONImpl(v, tTracking, bNBTStyle) if nArraySize == 0 then sArrayResult = sArrayResult .. sEntry else @@ -375,13 +375,13 @@ local function serializeJSONImpl( t, tTracking, bNBTStyle ) end elseif sType == "string" then - return string.format( "%q", t ) + return string.format("%q", t) elseif sType == "number" or sType == "boolean" then return tostring(t) else - error( "Cannot serialize type " .. sType, 0 ) + error("Cannot serialize type " .. sType, 0) end end @@ -394,9 +394,9 @@ end -- @throws If the object contains a value which cannot be -- serialised. This includes functions and tables which appear multiple -- times. -function serialize( t ) +function serialize(t) local tTracking = {} - return serializeImpl( t, tTracking, "" ) + return serializeImpl(t, tTracking, "") end serialise = serialize -- GB version @@ -408,11 +408,11 @@ serialise = serialize -- GB version -- @tparam string s The serialised string to deserialise. -- @return[1] The deserialised object -- @treturn[2] nil If the object could not be deserialised. -function unserialize( s ) +function unserialize(s) expect(1, s, "string") - local func = load( "return " .. s, "unserialize", "t", {} ) + local func = load("return " .. s, "unserialize", "t", {}) if func then - local ok, result = pcall( func ) + local ok, result = pcall(func) if ok then return result end @@ -440,11 +440,11 @@ unserialise = unserialize -- GB version -- serialised. This includes functions and tables which appear multiple -- times. -- @usage textutils.serializeJSON({ values = { 1, "2", true } }) -function serializeJSON( t, bNBTStyle ) +function serializeJSON(t, bNBTStyle) expect(1, t, "table", "string", "number", "boolean") expect(2, bNBTStyle, "boolean", "nil") local tTracking = {} - return serializeJSONImpl( t, tTracking, bNBTStyle or false ) + return serializeJSONImpl(t, tTracking, bNBTStyle or false) end serialiseJSON = serializeJSON -- GB version @@ -454,7 +454,7 @@ serialiseJSON = serializeJSON -- GB version -- @tparam string str The string to encode -- @treturn string The encoded string. -- @usage print("https://example.com/?view=" .. textutils.urlEncode(read())) -function urlEncode( str ) +function urlEncode(str) expect(1, str, "string") if str then str = string.gsub(str, "\n", "\r\n") @@ -466,8 +466,8 @@ function urlEncode( str ) else -- Non-ASCII (encode as UTF-8) return - string.format("%%%02X", 192 + bit32.band( bit32.arshift(n, 6), 31 )) .. - string.format("%%%02X", 128 + bit32.band( n, 63 )) + string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) .. + string.format("%%%02X", 128 + bit32.band(n, 63)) end end) str = string.gsub(str, " ", "+") @@ -493,30 +493,30 @@ local tEmpty = {} -- @see shell.setCompletionFunction -- @see read -- @usage textutils.complete( "pa", getfenv() ) -function complete( sSearchText, tSearchTable ) +function complete(sSearchText, tSearchTable) expect(1, sSearchText, "string") expect(2, tSearchTable, "table", "nil") if g_tLuaKeywords[sSearchText] then return tEmpty end local nStart = 1 - local nDot = string.find( sSearchText, ".", nStart, true ) + local nDot = string.find(sSearchText, ".", nStart, true) local tTable = tSearchTable or _ENV while nDot do - local sPart = string.sub( sSearchText, nStart, nDot - 1 ) - local value = tTable[ sPart ] - if type( value ) == "table" then + local sPart = string.sub(sSearchText, nStart, nDot - 1) + local value = tTable[sPart] + if type(value) == "table" then tTable = value nStart = nDot + 1 - nDot = string.find( sSearchText, ".", nStart, true ) + nDot = string.find(sSearchText, ".", nStart, true) else return tEmpty end end - local nColon = string.find( sSearchText, ":", nStart, true ) + local nColon = string.find(sSearchText, ":", nStart, true) if nColon then - local sPart = string.sub( sSearchText, nStart, nColon - 1 ) - local value = tTable[ sPart ] - if type( value ) == "table" then + local sPart = string.sub(sSearchText, nStart, nColon - 1) + local value = tTable[sPart] + if type(value) == "table" then tTable = value nStart = nColon + 1 else @@ -524,24 +524,24 @@ function complete( sSearchText, tSearchTable ) end end - local sPart = string.sub( sSearchText, nStart ) + local sPart = string.sub(sSearchText, nStart) local nPartLength = #sPart local tResults = {} local tSeen = {} while tTable do - for k, v in pairs( tTable ) do + for k, v in pairs(tTable) do if not tSeen[k] and type(k) == "string" then - if string.find( k, sPart, 1, true ) == 1 then - if not g_tLuaKeywords[k] and string.match( k, "^[%a_][%a%d_]*$" ) then - local sResult = string.sub( k, nPartLength + 1 ) + if string.find(k, sPart, 1, true) == 1 then + if not g_tLuaKeywords[k] and string.match(k, "^[%a_][%a%d_]*$") then + local sResult = string.sub(k, nPartLength + 1) if nColon then if type(v) == "function" then - table.insert( tResults, sResult .. "(" ) + table.insert(tResults, sResult .. "(") elseif type(v) == "table" then - local tMetatable = getmetatable( v ) - if tMetatable and ( type( tMetatable.__call ) == "function" or type( tMetatable.__call ) == "table" ) then - table.insert( tResults, sResult .. "(" ) + local tMetatable = getmetatable(v) + if tMetatable and (type(tMetatable.__call) == "function" or type(tMetatable.__call) == "table") then + table.insert(tResults, sResult .. "(") end end else @@ -550,21 +550,21 @@ function complete( sSearchText, tSearchTable ) elseif type(v) == "table" and next(v) ~= nil then sResult = sResult .. "." end - table.insert( tResults, sResult ) + table.insert(tResults, sResult) end end end end tSeen[k] = true end - local tMetatable = getmetatable( tTable ) - if tMetatable and type( tMetatable.__index ) == "table" then + local tMetatable = getmetatable(tTable) + if tMetatable and type(tMetatable.__index) == "table" then tTable = tMetatable.__index else tTable = nil end end - table.sort( tResults ) + table.sort(tResults) return tResults end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua index 9b5fab369..f52645524 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua @@ -3,18 +3,18 @@ -- @module turtle if not turtle then - error( "Cannot load turtle API on computer", 2 ) + error("Cannot load turtle API on computer", 2) end native = turtle.native or turtle -local function addCraftMethod( object ) - if peripheral.getType( "left" ) == "workbench" then - object.craft = function( ... ) - return peripheral.call( "left", "craft", ... ) +local function addCraftMethod(object) + if peripheral.getType("left") == "workbench" then + object.craft = function(...) + return peripheral.call("left", "craft", ...) end - elseif peripheral.getType( "right" ) == "workbench" then - object.craft = function( ... ) - return peripheral.call( "right", "craft", ... ) + elseif peripheral.getType("right") == "workbench" then + object.craft = function(...) + return peripheral.call("right", "craft", ...) end else object.craft = nil @@ -23,15 +23,15 @@ end -- Put commands into environment table local env = _ENV -for k, v in pairs( native ) do +for k, v in pairs(native) do if k == "equipLeft" or k == "equipRight" then - env[k] = function( ... ) - local result, err = v( ... ) - addCraftMethod( turtle ) + env[k] = function(...) + local result, err = v(...) + addCraftMethod(turtle) return result, err end else env[k] = v end end -addCraftMethod( env ) +addCraftMethod(env) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua index e19937bba..05dab327e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/vector.lua @@ -113,7 +113,7 @@ local vector = { -- @tparam Vector self This vector. -- @treturn number The length of this vector. length = function(self) - return math.sqrt( self.x * self.x + self.y * self.y + self.z * self.z ) + return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z) end, --- Divide this vector by its length, producing with the same direction, but @@ -123,7 +123,7 @@ local vector = { -- @treturn Vector The normalised vector -- @usage v:normalize() normalize = function(self) - return self:mul( 1 / self:length() ) + return self:mul(1 / self:length()) end, --- Construct a vector with each dimension rounded to the nearest value. diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 5617c2175..aa6e5aab6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -30,22 +30,22 @@ local expect = dofile("rom/modules/main/cc/expect.lua").expect local tHex = { - [ colors.white ] = "0", - [ colors.orange ] = "1", - [ colors.magenta ] = "2", - [ colors.lightBlue ] = "3", - [ colors.yellow ] = "4", - [ colors.lime ] = "5", - [ colors.pink ] = "6", - [ colors.gray ] = "7", - [ colors.lightGray ] = "8", - [ colors.cyan ] = "9", - [ colors.purple ] = "a", - [ colors.blue ] = "b", - [ colors.brown ] = "c", - [ colors.green ] = "d", - [ colors.red ] = "e", - [ colors.black ] = "f", + [colors.white] = "0", + [colors.orange] = "1", + [colors.magenta] = "2", + [colors.lightBlue] = "3", + [colors.yellow] = "4", + [colors.lime] = "5", + [colors.pink] = "6", + [colors.gray] = "7", + [colors.lightGray] = "8", + [colors.cyan] = "9", + [colors.purple] = "a", + [colors.blue] = "b", + [colors.brown] = "c", + [colors.green] = "d", + [colors.red] = "e", + [colors.black] = "f", } local type = type @@ -70,7 +70,7 @@ local string_sub = string.sub -- @tparam[opt] boolean bStartVisible Whether this window is visible by -- default. Defaults to `true`. -- @treturn Window The constructed window -function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) +function create(parent, nX, nY, nWidth, nHeight, bStartVisible) expect(1, parent, "table") expect(2, nX, "number") expect(3, nY, "number") @@ -79,21 +79,21 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) expect(6, bStartVisible, "boolean", "nil") if parent == term then - error( "term is not a recommended window parent, try term.current() instead", 2 ) + error("term is not a recommended window parent, try term.current() instead", 2) end local sEmptySpaceLine local tEmptyColorLines = {} - local function createEmptyLines( nWidth ) - sEmptySpaceLine = string_rep( " ", nWidth ) + local function createEmptyLines(nWidth) + sEmptySpaceLine = string_rep(" ", nWidth) for n = 0, 15 do local nColor = 2 ^ n local sHex = tHex[nColor] - tEmptyColorLines[nColor] = string_rep( sHex, nWidth ) + tEmptyColorLines[nColor] = string_rep(sHex, nWidth) end end - createEmptyLines( nWidth ) + createEmptyLines(nWidth) -- Setup local bVisible = bStartVisible ~= false @@ -106,8 +106,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local tPalette = {} do local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for y = 1, nHeight do tLines[y] = { text = sEmptyText, @@ -118,7 +118,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) for i = 0, 15 do local c = 2 ^ i - tPalette[c] = { parent.getPaletteColour( c ) } + tPalette[c] = { parent.getPaletteColour(c) } end end @@ -126,45 +126,45 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local function updateCursorPos() if nCursorX >= 1 and nCursorY >= 1 and nCursorX <= nWidth and nCursorY <= nHeight then - parent.setCursorPos( nX + nCursorX - 1, nY + nCursorY - 1 ) + parent.setCursorPos(nX + nCursorX - 1, nY + nCursorY - 1) else - parent.setCursorPos( 0, 0 ) + parent.setCursorPos(0, 0) end end local function updateCursorBlink() - parent.setCursorBlink( bCursorBlink ) + parent.setCursorBlink(bCursorBlink) end local function updateCursorColor() - parent.setTextColor( nTextColor ) + parent.setTextColor(nTextColor) end - local function redrawLine( n ) - local tLine = tLines[ n ] - parent.setCursorPos( nX, nY + n - 1 ) - parent.blit( tLine.text, tLine.textColor, tLine.backgroundColor ) + local function redrawLine(n) + local tLine = tLines[n] + parent.setCursorPos(nX, nY + n - 1) + parent.blit(tLine.text, tLine.textColor, tLine.backgroundColor) end local function redraw() for n = 1, nHeight do - redrawLine( n ) + redrawLine(n) end end local function updatePalette() - for k, v in pairs( tPalette ) do - parent.setPaletteColour( k, v[1], v[2], v[3] ) + for k, v in pairs(tPalette) do + parent.setPaletteColour(k, v[1], v[2], v[3]) end end - local function internalBlit( sText, sTextColor, sBackgroundColor ) + local function internalBlit(sText, sTextColor, sBackgroundColor) local nStart = nCursorX local nEnd = nStart + #sText - 1 if nCursorY >= 1 and nCursorY <= nHeight then if nStart <= nWidth and nEnd >= 1 then -- Modify line - local tLine = tLines[ nCursorY ] + local tLine = tLines[nCursorY] if nStart == 1 and nEnd == nWidth then tLine.text = sText tLine.textColor = sTextColor @@ -174,14 +174,14 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) if nStart < 1 then local nClipStart = 1 - nStart + 1 local nClipEnd = nWidth - nStart + 1 - sClippedText = string_sub( sText, nClipStart, nClipEnd ) - sClippedTextColor = string_sub( sTextColor, nClipStart, nClipEnd ) - sClippedBackgroundColor = string_sub( sBackgroundColor, nClipStart, nClipEnd ) + sClippedText = string_sub(sText, nClipStart, nClipEnd) + sClippedTextColor = string_sub(sTextColor, nClipStart, nClipEnd) + sClippedBackgroundColor = string_sub(sBackgroundColor, nClipStart, nClipEnd) elseif nEnd > nWidth then local nClipEnd = nWidth - nStart + 1 - sClippedText = string_sub( sText, 1, nClipEnd ) - sClippedTextColor = string_sub( sTextColor, 1, nClipEnd ) - sClippedBackgroundColor = string_sub( sBackgroundColor, 1, nClipEnd ) + sClippedText = string_sub(sText, 1, nClipEnd) + sClippedTextColor = string_sub(sTextColor, 1, nClipEnd) + sClippedBackgroundColor = string_sub(sBackgroundColor, 1, nClipEnd) else sClippedText = sText sClippedTextColor = sTextColor @@ -194,9 +194,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) local sNewText, sNewTextColor, sNewBackgroundColor if nStart > 1 then local nOldEnd = nStart - 1 - sNewText = string_sub( sOldText, 1, nOldEnd ) .. sClippedText - sNewTextColor = string_sub( sOldTextColor, 1, nOldEnd ) .. sClippedTextColor - sNewBackgroundColor = string_sub( sOldBackgroundColor, 1, nOldEnd ) .. sClippedBackgroundColor + sNewText = string_sub(sOldText, 1, nOldEnd) .. sClippedText + sNewTextColor = string_sub(sOldTextColor, 1, nOldEnd) .. sClippedTextColor + sNewBackgroundColor = string_sub(sOldBackgroundColor, 1, nOldEnd) .. sClippedBackgroundColor else sNewText = sClippedText sNewTextColor = sClippedTextColor @@ -204,9 +204,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end if nEnd < nWidth then local nOldStart = nEnd + 1 - sNewText = sNewText .. string_sub( sOldText, nOldStart, nWidth ) - sNewTextColor = sNewTextColor .. string_sub( sOldTextColor, nOldStart, nWidth ) - sNewBackgroundColor = sNewBackgroundColor .. string_sub( sOldBackgroundColor, nOldStart, nWidth ) + sNewText = sNewText .. string_sub(sOldText, nOldStart, nWidth) + sNewTextColor = sNewTextColor .. string_sub(sOldTextColor, nOldStart, nWidth) + sNewBackgroundColor = sNewBackgroundColor .. string_sub(sOldBackgroundColor, nOldStart, nWidth) end tLine.text = sNewText @@ -216,7 +216,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) -- Redraw line if bVisible then - redrawLine( nCursorY ) + redrawLine(nCursorY) end end end @@ -234,25 +234,25 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) -- @type Window local window = {} - function window.write( sText ) - sText = tostring( sText ) - internalBlit( sText, string_rep( tHex[ nTextColor ], #sText ), string_rep( tHex[ nBackgroundColor ], #sText ) ) + function window.write(sText) + sText = tostring(sText) + internalBlit(sText, string_rep(tHex[nTextColor], #sText), string_rep(tHex[nBackgroundColor], #sText)) end - function window.blit( sText, sTextColor, sBackgroundColor ) + function window.blit(sText, sTextColor, sBackgroundColor) if type(sText) ~= "string" then expect(1, sText, "string") end if type(sTextColor) ~= "string" then expect(2, sTextColor, "string") end if type(sBackgroundColor) ~= "string" then expect(3, sBackgroundColor, "string") end if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then - error( "Arguments must be the same length", 2 ) + error("Arguments must be the same length", 2) end - internalBlit( sText, sTextColor, sBackgroundColor ) + internalBlit(sText, sTextColor, sBackgroundColor) end function window.clear() local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for y = 1, nHeight do tLines[y] = { text = sEmptyText, @@ -270,15 +270,15 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) function window.clearLine() if nCursorY >= 1 and nCursorY <= nHeight then local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] - tLines[ nCursorY ] = { + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] + tLines[nCursorY] = { text = sEmptyText, textColor = sEmptyTextColor, backgroundColor = sEmptyBackgroundColor, } if bVisible then - redrawLine( nCursorY ) + redrawLine(nCursorY) updateCursorColor() updateCursorPos() end @@ -289,17 +289,17 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nCursorX, nCursorY end - function window.setCursorPos( x, y ) + function window.setCursorPos(x, y) if type(x) ~= "number" then expect(1, x, "number") end if type(y) ~= "number" then expect(2, y, "number") end - nCursorX = math.floor( x ) - nCursorY = math.floor( y ) + nCursorX = math.floor(x) + nCursorY = math.floor(y) if bVisible then updateCursorPos() end end - function window.setCursorBlink( blink ) + function window.setCursorBlink(blink) if type(blink) ~= "boolean" then expect(1, blink, "boolean") end bCursorBlink = blink if bVisible then @@ -323,10 +323,10 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return isColor() end - local function setTextColor( color ) + local function setTextColor(color) if type(color) ~= "number" then expect(1, color, "number") end if tHex[color] == nil then - error( "Invalid color (got " .. color .. ")" , 2 ) + error("Invalid color (got " .. color .. ")" , 2) end nTextColor = color @@ -338,50 +338,50 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) window.setTextColor = setTextColor window.setTextColour = setTextColor - function window.setPaletteColour( colour, r, g, b ) + function window.setPaletteColour(colour, r, g, b) if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then - error( "Invalid color (got " .. colour .. ")" , 2 ) + error("Invalid color (got " .. colour .. ")" , 2) end local tCol if type(r) == "number" and g == nil and b == nil then - tCol = { colours.unpackRGB( r ) } - tPalette[ colour ] = tCol + tCol = { colours.unpackRGB(r) } + tPalette[colour] = tCol else if type(r) ~= "number" then expect(2, r, "number") end if type(g) ~= "number" then expect(3, g, "number") end if type(b) ~= "number" then expect(4, b, "number") end - tCol = tPalette[ colour ] + tCol = tPalette[colour] tCol[1] = r tCol[2] = g tCol[3] = b end if bVisible then - return parent.setPaletteColour( colour, tCol[1], tCol[2], tCol[3] ) + return parent.setPaletteColour(colour, tCol[1], tCol[2], tCol[3]) end end window.setPaletteColor = window.setPaletteColour - function window.getPaletteColour( colour ) + function window.getPaletteColour(colour) if type(colour) ~= "number" then expect(1, colour, "number") end if tHex[colour] == nil then - error( "Invalid color (got " .. colour .. ")" , 2 ) + error("Invalid color (got " .. colour .. ")" , 2) end - local tCol = tPalette[ colour ] + local tCol = tPalette[colour] return tCol[1], tCol[2], tCol[3] end window.getPaletteColor = window.getPaletteColour - local function setBackgroundColor( color ) + local function setBackgroundColor(color) if type(color) ~= "number" then expect(1, color, "number") end if tHex[color] == nil then - error( "Invalid color (got " .. color .. ")", 2 ) + error("Invalid color (got " .. color .. ")", 2) end nBackgroundColor = color end @@ -393,13 +393,13 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nWidth, nHeight end - function window.scroll( n ) + function window.scroll(n) if type(n) ~= "number" then expect(1, n, "number") end if n ~= 0 then local tNewLines = {} local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for newY = 1, nHeight do local y = newY + n if y >= 1 and y <= nHeight then @@ -448,7 +448,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) end -- Other functions - function window.setVisible( bVis ) + function window.setVisible(bVis) if type(bVis) ~= "boolean" then expect(1, bVis, "boolean") end if bVisible ~= bVis then bVisible = bVis @@ -480,7 +480,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) return nX, nY end - function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight, newParent ) + function window.reposition(nNewX, nNewY, nNewWidth, nNewHeight, newParent) if type(nNewX) ~= "number" then expect(1, nNewX, "number") end if type(nNewY) ~= "number" then expect(2, nNewY, "number") end if nNewWidth ~= nil or nNewHeight ~= nil then @@ -496,10 +496,10 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) if nNewWidth and nNewHeight then local tNewLines = {} - createEmptyLines( nNewWidth ) + createEmptyLines(nNewWidth) local sEmptyText = sEmptySpaceLine - local sEmptyTextColor = tEmptyColorLines[ nTextColor ] - local sEmptyBackgroundColor = tEmptyColorLines[ nBackgroundColor ] + local sEmptyTextColor = tEmptyColorLines[nTextColor] + local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] for y = 1, nNewHeight do if y > nHeight then tNewLines[y] = { @@ -513,15 +513,15 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible ) tNewLines[y] = tOldLine elseif nNewWidth < nWidth then tNewLines[y] = { - text = string_sub( tOldLine.text, 1, nNewWidth ), - textColor = string_sub( tOldLine.textColor, 1, nNewWidth ), - backgroundColor = string_sub( tOldLine.backgroundColor, 1, nNewWidth ), + text = string_sub(tOldLine.text, 1, nNewWidth), + textColor = string_sub(tOldLine.textColor, 1, nNewWidth), + backgroundColor = string_sub(tOldLine.backgroundColor, 1, nNewWidth), } else tNewLines[y] = { - text = tOldLine.text .. string_sub( sEmptyText, nWidth + 1, nNewWidth ), - textColor = tOldLine.textColor .. string_sub( sEmptyTextColor, nWidth + 1, nNewWidth ), - backgroundColor = tOldLine.backgroundColor .. string_sub( sEmptyBackgroundColor, nWidth + 1, nNewWidth ), + text = tOldLine.text .. string_sub(sEmptyText, nWidth + 1, nNewWidth), + textColor = tOldLine.textColor .. string_sub(sEmptyTextColor, nWidth + 1, nNewWidth), + backgroundColor = tOldLine.backgroundColor .. string_sub(sEmptyBackgroundColor, nWidth + 1, nNewWidth), } end end diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua index 1791a29a0..2f4c648b6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua @@ -37,9 +37,9 @@ local function expect(index, value, ...) end if name then - error( ("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3 ) + error(("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3) else - error( ("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3 ) + error(("bad argument #%d (expected %s, got %s)"):format(index, type_names, t), 3) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua index 5a34ad389..95b0c76fa 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -320,11 +320,11 @@ end Doc.__tostring = render --- @local local keywords = { - [ "and" ] = true, [ "break" ] = true, [ "do" ] = true, [ "else" ] = true, - [ "elseif" ] = true, [ "end" ] = true, [ "false" ] = true, [ "for" ] = true, - [ "function" ] = true, [ "if" ] = true, [ "in" ] = true, [ "local" ] = true, - [ "nil" ] = true, [ "not" ] = true, [ "or" ] = true, [ "repeat" ] = true, [ "return" ] = true, - [ "then" ] = true, [ "true" ] = true, [ "until" ] = true, [ "while" ] = true, + ["and"] = true, ["break"] = true, ["do"] = true, ["else"] = true, + ["elseif"] = true, ["end"] = true, ["false"] = true, ["for"] = true, + ["function"] = true, ["if"] = true, ["in"] = true, ["local"] = true, + ["nil"] = true, ["not"] = true, ["or"] = true, ["repeat"] = true, ["return"] = true, + ["then"] = true, ["true"] = true, ["until"] = true, ["while"] = true, } local comma = text(",") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua index 806a128cd..907e9f7aa 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua @@ -1,12 +1,12 @@ if not shell.openTab then - printError( "Requires multishell" ) + printError("Requires multishell") return end local tArgs = { ... } if #tArgs > 0 then - shell.openTab( table.unpack( tArgs ) ) + shell.openTab(table.unpack(tArgs)) else - shell.openTab( "shell" ) + shell.openTab("shell") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua index 754fdbf8e..efc7832eb 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua @@ -1,18 +1,18 @@ if not shell.openTab then - printError( "Requires multishell" ) + printError("Requires multishell") return end local tArgs = { ... } if #tArgs > 0 then - local nTask = shell.openTab( table.unpack( tArgs ) ) + local nTask = shell.openTab(table.unpack(tArgs)) if nTask then - shell.switchTab( nTask ) + shell.switchTab(nTask) end else - local nTask = shell.openTab( "shell" ) + local nTask = shell.openTab("shell") if nTask then - shell.switchTab( nTask ) + shell.switchTab(nTask) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index 75dd3b3da..c675f2dc6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -12,84 +12,84 @@ local bWindowsResized = false local nScrollPos = 1 local bScrollRight = false -local function selectProcess( n ) +local function selectProcess(n) if nCurrentProcess ~= n then if nCurrentProcess then - local tOldProcess = tProcesses[ nCurrentProcess ] - tOldProcess.window.setVisible( false ) + local tOldProcess = tProcesses[nCurrentProcess] + tOldProcess.window.setVisible(false) end nCurrentProcess = n if nCurrentProcess then - local tNewProcess = tProcesses[ nCurrentProcess ] - tNewProcess.window.setVisible( true ) + local tNewProcess = tProcesses[nCurrentProcess] + tNewProcess.window.setVisible(true) tNewProcess.bInteracted = true end end end -local function setProcessTitle( n, sTitle ) - tProcesses[ n ].sTitle = sTitle +local function setProcessTitle(n, sTitle) + tProcesses[n].sTitle = sTitle end -local function resumeProcess( nProcess, sEvent, ... ) - local tProcess = tProcesses[ nProcess ] +local function resumeProcess(nProcess, sEvent, ...) + local tProcess = tProcesses[nProcess] local sFilter = tProcess.sFilter if sFilter == nil or sFilter == sEvent or sEvent == "terminate" then local nPreviousProcess = nRunningProcess nRunningProcess = nProcess - term.redirect( tProcess.terminal ) - local ok, result = coroutine.resume( tProcess.co, sEvent, ... ) + term.redirect(tProcess.terminal) + local ok, result = coroutine.resume(tProcess.co, sEvent, ...) tProcess.terminal = term.current() if ok then tProcess.sFilter = result else - printError( result ) + printError(result) end nRunningProcess = nPreviousProcess end end -local function launchProcess( bFocus, tProgramEnv, sProgramPath, ... ) - local tProgramArgs = table.pack( ... ) +local function launchProcess(bFocus, tProgramEnv, sProgramPath, ...) + local tProgramArgs = table.pack(...) local nProcess = #tProcesses + 1 local tProcess = {} - tProcess.sTitle = fs.getName( sProgramPath ) + tProcess.sTitle = fs.getName(sProgramPath) if bShowMenu then - tProcess.window = window.create( parentTerm, 1, 2, w, h - 1, false ) + tProcess.window = window.create(parentTerm, 1, 2, w, h - 1, false) else - tProcess.window = window.create( parentTerm, 1, 1, w, h, false ) + tProcess.window = window.create(parentTerm, 1, 1, w, h, false) end - tProcess.co = coroutine.create( function() - os.run( tProgramEnv, sProgramPath, table.unpack( tProgramArgs, 1, tProgramArgs.n ) ) + tProcess.co = coroutine.create(function() + os.run(tProgramEnv, sProgramPath, table.unpack(tProgramArgs, 1, tProgramArgs.n)) if not tProcess.bInteracted then - term.setCursorBlink( false ) - print( "Press any key to continue" ) - os.pullEvent( "char" ) + term.setCursorBlink(false) + print("Press any key to continue") + os.pullEvent("char") end - end ) + end) tProcess.sFilter = nil tProcess.terminal = tProcess.window tProcess.bInteracted = false - tProcesses[ nProcess ] = tProcess + tProcesses[nProcess] = tProcess if bFocus then - selectProcess( nProcess ) + selectProcess(nProcess) end - resumeProcess( nProcess ) + resumeProcess(nProcess) return nProcess end -local function cullProcess( nProcess ) - local tProcess = tProcesses[ nProcess ] - if coroutine.status( tProcess.co ) == "dead" then +local function cullProcess(nProcess) + local tProcess = tProcesses[nProcess] + if coroutine.status(tProcess.co) == "dead" then if nCurrentProcess == nProcess then - selectProcess( nil ) + selectProcess(nil) end - table.remove( tProcesses, nProcess ) + table.remove(tProcesses, nProcess) if nCurrentProcess == nil then if nProcess > 1 then - selectProcess( nProcess - 1 ) + selectProcess(nProcess - 1) elseif #tProcesses > 0 then - selectProcess( 1 ) + selectProcess(1) end end if nScrollPos ~= 1 then @@ -103,7 +103,7 @@ end local function cullProcesses() local culled = false for n = #tProcesses, 1, -1 do - culled = culled or cullProcess( n ) + culled = culled or cullProcess(n) end return culled end @@ -121,40 +121,40 @@ end local function redrawMenu() if bShowMenu then -- Draw menu - parentTerm.setCursorPos( 1, 1 ) - parentTerm.setBackgroundColor( menuOtherBgColor ) + parentTerm.setCursorPos(1, 1) + parentTerm.setBackgroundColor(menuOtherBgColor) parentTerm.clearLine() local nCharCount = 0 local nSize = parentTerm.getSize() if nScrollPos ~= 1 then - parentTerm.setTextColor( menuOtherTextColor ) - parentTerm.setBackgroundColor( menuOtherBgColor ) - parentTerm.write( "<" ) + parentTerm.setTextColor(menuOtherTextColor) + parentTerm.setBackgroundColor(menuOtherBgColor) + parentTerm.write("<") nCharCount = 1 end for n = nScrollPos, #tProcesses do if n == nCurrentProcess then - parentTerm.setTextColor( menuMainTextColor ) - parentTerm.setBackgroundColor( menuMainBgColor ) + parentTerm.setTextColor(menuMainTextColor) + parentTerm.setBackgroundColor(menuMainBgColor) else - parentTerm.setTextColor( menuOtherTextColor ) - parentTerm.setBackgroundColor( menuOtherBgColor ) + parentTerm.setTextColor(menuOtherTextColor) + parentTerm.setBackgroundColor(menuOtherBgColor) end - parentTerm.write( " " .. tProcesses[n].sTitle .. " " ) + parentTerm.write(" " .. tProcesses[n].sTitle .. " ") nCharCount = nCharCount + #tProcesses[n].sTitle + 2 end if nCharCount > nSize then - parentTerm.setTextColor( menuOtherTextColor ) - parentTerm.setBackgroundColor( menuOtherBgColor ) - parentTerm.setCursorPos( nSize, 1 ) - parentTerm.write( ">" ) + parentTerm.setTextColor(menuOtherTextColor) + parentTerm.setBackgroundColor(menuOtherBgColor) + parentTerm.setCursorPos(nSize, 1) + parentTerm.write(">") bScrollRight = true else bScrollRight = false end -- Put the cursor back where it should be - local tProcess = tProcesses[ nCurrentProcess ] + local tProcess = tProcesses[nCurrentProcess] if tProcess then tProcess.window.restoreCursor() end @@ -174,15 +174,15 @@ local function resizeWindows() local tProcess = tProcesses[n] local x, y = tProcess.window.getCursorPos() if y > windowHeight then - tProcess.window.scroll( y - windowHeight ) - tProcess.window.setCursorPos( x, windowHeight ) + tProcess.window.scroll(y - windowHeight) + tProcess.window.setCursorPos(x, windowHeight) end - tProcess.window.reposition( 1, windowY, w, windowHeight ) + tProcess.window.reposition(1, windowY, w, windowHeight) end bWindowsResized = true end -local function setMenuVisible( bVis ) +local function setMenuVisible(bVis) if bShowMenu ~= bVis then bShowMenu = bVis resizeWindows() @@ -196,17 +196,17 @@ function multishell.getFocus() return nCurrentProcess end -function multishell.setFocus( n ) +function multishell.setFocus(n) expect(1, n, "number") if n >= 1 and n <= #tProcesses then - selectProcess( n ) + selectProcess(n) redrawMenu() return true end return false end -function multishell.getTitle( n ) +function multishell.getTitle(n) expect(1, n, "number") if n >= 1 and n <= #tProcesses then return tProcesses[n].sTitle @@ -214,11 +214,11 @@ function multishell.getTitle( n ) return nil end -function multishell.setTitle( n, sTitle ) +function multishell.setTitle(n, sTitle) expect(1, n, "number") expect(2, sTitle, "string") if n >= 1 and n <= #tProcesses then - setProcessTitle( n, sTitle ) + setProcessTitle(n, sTitle) redrawMenu() end end @@ -227,14 +227,14 @@ function multishell.getCurrent() return nRunningProcess end -function multishell.launch( tProgramEnv, sProgramPath, ... ) +function multishell.launch(tProgramEnv, sProgramPath, ...) expect(1, tProgramEnv, "table") expect(2, sProgramPath, "string") local previousTerm = term.current() - setMenuVisible( #tProcesses + 1 >= 2 ) - local nResult = launchProcess( false, tProgramEnv, sProgramPath, ... ) + setMenuVisible(#tProcesses + 1 >= 2) + local nResult = launchProcess(false, tProgramEnv, sProgramPath, ...) redrawMenu() - term.redirect( previousTerm ) + term.redirect(previousTerm) return nResult end @@ -244,16 +244,16 @@ end -- Begin parentTerm.clear() -setMenuVisible( false ) -launchProcess( true, { +setMenuVisible(false) +launchProcess(true, { ["shell"] = shell, ["multishell"] = multishell, -}, "/rom/programs/shell.lua" ) +}, "/rom/programs/shell.lua") -- Run processes while #tProcesses > 0 do -- Get the event - local tEventData = table.pack( os.pullEventRaw() ) + local tEventData = table.pack(os.pullEventRaw()) local sEvent = tEventData[1] if sEvent == "term_resize" then -- Resize event @@ -264,9 +264,9 @@ while #tProcesses > 0 do elseif sEvent == "char" or sEvent == "key" or sEvent == "key_up" or sEvent == "paste" or sEvent == "terminate" then -- Keyboard event -- Passthrough to current process - resumeProcess( nCurrentProcess, table.unpack( tEventData, 1, tEventData.n ) ) - if cullProcess( nCurrentProcess ) then - setMenuVisible( #tProcesses >= 2 ) + resumeProcess(nCurrentProcess, table.unpack(tEventData, 1, tEventData.n)) + if cullProcess(nCurrentProcess) then + setMenuVisible(#tProcesses >= 2) redrawMenu() end @@ -289,7 +289,7 @@ while #tProcesses > 0 do for n = nScrollPos, #tProcesses do local tabEnd = tabStart + #tProcesses[n].sTitle + 1 if x >= tabStart and x <= tabEnd then - selectProcess( n ) + selectProcess(n) redrawMenu() break end @@ -298,9 +298,9 @@ while #tProcesses > 0 do end else -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y ) - if cullProcess( nCurrentProcess ) then - setMenuVisible( #tProcesses >= 2 ) + resumeProcess(nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y) + if cullProcess(nCurrentProcess) then + setMenuVisible(#tProcesses >= 2) redrawMenu() end end @@ -318,9 +318,9 @@ while #tProcesses > 0 do end elseif not (bShowMenu and y == 1) then -- Passthrough to current process - resumeProcess( nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y ) - if cullProcess( nCurrentProcess ) then - setMenuVisible( #tProcesses >= 2 ) + resumeProcess(nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y) + if cullProcess(nCurrentProcess) then + setMenuVisible(#tProcesses >= 2) redrawMenu() end end @@ -330,10 +330,10 @@ while #tProcesses > 0 do -- Passthrough to all processes local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event for n = 1, nLimit do - resumeProcess( n, table.unpack( tEventData, 1, tEventData.n ) ) + resumeProcess(n, table.unpack(tEventData, 1, tEventData.n)) end if cullProcesses() then - setMenuVisible( #tProcesses >= 2 ) + setMenuVisible(#tProcesses >= 2) redrawMenu() end end @@ -342,15 +342,15 @@ while #tProcesses > 0 do -- Pass term_resize to all processes local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event for n = 1, nLimit do - resumeProcess( n, "term_resize" ) + resumeProcess(n, "term_resize") end bWindowsResized = false if cullProcesses() then - setMenuVisible( #tProcesses >= 2 ) + setMenuVisible(#tProcesses >= 2) redrawMenu() end end end -- Shutdown -term.redirect( parentTerm ) +term.redirect(parentTerm) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua b/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua index c4f8c5ffe..d35eb7707 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua @@ -1,7 +1,7 @@ local tArgs = { ... } if #tArgs > 2 then - print( "Usage: alias " ) + print("Usage: alias ") return end @@ -10,17 +10,17 @@ local sProgram = tArgs[2] if sAlias and sProgram then -- Set alias - shell.setAlias( sAlias, sProgram ) + shell.setAlias(sAlias, sProgram) elseif sAlias then -- Clear alias - shell.clearAlias( sAlias ) + shell.clearAlias(sAlias) else -- List aliases local tAliases = shell.aliases() local tList = {} - for sAlias, sCommand in pairs( tAliases ) do - table.insert( tList, sAlias .. ":" .. sCommand ) + for sAlias, sCommand in pairs(tAliases) do + table.insert(tList, sAlias .. ":" .. sCommand) end - table.sort( tList ) - textutils.pagedTabulate( tList ) + table.sort(tList) + textutils.pagedTabulate(tList) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua b/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua index 7ef16e96f..801477650 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua @@ -1,15 +1,15 @@ local tApis = {} -for k, v in pairs( _G ) do +for k, v in pairs(_G) do if type(k) == "string" and type(v) == "table" and k ~= "_G" then - table.insert( tApis, k ) + table.insert(tApis, k) end end -table.insert( tApis, "shell" ) -table.insert( tApis, "package" ) +table.insert(tApis, "shell") +table.insert(tApis, "package") if multishell then - table.insert( tApis, "multishell" ) + table.insert(tApis, "multishell") end -table.sort( tApis ) +table.sort(tApis) -textutils.pagedTabulate( tApis ) +textutils.pagedTabulate(tApis) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua b/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua index abadf5366..6f05a98ac 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua @@ -1,14 +1,14 @@ local tArgs = { ... } if #tArgs < 1 then - print( "Usage: cd " ) + print("Usage: cd ") return end -local sNewDir = shell.resolve( tArgs[1] ) -if fs.isDir( sNewDir ) then - shell.setDir( sNewDir ) +local sNewDir = shell.resolve(tArgs[1]) +if fs.isDir(sNewDir) then + shell.setDir(sNewDir) else - print( "Not a directory" ) + print("Not a directory") return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/clear.lua b/src/main/resources/assets/computercraft/lua/rom/programs/clear.lua index 50283c8d7..d69a29993 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/clear.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/clear.lua @@ -1,2 +1,2 @@ term.clear() -term.setCursorPos( 1, 1 ) +term.setCursorPos(1, 1) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua index 230d766f7..dacc5626d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua @@ -1,16 +1,16 @@ if not commands then - printError( "Requires a Command Computer." ) + printError("Requires a Command Computer.") return end local tCommands = commands.list() -table.sort( tCommands ) +table.sort(tCommands) if term.isColor() then - term.setTextColor( colors.green ) + term.setTextColor(colors.green) end -print( "Available commands:" ) -term.setTextColor( colors.white ) +print("Available commands:") +term.setTextColor(colors.white) -textutils.pagedTabulate( tCommands ) +textutils.pagedTabulate(tCommands) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua b/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua index c54b3f567..b50c8ec20 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua @@ -1,40 +1,40 @@ local tArgs = { ... } if not commands then - printError( "Requires a Command Computer." ) + printError("Requires a Command Computer.") return end if #tArgs == 0 then - printError( "Usage: exec " ) + printError("Usage: exec ") return end -local function printSuccess( text ) +local function printSuccess(text) if term.isColor() then - term.setTextColor( colors.green ) + term.setTextColor(colors.green) end - print( text ) - term.setTextColor( colors.white ) + print(text) + term.setTextColor(colors.white) end -local sCommand = string.lower( tArgs[1] ) +local sCommand = string.lower(tArgs[1]) for n = 2, #tArgs do sCommand = sCommand .. " " .. tArgs[n] end -local bResult, tOutput = commands.exec( sCommand ) +local bResult, tOutput = commands.exec(sCommand) if bResult then - printSuccess( "Success" ) + printSuccess("Success") if #tOutput > 0 then for n = 1, #tOutput do - print( tOutput[n] ) + print(tOutput[n]) end end else - printError( "Failed" ) + printError("Failed") if #tOutput > 0 then for n = 1, #tOutput do - print( tOutput[n] ) + print(tOutput[n]) end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua index c8d66459b..d50132f82 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua @@ -1,32 +1,32 @@ local tArgs = { ... } if #tArgs < 2 then - print( "Usage: cp " ) + print("Usage: cp ") return end -local sSource = shell.resolve( tArgs[1] ) -local sDest = shell.resolve( tArgs[2] ) -local tFiles = fs.find( sSource ) +local sSource = shell.resolve(tArgs[1]) +local sDest = shell.resolve(tArgs[2]) +local tFiles = fs.find(sSource) if #tFiles > 0 then - for _, sFile in ipairs( tFiles ) do - if fs.isDir( sDest ) then - fs.copy( sFile, fs.combine( sDest, fs.getName(sFile) ) ) + for _, sFile in ipairs(tFiles) do + if fs.isDir(sDest) then + fs.copy(sFile, fs.combine(sDest, fs.getName(sFile))) elseif #tFiles == 1 then - if fs.exists( sDest ) then - printError( "Destination exists" ) - elseif fs.isReadOnly( sDest ) then - printError( "Destination is read-only" ) - elseif fs.getFreeSpace( sDest ) < fs.getSize( sFile ) then - printError( "Not enough space" ) + if fs.exists(sDest) then + printError("Destination exists") + elseif fs.isReadOnly(sDest) then + printError("Destination is read-only") + elseif fs.getFreeSpace(sDest) < fs.getSize(sFile) then + printError("Not enough space") else - fs.copy( sFile, sDest ) + fs.copy(sFile, sDest) end else - printError( "Cannot overwrite file multiple times" ) + printError("Cannot overwrite file multiple times") return end end else - printError( "No matching files" ) + printError("No matching files") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua b/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua index 807cf88b4..799b65ecc 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/drive.lua @@ -3,19 +3,19 @@ local tArgs = { ... } -- Get where a directory is mounted local sPath = shell.dir() if tArgs[1] ~= nil then - sPath = shell.resolve( tArgs[1] ) + sPath = shell.resolve(tArgs[1]) end -if fs.exists( sPath ) then - write( fs.getDrive( sPath ) .. " (" ) - local nSpace = fs.getFreeSpace( sPath ) +if fs.exists(sPath) then + write(fs.getDrive(sPath) .. " (") + local nSpace = fs.getFreeSpace(sPath) if nSpace >= 1000 * 1000 then - print( math.floor( nSpace / (100 * 1000) ) / 10 .. "MB remaining)" ) + print(math.floor(nSpace / (100 * 1000)) / 10 .. "MB remaining)") elseif nSpace >= 1000 then - print( math.floor( nSpace / 100 ) / 10 .. "KB remaining)" ) + print(math.floor(nSpace / 100) / 10 .. "KB remaining)") else - print( nSpace .. "B remaining)" ) + print(nSpace .. "B remaining)") end else - print( "No such path" ) + print("No such path") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index 0125d5b12..a6ea4d8d0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -1,22 +1,22 @@ -- Get file to edit local tArgs = { ... } if #tArgs == 0 then - print( "Usage: edit " ) + print("Usage: edit ") return end -- Error checking -local sPath = shell.resolve( tArgs[1] ) -local bReadOnly = fs.isReadOnly( sPath ) -if fs.exists( sPath ) and fs.isDir( sPath ) then - print( "Cannot edit a directory." ) +local sPath = shell.resolve(tArgs[1]) +local bReadOnly = fs.isReadOnly(sPath) +if fs.exists(sPath) and fs.isDir(sPath) then + print("Cannot edit a directory.") return end -- Create .lua files by default -if not fs.exists( sPath ) and not string.find( sPath, "%." ) then +if not fs.exists(sPath) and not string.find(sPath, "%.") then local sExtension = settings.get("edit.default_extension", "") - if sExtension ~= "" and type( sExtension ) == "string" then + if sExtension ~= "" and type(sExtension) == "string" then sPath = sPath .. "." .. sExtension end end @@ -51,59 +51,59 @@ local bMenu = false local nMenuItem = 1 local tMenuItems = {} if not bReadOnly then - table.insert( tMenuItems, "Save" ) + table.insert(tMenuItems, "Save") end if shell.openTab then - table.insert( tMenuItems, "Run" ) + table.insert(tMenuItems, "Run") end -if peripheral.find( "printer" ) then - table.insert( tMenuItems, "Print" ) +if peripheral.find("printer") then + table.insert(tMenuItems, "Print") end -table.insert( tMenuItems, "Exit" ) +table.insert(tMenuItems, "Exit") local sStatus = "Press Ctrl to access menu" if #sStatus > w - 5 then sStatus = "Press Ctrl for menu" end -local function load( _sPath ) +local function load(_sPath) tLines = {} - if fs.exists( _sPath ) then - local file = io.open( _sPath, "r" ) + if fs.exists(_sPath) then + local file = io.open(_sPath, "r") local sLine = file:read() while sLine do - table.insert( tLines, sLine ) + table.insert(tLines, sLine) sLine = file:read() end file:close() end if #tLines == 0 then - table.insert( tLines, "" ) + table.insert(tLines, "") end end -local function save( _sPath ) +local function save(_sPath) -- Create intervening folder local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len()) - if not fs.exists( sDir ) then - fs.makeDir( sDir ) + if not fs.exists(sDir) then + fs.makeDir(sDir) end -- Save local file, fileerr local function innerSave() - file, fileerr = fs.open( _sPath, "w" ) + file, fileerr = fs.open(_sPath, "w") if file then - for _, sLine in ipairs( tLines ) do - file.write( sLine .. "\n" ) + for _, sLine in ipairs(tLines) do + file.write(sLine .. "\n") end else - error( "Failed to open " .. _sPath ) + error("Failed to open " .. _sPath) end end - local ok, err = pcall( innerSave ) + local ok, err = pcall(innerSave) if file then file.close() end @@ -134,38 +134,38 @@ local tKeywords = { ["while"] = true, } -local function tryWrite( sLine, regex, colour ) - local match = string.match( sLine, regex ) +local function tryWrite(sLine, regex, colour) + local match = string.match(sLine, regex) if match then if type(colour) == "number" then - term.setTextColour( colour ) + term.setTextColour(colour) else - term.setTextColour( colour(match) ) + term.setTextColour(colour(match)) end - term.write( match ) - term.setTextColour( textColour ) - return string.sub( sLine, #match + 1 ) + term.write(match) + term.setTextColour(textColour) + return string.sub(sLine, #match + 1) end return nil end -local function writeHighlighted( sLine ) +local function writeHighlighted(sLine) while #sLine > 0 do sLine = - tryWrite( sLine, "^%-%-%[%[.-%]%]", commentColour ) or - tryWrite( sLine, "^%-%-.*", commentColour ) or - tryWrite( sLine, "^\"\"", stringColour ) or - tryWrite( sLine, "^\".-[^\\]\"", stringColour ) or - tryWrite( sLine, "^\'\'", stringColour ) or - tryWrite( sLine, "^\'.-[^\\]\'", stringColour ) or - tryWrite( sLine, "^%[%[.-%]%]", stringColour ) or - tryWrite( sLine, "^[%w_]+", function( match ) - if tKeywords[ match ] then + tryWrite(sLine, "^%-%-%[%[.-%]%]", commentColour) or + tryWrite(sLine, "^%-%-.*", commentColour) or + tryWrite(sLine, "^\"\"", stringColour) or + tryWrite(sLine, "^\".-[^\\]\"", stringColour) or + tryWrite(sLine, "^\'\'", stringColour) or + tryWrite(sLine, "^\'.-[^\\]\'", stringColour) or + tryWrite(sLine, "^%[%[.-%]%]", stringColour) or + tryWrite(sLine, "^[%w_]+", function(match) + if tKeywords[match] then return keywordColour end return textColour - end ) or - tryWrite( sLine, "^[^%w_]", textColour ) + end) or + tryWrite(sLine, "^[^%w_]", textColour) end end @@ -173,14 +173,14 @@ local tCompletions local nCompletion local tCompleteEnv = _ENV -local function complete( sLine ) - if settings.get( "edit.autocomplete" ) then - local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.:]+$" ) +local function complete(sLine) + if settings.get("edit.autocomplete") then + local nStartPos = string.find(sLine, "[a-zA-Z0-9_%.:]+$") if nStartPos then - sLine = string.sub( sLine, nStartPos ) + sLine = string.sub(sLine, nStartPos) end if #sLine > 0 then - return textutils.complete( sLine, tCompleteEnv ) + return textutils.complete(sLine, tCompleteEnv) end end return nil @@ -189,7 +189,7 @@ end local function recomplete() local sLine = tLines[y] if not bMenu and not bReadOnly and x == #sLine + 1 then - tCompletions = complete( sLine ) + tCompletions = complete(sLine) if tCompletions and #tCompletions > 0 then nCompletion = 1 else @@ -201,85 +201,85 @@ local function recomplete() end end -local function writeCompletion( sLine ) +local function writeCompletion(sLine) if nCompletion then - local sCompletion = tCompletions[ nCompletion ] - term.setTextColor( colours.white ) - term.setBackgroundColor( colours.grey ) - term.write( sCompletion ) - term.setTextColor( textColour ) - term.setBackgroundColor( bgColour ) + local sCompletion = tCompletions[nCompletion] + term.setTextColor(colours.white) + term.setBackgroundColor(colours.grey) + term.write(sCompletion) + term.setTextColor(textColour) + term.setBackgroundColor(bgColour) end end local function redrawText() local cursorX, cursorY = x, y for y = 1, h - 1 do - term.setCursorPos( 1 - scrollX, y ) + term.setCursorPos(1 - scrollX, y) term.clearLine() - local sLine = tLines[ y + scrollY ] + local sLine = tLines[y + scrollY] if sLine ~= nil then - writeHighlighted( sLine ) + writeHighlighted(sLine) if cursorY == y and cursorX == #sLine + 1 then writeCompletion() end end end - term.setCursorPos( x - scrollX, y - scrollY ) + term.setCursorPos(x - scrollX, y - scrollY) end local function redrawLine(_nY) local sLine = tLines[_nY] if sLine then - term.setCursorPos( 1 - scrollX, _nY - scrollY ) + term.setCursorPos(1 - scrollX, _nY - scrollY) term.clearLine() - writeHighlighted( sLine ) + writeHighlighted(sLine) if _nY == y and x == #sLine + 1 then writeCompletion() end - term.setCursorPos( x - scrollX, _nY - scrollY ) + term.setCursorPos(x - scrollX, _nY - scrollY) end end local function redrawMenu() -- Clear line - term.setCursorPos( 1, h ) + term.setCursorPos(1, h) term.clearLine() -- Draw line numbers - term.setCursorPos( w - #( "Ln " .. y ) + 1, h ) - term.setTextColour( highlightColour ) - term.write( "Ln " ) - term.setTextColour( textColour ) - term.write( y ) + term.setCursorPos(w - #("Ln " .. y) + 1, h) + term.setTextColour(highlightColour) + term.write("Ln ") + term.setTextColour(textColour) + term.write(y) - term.setCursorPos( 1, h ) + term.setCursorPos(1, h) if bMenu then -- Draw menu - term.setTextColour( textColour ) - for nItem, sItem in pairs( tMenuItems ) do + term.setTextColour(textColour) + for nItem, sItem in pairs(tMenuItems) do if nItem == nMenuItem then - term.setTextColour( highlightColour ) - term.write( "[" ) - term.setTextColour( textColour ) - term.write( sItem ) - term.setTextColour( highlightColour ) - term.write( "]" ) - term.setTextColour( textColour ) + term.setTextColour(highlightColour) + term.write("[") + term.setTextColour(textColour) + term.write(sItem) + term.setTextColour(highlightColour) + term.write("]") + term.setTextColour(textColour) else - term.write( " " .. sItem .. " " ) + term.write(" " .. sItem .. " ") end end else -- Draw status - term.setTextColour( highlightColour ) - term.write( sStatus ) - term.setTextColour( textColour ) + term.setTextColour(highlightColour) + term.write(sStatus) + term.setTextColour(textColour) end -- Reset cursor - term.setCursorPos( x - scrollX, y - scrollY ) + term.setCursorPos(x - scrollX, y - scrollY) end local tMenuFuncs = { @@ -287,7 +287,7 @@ local tMenuFuncs = { if bReadOnly then sStatus = "Access denied" else - local ok, _, fileerr = save( sPath ) + local ok, _, fileerr = save(sPath) if ok then sStatus = "Saved to " .. sPath else @@ -301,14 +301,14 @@ local tMenuFuncs = { redrawMenu() end, Print = function() - local printer = peripheral.find( "printer" ) + local printer = peripheral.find("printer") if not printer then sStatus = "No printer attached" return end local nPage = 0 - local sName = fs.getName( sPath ) + local sName = fs.getName(sPath) if printer.getInkLevel() < 1 then sStatus = "Printer out of ink" return @@ -326,7 +326,7 @@ local tMenuFuncs = { } printerTerminal.scroll = function() if nPage == 1 then - printer.setPageTitle( sName .. " (page " .. nPage .. ")" ) + printer.setPageTitle(sName .. " (page " .. nPage .. ")") end while not printer.newPage() do @@ -338,38 +338,38 @@ local tMenuFuncs = { sStatus = "Printer output tray full, please empty" end - term.redirect( screenTerminal ) + term.redirect(screenTerminal) redrawMenu() - term.redirect( printerTerminal ) + term.redirect(printerTerminal) sleep(0.5) end nPage = nPage + 1 if nPage == 1 then - printer.setPageTitle( sName ) + printer.setPageTitle(sName) else - printer.setPageTitle( sName .. " (page " .. nPage .. ")" ) + printer.setPageTitle(sName .. " (page " .. nPage .. ")") end end bMenu = false - term.redirect( printerTerminal ) - local ok, error = pcall( function() + term.redirect(printerTerminal) + local ok, error = pcall(function() term.scroll() - for _, sLine in ipairs( tLines ) do - print( sLine ) + for _, sLine in ipairs(tLines) do + print(sLine) end - end ) - term.redirect( screenTerminal ) + end) + term.redirect(screenTerminal) if not ok then - print( error ) + print(error) end while not printer.endPage() do sStatus = "Printer output tray full, please empty" redrawMenu() - sleep( 0.5 ) + sleep(0.5) end bMenu = true @@ -385,15 +385,15 @@ local tMenuFuncs = { end, Run = function() local sTempPath = "/.temp" - local ok = save( sTempPath ) + local ok = save(sTempPath) if ok then - local nTask = shell.openTab( sTempPath ) + local nTask = shell.openTab(sTempPath) if nTask then - shell.switchTab( nTask ) + shell.switchTab(nTask) else sStatus = "Error starting Task" end - fs.delete( sTempPath ) + fs.delete(sTempPath) else sStatus = "Error saving to " .. sTempPath end @@ -401,16 +401,16 @@ local tMenuFuncs = { end, } -local function doMenuItem( _n ) +local function doMenuItem(_n) tMenuFuncs[tMenuItems[_n]]() if bMenu then bMenu = false - term.setCursorBlink( true ) + term.setCursorBlink(true) end redrawMenu() end -local function setCursor( newX, newY ) +local function setCursor(newX, newY) local _, oldY = x, y x, y = newX, newY local screenX = x - scrollX @@ -441,12 +441,12 @@ local function setCursor( newX, newY ) if bRedraw then redrawText() elseif y ~= oldY then - redrawLine( oldY ) - redrawLine( y ) + redrawLine(oldY) + redrawLine(y) else - redrawLine( y ) + redrawLine(y) end - term.setCursorPos( screenX, screenY ) + term.setCursorPos(screenX, screenY) redrawMenu() end @@ -454,10 +454,10 @@ end -- Actual program functionality begins load(sPath) -term.setBackgroundColour( bgColour ) +term.setBackgroundColour(bgColour) term.clear() term.setCursorPos(x, y) -term.setCursorBlink( true ) +term.setCursorBlink(true) recomplete() redrawText() @@ -466,9 +466,9 @@ redrawMenu() local function acceptCompletion() if nCompletion then -- Append the completion - local sCompletion = tCompletions[ nCompletion ] + local sCompletion = tCompletions[nCompletion] tLines[y] = tLines[y] .. sCompletion - setCursor( x + #sCompletion , y ) + setCursor(x + #sCompletion , y) end end @@ -490,7 +490,7 @@ while bRunning do elseif y > 1 then -- Move cursor up setCursor( - math.min( x, #tLines[y - 1] + 1 ), + math.min(x, #tLines[y - 1] + 1), y - 1 ) end @@ -511,7 +511,7 @@ while bRunning do elseif y < #tLines then -- Move cursor down setCursor( - math.min( x, #tLines[y + 1] + 1 ), + math.min(x, #tLines[y + 1] + 1), y + 1 ) end @@ -527,7 +527,7 @@ while bRunning do -- Indent line local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. " " .. string.sub(sLine, x) - setCursor( x + 4, y ) + setCursor(x + 4, y) end end @@ -542,7 +542,7 @@ while bRunning do newY = 1 end setCursor( - math.min( x, #tLines[newY] + 1 ), + math.min(x, #tLines[newY] + 1), newY ) end @@ -557,8 +557,8 @@ while bRunning do else newY = #tLines end - local newX = math.min( x, #tLines[newY] + 1 ) - setCursor( newX, newY ) + local newX = math.min(x, #tLines[newY] + 1) + setCursor(newX, newY) end elseif param == keys.home then @@ -576,7 +576,7 @@ while bRunning do -- Move cursor to the end local nLimit = #tLines[y] + 1 if x < nLimit then - setCursor( nLimit, y ) + setCursor(nLimit, y) end end @@ -585,9 +585,9 @@ while bRunning do if not bMenu then if x > 1 then -- Move cursor left - setCursor( x - 1, y ) + setCursor(x - 1, y) elseif x == 1 and y > 1 then - setCursor( #tLines[y - 1] + 1, y - 1 ) + setCursor(#tLines[y - 1] + 1, y - 1) end else -- Move menu left @@ -604,13 +604,13 @@ while bRunning do local nLimit = #tLines[y] + 1 if x < nLimit then -- Move cursor right - setCursor( x + 1, y ) + setCursor(x + 1, y) elseif nCompletion and x == #tLines[y] + 1 then -- Accept autocomplete acceptCompletion() elseif x == nLimit and y < #tLines then -- Go to next line - setCursor( 1, y + 1 ) + setCursor(1, y + 1) end else -- Move menu right @@ -632,7 +632,7 @@ while bRunning do redrawLine(y) elseif y < #tLines then tLines[y] = tLines[y] .. tLines[y + 1] - table.remove( tLines, y + 1 ) + table.remove(tLines, y + 1) recomplete() redrawText() end @@ -646,17 +646,17 @@ while bRunning do local sLine = tLines[y] if x > 4 and string.sub(sLine, x - 4, x - 1) == " " and not string.sub(sLine, 1, x - 1):find("%S") then tLines[y] = string.sub(sLine, 1, x - 5) .. string.sub(sLine, x) - setCursor( x - 4, y ) + setCursor(x - 4, y) else tLines[y] = string.sub(sLine, 1, x - 2) .. string.sub(sLine, x) - setCursor( x - 1, y ) + setCursor(x - 1, y) end elseif y > 1 then -- Remove newline local sPrevLen = #tLines[y - 1] tLines[y - 1] = tLines[y - 1] .. tLines[y] - table.remove( tLines, y ) - setCursor( sPrevLen + 1, y - 1 ) + table.remove(tLines, y) + setCursor(sPrevLen + 1, y - 1) redrawText() end end @@ -671,13 +671,13 @@ while bRunning do spaces = 0 end tLines[y] = string.sub(sLine, 1, x - 1) - table.insert( tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x) ) - setCursor( spaces + 1, y + 1 ) + table.insert(tLines, y + 1, string.rep(' ', spaces) .. string.sub(sLine, x)) + setCursor(spaces + 1, y + 1) redrawText() elseif bMenu then -- Menu selection - doMenuItem( nMenuItem ) + doMenuItem(nMenuItem) end @@ -685,9 +685,9 @@ while bRunning do -- Menu toggle bMenu = not bMenu if bMenu then - term.setCursorBlink( false ) + term.setCursorBlink(false) else - term.setCursorBlink( true ) + term.setCursorBlink(true) end redrawMenu() @@ -698,13 +698,13 @@ while bRunning do -- Input text local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) - setCursor( x + 1, y ) + setCursor(x + 1, y) elseif bMenu then -- Select menu items - for n, sMenuItem in ipairs( tMenuItems ) do + for n, sMenuItem in ipairs(tMenuItems) do if string.lower(string.sub(sMenuItem, 1, 1)) == string.lower(param) then - doMenuItem( n ) + doMenuItem(n) break end end @@ -715,13 +715,13 @@ while bRunning do -- Close menu if open if bMenu then bMenu = false - term.setCursorBlink( true ) + term.setCursorBlink(true) redrawMenu() end -- Input text local sLine = tLines[y] tLines[y] = string.sub(sLine, 1, x - 1) .. param .. string.sub(sLine, x) - setCursor( x + #param , y ) + setCursor(x + #param , y) end elseif sEvent == "mouse_click" then @@ -730,9 +730,9 @@ while bRunning do -- Left click local cx, cy = param2, param3 if cy < h then - local newY = math.min( math.max( scrollY + cy, 1 ), #tLines ) - local newX = math.min( math.max( scrollX + cx, 1 ), #tLines[newY] + 1 ) - setCursor( newX, newY ) + local newY = math.min(math.max(scrollY + cy, 1), #tLines) + local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1) + setCursor(newX, newY) end end end @@ -761,7 +761,7 @@ while bRunning do elseif sEvent == "term_resize" then w, h = term.getSize() - setCursor( x, y ) + setCursor(x, y) redrawMenu() redrawText() @@ -770,5 +770,5 @@ end -- Cleanup term.clear() -term.setCursorBlink( false ) -term.setCursorPos( 1, 1 ) +term.setCursorBlink(false) +term.setCursorPos(1, 1) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua b/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua index ad47bbd99..635c2f4e8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua @@ -2,17 +2,17 @@ -- Get arguments local tArgs = { ... } if #tArgs == 0 then - print( "Usage: eject " ) + print("Usage: eject ") return end local sDrive = tArgs[1] -- Check the disk exists -local bPresent = disk.isPresent( sDrive ) +local bPresent = disk.isPresent(sDrive) if not bPresent then - print( "Nothing in " .. sDrive .. " drive" ) + print("Nothing in " .. sDrive .. " drive") return end -disk.eject( sDrive ) +disk.eject(sDrive) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index d2f3a5159..fbe228091 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -32,7 +32,7 @@ if not term.isColour() then end -- Determines if the file exists, and can be edited on this computer -local tArgs = {...} +local tArgs = { ... } if #tArgs == 0 then print("Usage: paint ") return @@ -45,9 +45,9 @@ if fs.exists(sPath) and fs.isDir(sPath) then end -- Create .nfp files by default -if not fs.exists( sPath ) and not string.find( sPath, "%." ) then +if not fs.exists(sPath) and not string.find(sPath, "%.") then local sExtension = settings.get("paint.default_extension", "") - if sExtension ~= "" and type( sExtension ) == "string" then + if sExtension ~= "" and type(sExtension) == "string" then sPath = sPath .. "." .. sExtension end end @@ -57,7 +57,7 @@ end -- Functions -- --------------- -local function getCanvasPixel( x, y ) +local function getCanvasPixel(x, y) if canvas[y] then return canvas[y][x] end @@ -69,12 +69,12 @@ end params: colour = the number to convert to a hex value returns: a string representing the chosen colour ]] -local function getCharOf( colour ) +local function getCharOf(colour) -- Incorrect values always convert to nil if type(colour) == "number" then - local value = math.floor( math.log(colour) / math.log(2) ) + 1 + local value = math.floor(math.log(colour) / math.log(2)) + 1 if value >= 1 and value <= 16 then - return string.sub( "0123456789abcdef", value, value ) + return string.sub("0123456789abcdef", value, value) end end return " " @@ -87,9 +87,9 @@ end ]] local tColourLookup = {} for n = 1, 16 do - tColourLookup[ string.byte( "0123456789abcdef", n, n ) ] = 2 ^ (n - 1) + tColourLookup[string.byte("0123456789abcdef", n, n)] = 2 ^ (n - 1) end -local function getColourOf( char ) +local function getColourOf(char) -- Values not in the hex table are transparent (canvas coloured) return tColourLookup[char] end @@ -107,9 +107,9 @@ local function load(path) while sLine do local line = {} for x = 1, w - 2 do - line[x] = getColourOf( string.byte(sLine, x, x) ) + line[x] = getColourOf(string.byte(sLine, x, x)) end - table.insert( canvas, line ) + table.insert(canvas, line) sLine = file.readLine() end file.close() @@ -128,7 +128,7 @@ local function save(path) fs.makeDir(sDir) end - local file, err = fs.open( path, "w" ) + local file, err = fs.open(path, "w") if not file then return false, err end @@ -140,13 +140,13 @@ local function save(path) local sLine = "" local nLastChar = 0 for x = 1, w - 2 do - local c = getCharOf( getCanvasPixel( x, y ) ) + local c = getCharOf(getCanvasPixel(x, y)) sLine = sLine .. c if c ~= " " then nLastChar = x end end - sLine = string.sub( sLine, 1, nLastChar ) + sLine = string.sub(sLine, 1, nLastChar) tLines[y] = sLine if #sLine > 0 then nLastLine = y @@ -155,7 +155,7 @@ local function save(path) -- Save out for n = 1, nLastLine do - file.writeLine( tLines[ n ] ) + file.writeLine(tLines[n]) end file.close() return true @@ -176,38 +176,38 @@ local function drawInterface() -- Colour Picker for i = 1, 16 do term.setCursorPos(w - 1, i) - term.setBackgroundColour( 2 ^ (i - 1) ) + term.setBackgroundColour(2 ^ (i - 1)) term.write(" ") end term.setCursorPos(w - 1, 17) - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.write("\127\127") -- Left and Right Selected Colours do term.setCursorPos(w - 1, 18) if leftColour ~= nil then - term.setBackgroundColour( leftColour ) + term.setBackgroundColour(leftColour) term.write(" ") else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.write("\127") end if rightColour ~= nil then - term.setBackgroundColour( rightColour ) + term.setBackgroundColour(rightColour) term.write(" ") else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.write("\127") end end -- Padding - term.setBackgroundColour( canvasColour ) + term.setBackgroundColour(canvasColour) for i = 20, h - 1 do term.setCursorPos(w - 1, i) term.write(" ") @@ -218,15 +218,15 @@ end Converts a single pixel of a single line of the canvas and draws it returns: nil ]] -local function drawCanvasPixel( x, y ) - local pixel = getCanvasPixel( x, y ) +local function drawCanvasPixel(x, y) + local pixel = getCanvasPixel(x, y) if pixel then - term.setBackgroundColour( pixel or canvasColour ) + term.setBackgroundColour(pixel or canvasColour) term.setCursorPos(x, y) term.write(" ") else - term.setBackgroundColour( canvasColour ) - term.setTextColour( colours.grey ) + term.setBackgroundColour(canvasColour) + term.setTextColour(colours.grey) term.setCursorPos(x, y) term.write("\127") end @@ -236,9 +236,9 @@ end Converts each colour in a single line of the canvas and draws it returns: nil ]] -local function drawCanvasLine( y ) +local function drawCanvasLine(y) for x = 1, w - 2 do - drawCanvasPixel( x, y ) + drawCanvasPixel(x, y) end end @@ -248,7 +248,7 @@ end ]] local function drawCanvas() for y = 1, h - 1 do - drawCanvasLine( y ) + drawCanvasLine(y) end end @@ -377,7 +377,7 @@ local function handleEvents() end canvas[p3][p2] = paintColour - drawCanvasPixel( p2, p3 ) + drawCanvasPixel(p2, p3) end elseif id == "key" then if p1 == keys.leftCtrl or p1 == keys.rightCtrl then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua index 3f68e3859..7cc1233a6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/redirection.lua @@ -59,10 +59,10 @@ local cR4 = colors.yellow local tArgs = { ... } --Functions-- -local function printCentred( yc, stg ) +local function printCentred(yc, stg) local xc = math.floor((TermW - #stg) / 2) + 1 term.setCursorPos(xc, yc) - term.write( stg ) + term.write(stg) end local function centerOrgin() @@ -173,9 +173,9 @@ end local function loadLevel(nNum) sLevelTitle = "Level " .. nNum if nNum == nil then return error("nNum == nil") end - local sDir = fs.getDir( shell.getRunningProgram() ) + local sDir = fs.getDir(shell.getRunningProgram()) local sLevelD = sDir .. "/levels/" .. tostring(nNum) .. ".dat" - if not ( fs.exists(sLevelD) or fs.isDir(sLevelD) ) then return error("Level Not Exists : " .. sLevelD) end + if not (fs.exists(sLevelD) or fs.isDir(sLevelD)) then return error("Level Not Exists : " .. sLevelD) end fLevel = fs.open(sLevelD, "r") local wl = true Blocks = tonumber(string.sub(fLevel.readLine(), 1, 1)) @@ -512,18 +512,18 @@ local function gRender(sContext) end function InterFace.drawBar() - term.setBackgroundColor( colors.black ) - term.setTextColor( InterFace.cTitle ) - printCentred( 1, " " .. sLevelTitle .. " " ) + term.setBackgroundColor(colors.black) + term.setTextColor(InterFace.cTitle) + printCentred(1, " " .. sLevelTitle .. " ") term.setCursorPos(1, 1) - term.setBackgroundColor( cW ) - write( " " ) - term.setBackgroundColor( colors.black ) - write( " x " .. tostring(Blocks) .. " " ) + term.setBackgroundColor(cW) + write(" ") + term.setBackgroundColor(colors.black) + write(" x " .. tostring(Blocks) .. " ") - term.setCursorPos( TermW - 8, TermH ) - term.setBackgroundColor( colors.black ) + term.setCursorPos(TermW - 8, TermH) + term.setBackgroundColor(colors.black) term.setTextColour(InterFace.cSpeedD) write(" <<") if bPaused then @@ -539,9 +539,9 @@ function InterFace.drawBar() end write(" >>") - term.setCursorPos( TermW - 1, 1 ) - term.setBackgroundColor( colors.black ) - term.setTextColour( InterFace.cExit ) + term.setCursorPos(TermW - 1, 1) + term.setBackgroundColor(colors.black) + term.setTextColour(InterFace.cExit) write(" X") term.setBackgroundColor(colors.black) end @@ -612,7 +612,7 @@ local function startG(LevelN) elseif isExit == "retry" then return LevelN elseif fExit == "yes" then - if fs.exists( fs.getDir( shell.getRunningProgram() ) .. "/levels/" .. tostring(LevelN + 1) .. ".dat" ) then + if fs.exists(fs.getDir(shell.getRunningProgram()) .. "/levels/" .. tostring(LevelN + 1) .. ".dat") then return LevelN + 1 else return nil @@ -629,26 +629,26 @@ local ok, err = true, nil --Menu-- local sStartLevel = tArgs[1] if ok and not sStartLevel then - ok, err = pcall( function() + ok, err = pcall(function() term.setTextColor(colors.white) - term.setBackgroundColor( colors.black ) + term.setBackgroundColor(colors.black) term.clear() drawStars() - term.setTextColor( colors.red ) - printCentred( TermH / 2 - 1, " REDIRECTION " ) - printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) - term.setTextColor( colors.yellow ) - printCentred( TermH / 2 + 2, " Click to Begin " ) - os.pullEvent( "mouse_click" ) - end ) + term.setTextColor(colors.red) + printCentred(TermH / 2 - 1, " REDIRECTION ") + printCentred(TermH / 2 - 0, " ComputerCraft Edition ") + term.setTextColor(colors.yellow) + printCentred(TermH / 2 + 2, " Click to Begin ") + os.pullEvent("mouse_click") + end) end --Game-- if ok then - ok, err = pcall( function() + ok, err = pcall(function() local nLevel if sStartLevel then - nLevel = tonumber( sStartLevel ) + nLevel = tonumber(sStartLevel) else nLevel = 1 end @@ -656,36 +656,36 @@ if ok then reset() nLevel = startG(nLevel) end - end ) + end) end --Upsell screen-- if ok then - ok, err = pcall( function() + ok, err = pcall(function() term.setTextColor(colors.white) - term.setBackgroundColor( colors.black ) + term.setBackgroundColor(colors.black) term.clear() drawStars() - term.setTextColor( colors.red ) + term.setTextColor(colors.red) if TermW >= 40 then - printCentred( TermH / 2 - 1, " Thank you for playing Redirection " ) - printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) - printCentred( TermH / 2 + 2, " Check out the full game: " ) - term.setTextColor( colors.yellow ) - printCentred( TermH / 2 + 3, " http://www.redirectiongame.com " ) + printCentred(TermH / 2 - 1, " Thank you for playing Redirection ") + printCentred(TermH / 2 - 0, " ComputerCraft Edition ") + printCentred(TermH / 2 + 2, " Check out the full game: ") + term.setTextColor(colors.yellow) + printCentred(TermH / 2 + 3, " http://www.redirectiongame.com ") else - printCentred( TermH / 2 - 2, " Thank you for " ) - printCentred( TermH / 2 - 1, " playing Redirection " ) - printCentred( TermH / 2 - 0, " ComputerCraft Edition " ) - printCentred( TermH / 2 + 2, " Check out the full game: " ) - term.setTextColor( colors.yellow ) - printCentred( TermH / 2 + 3, " www.redirectiongame.com " ) + printCentred(TermH / 2 - 2, " Thank you for ") + printCentred(TermH / 2 - 1, " playing Redirection ") + printCentred(TermH / 2 - 0, " ComputerCraft Edition ") + printCentred(TermH / 2 + 2, " Check out the full game: ") + term.setTextColor(colors.yellow) + printCentred(TermH / 2 + 3, " www.redirectiongame.com ") end parallel.waitForAll( function() sleep(2) end, - function() os.pullEvent( "mouse_click" ) end + function() os.pullEvent("mouse_click") end ) - end ) + end) end --Clear and exit-- @@ -695,9 +695,9 @@ term.setBackgroundColor(colors.black) term.clear() if not ok then if err == "Terminated" then - print( "Check out the full version of Redirection:" ) - print( "http://www.redirectiongame.com" ) + print("Check out the full version of Redirection:") + print("http://www.redirectiongame.com") else - printError( err ) + printError(err) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua index 48e06a950..0f08b59be 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua @@ -9,15 +9,15 @@ local tBiomes = { "in frozen tundra", } -local function hasTrees( _nBiome ) +local function hasTrees(_nBiome) return _nBiome <= 3 end -local function hasStone( _nBiome ) +local function hasStone(_nBiome) return _nBiome == 4 end -local function hasRivers( _nBiome ) +local function hasRivers(_nBiome) return _nBiome ~= 3 and _nBiome ~= 5 end @@ -338,14 +338,14 @@ local tDayCycle = { } local function getTimeOfDay() - return math.fmod( math.floor(nTurn / 3), #tDayCycle ) + 1 + return math.fmod(math.floor(nTurn / 3), #tDayCycle) + 1 end local function isSunny() return getTimeOfDay() < 10 end -local function getRoom( x, y, z, dontCreate ) +local function getRoom(x, y, z, dontCreate) tMap[x] = tMap[x] or {} tMap[x][y] = tMap[x][y] or {} if not tMap[x][y][z] and dontCreate ~= true then @@ -360,26 +360,26 @@ local function getRoom( x, y, z, dontCreate ) -- Room is above ground -- Pick biome - room.nBiome = math.random( 1, #tBiomes ) - room.trees = hasTrees( room.nBiome ) + room.nBiome = math.random(1, #tBiomes) + room.trees = hasTrees(room.nBiome) -- Add animals if math.random(1, 3) == 1 then for _ = 1, math.random(1, 2) do - local sAnimal = tAnimals[ math.random( 1, #tAnimals ) ] - room.items[ sAnimal ] = items[ sAnimal ] + local sAnimal = tAnimals[math.random(1, #tAnimals)] + room.items[sAnimal] = items[sAnimal] end end -- Add surface ore - if math.random(1, 5) == 1 or hasStone( room.nBiome ) then - room.items[ "some stone" ] = items[ "some stone" ] + if math.random(1, 5) == 1 or hasStone(room.nBiome) then + room.items["some stone"] = items["some stone"] end if math.random(1, 8) == 1 then - room.items[ "some coal" ] = items[ "some coal" ] + room.items["some coal"] = items["some coal"] end - if math.random(1, 8) == 1 and hasRivers( room.nBiome ) then - room.items[ "a river" ] = items[ "a river" ] + if math.random(1, 8) == 1 and hasRivers(room.nBiome) then + room.items["a river"] = items["a river"] end -- Add exits @@ -390,15 +390,15 @@ local function getRoom( x, y, z, dontCreate ) ["west"] = true, } if math.random(1, 8) == 1 then - room.exits["down"] = true + room.exits.down = true room.items["a cave entrance"] = items["a cave entrance"] end else -- Room is underground -- Add exits - local function tryExit( sDir, sOpp, x, y, z ) - local adj = getRoom( x, y, z, true ) + local function tryExit(sDir, sOpp, x, y, z) + local adj = getRoom(x, y, z, true) if adj then if adj.exits[sOpp] then room.exits[sDir] = true @@ -411,34 +411,34 @@ local function getRoom( x, y, z, dontCreate ) end if y == -1 then - local above = getRoom( x, y + 1, z ) - if above.exits["down"] then - room.exits["up"] = true + local above = getRoom(x, y + 1, z) + if above.exits.down then + room.exits.up = true room.items["an exit to the surface"] = items["an exit to the surface"] end else - tryExit( "up", "down", x, y + 1, z ) + tryExit("up", "down", x, y + 1, z) end if y > -3 then - tryExit( "down", "up", x, y - 1, z ) + tryExit("down", "up", x, y - 1, z) end - tryExit( "east", "west", x - 1, y, z ) - tryExit( "west", "east", x + 1, y, z ) - tryExit( "north", "south", x, y, z + 1 ) - tryExit( "south", "north", x, y, z - 1 ) + tryExit("east", "west", x - 1, y, z) + tryExit("west", "east", x + 1, y, z) + tryExit("north", "south", x, y, z + 1) + tryExit("south", "north", x, y, z - 1) -- Add ores - room.items[ "some stone" ] = items[ "some stone" ] + room.items["some stone"] = items["some stone"] if math.random(1, 3) == 1 then - room.items[ "some coal" ] = items[ "some coal" ] + room.items["some coal"] = items["some coal"] end if math.random(1, 8) == 1 then - room.items[ "some iron" ] = items[ "some iron" ] + room.items["some iron"] = items["some iron"] end if y == -3 and math.random(1, 15) == 1 then - room.items[ "some diamond" ] = items[ "some diamond" ] + room.items["some diamond"] = items["some diamond"] end -- Turn out the lights @@ -448,8 +448,8 @@ local function getRoom( x, y, z, dontCreate ) return tMap[x][y][z] end -local function itemize( t ) - local item = next( t ) +local function itemize(t) + local item = next(t) if item == nil then return "nothing" end @@ -458,9 +458,9 @@ local function itemize( t ) while item do text = text .. item - local nextItem = next( t, item ) + local nextItem = next(t, item) if nextItem ~= nil then - local nextNextItem = next( t, nextItem ) + local nextNextItem = next(t, nextItem) if nextNextItem == nil then text = text .. " and " else @@ -472,13 +472,13 @@ local function itemize( t ) return text end -local function findItem( _tList, _sQuery ) - for sItem, tItem in pairs( _tList ) do +local function findItem(_tList, _sQuery) + for sItem, tItem in pairs(_tList) do if sItem == _sQuery then return sItem end if tItem.aliases ~= nil then - for _, sAlias in pairs( tItem.aliases ) do + for _, sAlias in pairs(tItem.aliases) do if sAlias == _sQuery then return sItem end @@ -606,91 +606,91 @@ local tMatches = { } local commands = {} -local function doCommand( text ) +local function doCommand(text) if text == "" then - commands[ "noinput" ]() + commands.noinput() return end - for sCommand, t in pairs( tMatches ) do - for _, sMatch in pairs( t ) do - local tCaptures = { string.match( text, "^" .. sMatch .. "$" ) } + for sCommand, t in pairs(tMatches) do + for _, sMatch in pairs(t) do + local tCaptures = { string.match(text, "^" .. sMatch .. "$") } if #tCaptures ~= 0 then - local fnCommand = commands[ sCommand ] + local fnCommand = commands[sCommand] if #tCaptures == 1 and tCaptures[1] == sMatch then fnCommand() else - fnCommand( table.unpack( tCaptures ) ) + fnCommand(table.unpack(tCaptures)) end return end end end - commands[ "badinput" ]() + commands.badinput() end function commands.wait() - print( "Time passes..." ) + print("Time passes...") end -function commands.look( _sTarget ) - local room = getRoom( x, y, z ) +function commands.look(_sTarget) + local room = getRoom(x, y, z) if room.dark then - print( "It is pitch dark." ) + print("It is pitch dark.") return end if _sTarget == nil then -- Look at the world if y == 0 then - io.write( "You are standing " .. tBiomes[room.nBiome] .. ". " ) - print( tDayCycle[ getTimeOfDay() ] ) + io.write("You are standing " .. tBiomes[room.nBiome] .. ". ") + print(tDayCycle[getTimeOfDay()]) else - io.write( "You are underground. " ) - if next( room.exits ) ~= nil then - print( "You can travel " .. itemize( room.exits ) .. "." ) + io.write("You are underground. ") + if next(room.exits) ~= nil then + print("You can travel " .. itemize(room.exits) .. ".") else print() end end - if next( room.items ) ~= nil then - print( "There is " .. itemize( room.items ) .. " here." ) + if next(room.items) ~= nil then + print("There is " .. itemize(room.items) .. " here.") end if room.trees then - print( "There are trees here." ) + print("There are trees here.") end else -- Look at stuff if room.trees and (_sTarget == "tree" or _sTarget == "trees") then - print( "The trees look easy to break." ) + print("The trees look easy to break.") elseif _sTarget == "self" or _sTarget == "myself" then - print( "Very handsome." ) + print("Very handsome.") else local tItem = nil - local sItem = findItem( room.items, _sTarget ) + local sItem = findItem(room.items, _sTarget) if sItem then tItem = room.items[sItem] else - sItem = findItem( inventory, _sTarget ) + sItem = findItem(inventory, _sTarget) if sItem then tItem = inventory[sItem] end end if tItem then - print( tItem.desc or "You see nothing special about " .. sItem .. "." ) + print(tItem.desc or "You see nothing special about " .. sItem .. ".") else - print( "You don't see any " .. _sTarget .. " here." ) + print("You don't see any " .. _sTarget .. " here.") end end end end -function commands.go( _sDir ) - local room = getRoom( x, y, z ) +function commands.go(_sDir) + local room = getRoom(x, y, z) if _sDir == nil then - print( "Go where?" ) + print("Go where?") return end @@ -700,7 +700,7 @@ function commands.go( _sDir ) if nGoWest > #tGoWest then nGoWest = 1 end - print( tGoWest[ nGoWest ] ) + print(tGoWest[nGoWest]) else if nGoWest > 0 or nTurn > 6 then nGoWest = nil @@ -709,7 +709,7 @@ function commands.go( _sDir ) end if room.exits[_sDir] == nil then - print( "You can't go that way." ) + print("You can't go that way.") return end @@ -726,98 +726,98 @@ function commands.go( _sDir ) elseif _sDir == "down" then y = y - 1 else - print( "I don't understand that direction." ) + print("I don't understand that direction.") return end nTimeInRoom = 0 - doCommand( "look" ) + doCommand("look") end -function commands.dig( _sDir, _sTool ) - local room = getRoom( x, y, z ) +function commands.dig(_sDir, _sTool) + local room = getRoom(x, y, z) if _sDir == nil then - print( "Dig where?" ) + print("Dig where?") return end local sTool = nil local tTool = nil if _sTool ~= nil then - sTool = findItem( inventory, _sTool ) + sTool = findItem(inventory, _sTool) if not sTool then - print( "You're not carrying a " .. _sTool .. "." ) + print("You're not carrying a " .. _sTool .. ".") return end - tTool = inventory[ sTool ] + tTool = inventory[sTool] end - local bActuallyDigging = room.exits[ _sDir ] ~= true + local bActuallyDigging = room.exits[_sDir] ~= true if bActuallyDigging then if sTool == nil or tTool.toolType ~= "pick" then - print( "You need to use a pickaxe to dig through stone." ) + print("You need to use a pickaxe to dig through stone.") return end end if _sDir == "north" then - room.exits["north"] = true + room.exits.north = true z = z + 1 - getRoom( x, y, z ).exits["south"] = true + getRoom(x, y, z).exits.south = true elseif _sDir == "south" then - room.exits["south"] = true + room.exits.south = true z = z - 1 - getRoom( x, y, z ).exits["north"] = true + getRoom(x, y, z).exits.north = true elseif _sDir == "east" then - room.exits["east"] = true + room.exits.east = true x = x - 1 - getRoom( x, y, z ).exits["west"] = true + getRoom(x, y, z).exits.west = true elseif _sDir == "west" then - room.exits["west"] = true + room.exits.west = true x = x + 1 - getRoom( x, y, z ).exits["east"] = true + getRoom(x, y, z).exits.east = true elseif _sDir == "up" then if y == 0 then - print( "You can't dig that way." ) + print("You can't dig that way.") return end - room.exits["up"] = true + room.exits.up = true if y == -1 then - room.items[ "an exit to the surface" ] = items[ "an exit to the surface" ] + room.items["an exit to the surface"] = items["an exit to the surface"] end y = y + 1 - room = getRoom( x, y, z ) - room.exits["down"] = true + room = getRoom(x, y, z) + room.exits.down = true if y == 0 then - room.items[ "a cave entrance" ] = items[ "a cave entrance" ] + room.items["a cave entrance"] = items["a cave entrance"] end elseif _sDir == "down" then if y <= -3 then - print( "You hit bedrock." ) + print("You hit bedrock.") return end - room.exits["down"] = true + room.exits.down = true if y == 0 then - room.items[ "a cave entrance" ] = items[ "a cave entrance" ] + room.items["a cave entrance"] = items["a cave entrance"] end y = y - 1 - room = getRoom( x, y, z ) - room.exits["up"] = true + room = getRoom(x, y, z) + room.exits.up = true if y == -1 then - room.items[ "an exit to the surface" ] = items[ "an exit to the surface" ] + room.items["an exit to the surface"] = items["an exit to the surface"] end else - print( "I don't understand that direction." ) + print("I don't understand that direction.") return end @@ -825,179 +825,179 @@ function commands.dig( _sDir, _sTool ) if bActuallyDigging then if _sDir == "down" and y == -1 or _sDir == "up" and y == 0 then - inventory[ "some dirt" ] = items[ "some dirt" ] - inventory[ "some stone" ] = items[ "some stone" ] - print( "You dig " .. _sDir .. " using " .. sTool .. " and collect some dirt and stone." ) + inventory["some dirt"] = items["some dirt"] + inventory["some stone"] = items["some stone"] + print("You dig " .. _sDir .. " using " .. sTool .. " and collect some dirt and stone.") else - inventory[ "some stone" ] = items[ "some stone" ] - print( "You dig " .. _sDir .. " using " .. sTool .. " and collect some stone." ) + inventory["some stone"] = items["some stone"] + print("You dig " .. _sDir .. " using " .. sTool .. " and collect some stone.") end end nTimeInRoom = 0 - doCommand( "look" ) + doCommand("look") end function commands.inventory() - print( "You are carrying " .. itemize( inventory ) .. "." ) + print("You are carrying " .. itemize(inventory) .. ".") end -function commands.drop( _sItem ) +function commands.drop(_sItem) if _sItem == nil then - print( "Drop what?" ) + print("Drop what?") return end - local room = getRoom( x, y, z ) - local sItem = findItem( inventory, _sItem ) + local room = getRoom(x, y, z) + local sItem = findItem(inventory, _sItem) if sItem then - local tItem = inventory[ sItem ] + local tItem = inventory[sItem] if tItem.droppable == false then - print( "You can't drop that." ) + print("You can't drop that.") else - room.items[ sItem ] = tItem - inventory[ sItem ] = nil - print( "Dropped." ) + room.items[sItem] = tItem + inventory[sItem] = nil + print("Dropped.") end else - print( "You don't have a " .. _sItem .. "." ) + print("You don't have a " .. _sItem .. ".") end end -function commands.place( _sItem ) +function commands.place(_sItem) if _sItem == nil then - print( "Place what?" ) + print("Place what?") return end if _sItem == "torch" or _sItem == "a torch" then - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) if inventory["some torches"] or inventory["a torch"] then inventory["a torch"] = nil room.items["a torch"] = items["a torch"] if room.dark then - print( "The cave lights up under the torchflame." ) + print("The cave lights up under the torchflame.") room.dark = false elseif y == 0 and not isSunny() then - print( "The night gets a little brighter." ) + print("The night gets a little brighter.") else - print( "Placed." ) + print("Placed.") end else - print( "You don't have torches." ) + print("You don't have torches.") end return end - commands.drop( _sItem ) + commands.drop(_sItem) end -function commands.take( _sItem ) +function commands.take(_sItem) if _sItem == nil then - print( "Take what?" ) + print("Take what?") return end - local room = getRoom( x, y, z ) - local sItem = findItem( room.items, _sItem ) + local room = getRoom(x, y, z) + local sItem = findItem(room.items, _sItem) if sItem then - local tItem = room.items[ sItem ] + local tItem = room.items[sItem] if tItem.heavy == true then - print( "You can't carry " .. sItem .. "." ) + print("You can't carry " .. sItem .. ".") elseif tItem.ore == true then - print( "You need to mine this ore." ) + print("You need to mine this ore.") else if tItem.infinite ~= true then - room.items[ sItem ] = nil + room.items[sItem] = nil end - inventory[ sItem ] = tItem + inventory[sItem] = tItem if inventory["some torches"] and inventory["a torch"] then inventory["a torch"] = nil end if sItem == "a torch" and y < 0 then room.dark = true - print( "The cave plunges into darkness." ) + print("The cave plunges into darkness.") else - print( "Taken." ) + print("Taken.") end end else - print( "You don't see a " .. _sItem .. " here." ) + print("You don't see a " .. _sItem .. " here.") end end -function commands.mine( _sItem, _sTool ) +function commands.mine(_sItem, _sTool) if _sItem == nil then - print( "Mine what?" ) + print("Mine what?") return end if _sTool == nil then - print( "Mine " .. _sItem .. " with what?" ) + print("Mine " .. _sItem .. " with what?") return end - commands.cbreak( _sItem, _sTool ) + commands.cbreak(_sItem, _sTool) end -function commands.attack( _sItem, _sTool ) +function commands.attack(_sItem, _sTool) if _sItem == nil then - print( "Attack what?" ) + print("Attack what?") return end - commands.cbreak( _sItem, _sTool ) + commands.cbreak(_sItem, _sTool) end -function commands.cbreak( _sItem, _sTool ) +function commands.cbreak(_sItem, _sTool) if _sItem == nil then - print( "Break what?" ) + print("Break what?") return end local sTool = nil if _sTool ~= nil then - sTool = findItem( inventory, _sTool ) + sTool = findItem(inventory, _sTool) if sTool == nil then - print( "You're not carrying a " .. _sTool .. "." ) + print("You're not carrying a " .. _sTool .. ".") return end end - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) if _sItem == "tree" or _sItem == "trees" or _sItem == "a tree" then - print( "The tree breaks into blocks of wood, which you pick up." ) - inventory[ "some wood" ] = items[ "some wood" ] + print("The tree breaks into blocks of wood, which you pick up.") + inventory["some wood"] = items["some wood"] return elseif _sItem == "self" or _sItem == "myself" then if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You have died." ) - print( "Score: &e0" ) - term.setTextColour( colours.white ) + print("You have died.") + print("Score: &e0") + term.setTextColour(colours.white) bRunning = false return end - local sItem = findItem( room.items, _sItem ) + local sItem = findItem(room.items, _sItem) if sItem then - local tItem = room.items[ sItem ] + local tItem = room.items[sItem] if tItem.ore == true then -- Breaking ore if not sTool then - print( "You need a tool to break this ore." ) + print("You need a tool to break this ore.") return end - local tTool = inventory[ sTool ] + local tTool = inventory[sTool] if tTool.tool then if tTool.toolLevel < tItem.toolLevel then - print( sTool .. " is not strong enough to break this ore." ) + print(sTool .. " is not strong enough to break this ore.") elseif tTool.toolType ~= tItem.toolType then - print( "You need a different kind of tool to break this ore." ) + print("You need a different kind of tool to break this ore.") else - print( "The ore breaks, dropping " .. sItem .. ", which you pick up." ) - inventory[ sItem ] = items[ sItem ] + print("The ore breaks, dropping " .. sItem .. ", which you pick up.") + inventory[sItem] = items[sItem] if tItem.infinite ~= true then - room.items[ sItem ] = nil + room.items[sItem] = nil end end else @@ -1009,21 +1009,21 @@ function commands.cbreak( _sItem, _sTool ) local toolLevel = 0 local tTool = nil if sTool then - tTool = inventory[ sTool ] + tTool = inventory[sTool] if tTool.toolType == "sword" then toolLevel = tTool.toolLevel end end local tChances = { 0.2, 0.4, 0.55, 0.8, 1 } - if math.random() <= tChances[ toolLevel + 1 ] then - room.items[ sItem ] = nil - print( "The " .. tItem.aliases[1] .. " dies." ) + if math.random() <= tChances[toolLevel + 1] then + room.items[sItem] = nil + print("The " .. tItem.aliases[1] .. " dies.") if tItem.drops then - for _, sDrop in pairs( tItem.drops ) do + for _, sDrop in pairs(tItem.drops) do if not room.items[sDrop] then - print( "The " .. tItem.aliases[1] .. " dropped " .. sDrop .. "." ) + print("The " .. tItem.aliases[1] .. " dropped " .. sDrop .. ".") room.items[sDrop] = items[sDrop] end end @@ -1033,112 +1033,112 @@ function commands.cbreak( _sItem, _sTool ) room.nMonsters = room.nMonsters - 1 end else - print( "The " .. tItem.aliases[1] .. " is injured by your blow." ) + print("The " .. tItem.aliases[1] .. " is injured by your blow.") end if tItem.hitDrops then - for _, sDrop in pairs( tItem.hitDrops ) do + for _, sDrop in pairs(tItem.hitDrops) do if not room.items[sDrop] then - print( "The " .. tItem.aliases[1] .. " dropped " .. sDrop .. "." ) + print("The " .. tItem.aliases[1] .. " dropped " .. sDrop .. ".") room.items[sDrop] = items[sDrop] end end end else - print( "You can't break " .. sItem .. "." ) + print("You can't break " .. sItem .. ".") end else - print( "You don't see a " .. _sItem .. " here." ) + print("You don't see a " .. _sItem .. " here.") end end -function commands.craft( _sItem ) +function commands.craft(_sItem) if _sItem == nil then - print( "Craft what?" ) + print("Craft what?") return end if _sItem == "computer" or _sItem == "a computer" then - print( "By creating a computer in a computer in a computer, you tear a hole in the spacetime continuum from which no mortal being can escape." ) + print("By creating a computer in a computer in a computer, you tear a hole in the spacetime continuum from which no mortal being can escape.") if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You have died." ) - print( "Score: &e0" ) - term.setTextColour( colours.white ) + print("You have died.") + print("Score: &e0") + term.setTextColour(colours.white) bRunning = false return end - local sItem = findItem( items, _sItem ) - local tRecipe = sItem and tRecipes[ sItem ] or nil + local sItem = findItem(items, _sItem) + local tRecipe = sItem and tRecipes[sItem] or nil if tRecipe then - for _, sReq in ipairs( tRecipe ) do + for _, sReq in ipairs(tRecipe) do if inventory[sReq] == nil then - print( "You don't have the items you need to craft " .. sItem .. "." ) + print("You don't have the items you need to craft " .. sItem .. ".") return end end - for _, sReq in ipairs( tRecipe ) do + for _, sReq in ipairs(tRecipe) do inventory[sReq] = nil end - inventory[ sItem ] = items[ sItem ] + inventory[sItem] = items[sItem] if inventory["some torches"] and inventory["a torch"] then inventory["a torch"] = nil end - print( "Crafted." ) + print("Crafted.") else - print( "You don't know how to make " .. (sItem or _sItem) .. "." ) + print("You don't know how to make " .. (sItem or _sItem) .. ".") end end -function commands.build( _sThing, _sMaterial ) +function commands.build(_sThing, _sMaterial) if _sThing == nil then - print( "Build what?" ) + print("Build what?") return end local sMaterial = nil if _sMaterial == nil then - for sItem, tItem in pairs( inventory ) do + for sItem, tItem in pairs(inventory) do if tItem.material then sMaterial = sItem break end end if sMaterial == nil then - print( "You don't have any building materials." ) + print("You don't have any building materials.") return end else - sMaterial = findItem( inventory, _sMaterial ) + sMaterial = findItem(inventory, _sMaterial) if not sMaterial then - print( "You don't have any " .. _sMaterial ) + print("You don't have any " .. _sMaterial) return end if inventory[sMaterial].material ~= true then - print( sMaterial .. " is not a good building material." ) + print(sMaterial .. " is not a good building material.") return end end local alias = nil if string.sub(_sThing, 1, 1) == "a" then - alias = string.match( _sThing, "a ([%a ]+)" ) + alias = string.match(_sThing, "a ([%a ]+)") end - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) inventory[sMaterial] = nil - room.items[ _sThing ] = { + room.items[_sThing] = { heavy = true, aliases = { alias }, desc = "As you look at your creation (made from " .. sMaterial .. "), you feel a swelling sense of pride.", } - print( "Your construction is complete." ) + print("Your construction is complete.") end function commands.help() @@ -1147,32 +1147,32 @@ function commands.help() "To get around the world, type actions, and the adventure will " .. "be read back to you. The actions availiable to you are go, look, inspect, inventory, " .. "take, drop, place, punch, attack, mine, dig, craft, build, eat and exit." - print( sText ) + print(sText) end -function commands.eat( _sItem ) +function commands.eat(_sItem) if _sItem == nil then - print( "Eat what?" ) + print("Eat what?") return end - local sItem = findItem( inventory, _sItem ) + local sItem = findItem(inventory, _sItem) if not sItem then - print( "You don't have any " .. _sItem .. "." ) + print("You don't have any " .. _sItem .. ".") return end local tItem = inventory[sItem] if tItem.food then - print( "That was delicious!" ) + print("That was delicious!") inventory[sItem] = nil if bInjured then - print( "You are no longer injured." ) + print("You are no longer injured.") bInjured = false end else - print( "You can't eat " .. sItem .. "." ) + print("You can't eat " .. sItem .. ".") end end @@ -1195,7 +1195,7 @@ function commands.badinput() "That doesn't make any sense.", "What?", } - print( tResponses[ math.random(1, #tResponses) ] ) + print(tResponses[math.random(1, #tResponses)]) end function commands.noinput() @@ -1206,7 +1206,7 @@ function commands.noinput() "Don't be shy.", "Use your words.", } - print( tResponses[ math.random(1, #tResponses) ] ) + print(tResponses[math.random(1, #tResponses)]) end local function simulate() @@ -1218,20 +1218,20 @@ local function simulate() for sz = -2, 2 do local h = y + sy if h >= -3 and h <= 0 then - local room = getRoom( x + sx, h, z + sz ) + local room = getRoom(x + sx, h, z + sz) -- Spawn monsters if room.nMonsters < 2 and (h == 0 and not isSunny() and not room.items["a torch"] or room.dark) and math.random(1, 6) == 1 then - local sMonster = tMonsters[ math.random(1, #tMonsters) ] - if room.items[ sMonster ] == nil then - room.items[ sMonster ] = items[ sMonster ] + local sMonster = tMonsters[math.random(1, #tMonsters)] + if room.items[sMonster] == nil then + room.items[sMonster] = items[sMonster] room.nMonsters = room.nMonsters + 1 if sx == 0 and sy == 0 and sz == 0 and not room.dark then - print( "From the shadows, " .. sMonster .. " appears." ) + print("From the shadows, " .. sMonster .. " appears.") bNewMonstersThisRoom = true end end @@ -1239,11 +1239,11 @@ local function simulate() -- Burn monsters if h == 0 and isSunny() then - for _, sMonster in ipairs( tMonsters ) do + for _, sMonster in ipairs(tMonsters) do if room.items[sMonster] and items[sMonster].nocturnal then room.items[sMonster] = nil if sx == 0 and sy == 0 and sz == 0 and not room.dark then - print( "With the sun high in the sky, the " .. items[sMonster].aliases[1] .. " bursts into flame and dies." ) + print("With the sun high in the sky, the " .. items[sMonster].aliases[1] .. " bursts into flame and dies.") end room.nMonsters = room.nMonsters - 1 end @@ -1255,35 +1255,35 @@ local function simulate() end -- Make monsters attack - local room = getRoom( x, y, z ) + local room = getRoom(x, y, z) if nTimeInRoom >= 2 and not bNewMonstersThisRoom then - for _, sMonster in ipairs( tMonsters ) do + for _, sMonster in ipairs(tMonsters) do if room.items[sMonster] then if math.random(1, 4) == 1 and not (y == 0 and isSunny() and sMonster == "a spider") then if sMonster == "a creeper" then if room.dark then - print( "A creeper explodes." ) + print("A creeper explodes.") else - print( "The creeper explodes." ) + print("The creeper explodes.") end room.items[sMonster] = nil room.nMonsters = room.nMonsters - 1 else if room.dark then - print( "A " .. items[sMonster].aliases[1] .. " attacks you." ) + print("A " .. items[sMonster].aliases[1] .. " attacks you.") else - print( "The " .. items[sMonster].aliases[1] .. " attacks you." ) + print("The " .. items[sMonster].aliases[1] .. " attacks you.") end end if bInjured then if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You have died." ) - print( "Score: &e0" ) - term.setTextColour( colours.white ) + print("You have died.") + print("Score: &e0") + term.setTextColour(colours.white) bRunning = false return else @@ -1299,10 +1299,10 @@ local function simulate() -- Always print this if bInjured then if term.isColour() then - term.setTextColour( colours.red ) + term.setTextColour(colours.red) end - print( "You are injured." ) - term.setTextColour( colours.white ) + print("You are injured.") + term.setTextColour(colours.white) end -- Advance time @@ -1310,19 +1310,19 @@ local function simulate() nTimeInRoom = nTimeInRoom + 1 end -doCommand( "look" ) +doCommand("look") simulate() local tCommandHistory = {} while bRunning do if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end - write( "? " ) - term.setTextColour( colours.white ) + write("? ") + term.setTextColour(colours.white) - local sRawLine = read( nil, tCommandHistory ) - table.insert( tCommandHistory, sRawLine ) + local sRawLine = read(nil, tCommandHistory) + table.insert(tCommandHistory, sRawLine) local sLine = nil for match in string.gmatch(sRawLine, "%a+") do @@ -1333,7 +1333,7 @@ while bRunning do end end - doCommand( sLine or "" ) + doCommand(sLine or "") if bRunning then simulate() end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua index 5ec03d2ce..322b4a887 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/dj.lua @@ -1,10 +1,10 @@ local tArgs = { ... } local function printUsage() - print( "Usages:" ) - print( "dj play" ) - print( "dj play " ) - print( "dj stop" ) + print("Usages:") + print("dj play") + print("dj play ") + print("dj stop") end if #tArgs > 2 then @@ -23,24 +23,24 @@ elseif sCommand == "play" or sCommand == nil then if sName == nil then -- No disc specified, pick one at random local tNames = {} - for _, sName in ipairs( peripheral.getNames() ) do - if disk.isPresent( sName ) and disk.hasAudio( sName ) then - table.insert( tNames, sName ) + for _, sName in ipairs(peripheral.getNames()) do + if disk.isPresent(sName) and disk.hasAudio(sName) then + table.insert(tNames, sName) end end if #tNames == 0 then - print( "No Music Discs in attached disk drives" ) + print("No Music Discs in attached disk drives") return end - sName = tNames[ math.random(1, #tNames) ] + sName = tNames[math.random(1, #tNames)] end -- Play the disc - if disk.isPresent( sName ) and disk.hasAudio( sName ) then - print( "Playing " .. disk.getAudioTitle( sName ) ) - disk.playAudio( sName ) + if disk.isPresent(sName) and disk.hasAudio(sName) then + print("Playing " .. disk.getAudioTitle(sName)) + disk.playAudio(sName) else - print( "No Music Disc in disk drive: " .. sName ) + print("No Music Disc in disk drive: " .. sName) return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua index d22399410..0afdf9e77 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/hello.lua @@ -1,5 +1,5 @@ if term.isColour() then - term.setTextColour( 2 ^ math.random(0, 15) ) + term.setTextColour(2 ^ math.random(0, 15)) end -textutils.slowPrint( "Hello World!" ) -term.setTextColour( colours.white ) +textutils.slowPrint("Hello World!") +term.setTextColour(colours.white) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua index e02654d1f..fe753b032 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua @@ -15,11 +15,11 @@ else fruitColour = colours.white end -local function printCentred( y, s ) +local function printCentred(y, s) local x = math.floor((w - #s) / 2) term.setCursorPos(x, y) --term.clearLine() - term.write( s ) + term.write(s) end local xVel, yVel = 1, 0 @@ -65,9 +65,9 @@ local function addFruit() if fruit.snake == nil and fruit.wall == nil and fruit.fruit == nil then screen[x][y] = { fruit = true } term.setCursorPos(x, y) - term.setBackgroundColour( fruitColour ) + term.setBackgroundColour(fruitColour) term.write(" ") - term.setBackgroundColour( colours.black ) + term.setBackgroundColour(colours.black) break end end @@ -79,23 +79,23 @@ local function addFruit() end local function drawMenu() - term.setTextColour( headingColour ) + term.setTextColour(headingColour) term.setCursorPos(1, 1) - term.write( "SCORE " ) + term.write("SCORE ") - term.setTextColour( textColour ) + term.setTextColour(textColour) term.setCursorPos(7, 1) - term.write( tostring(nScore) ) + term.write(tostring(nScore)) - term.setTextColour( headingColour ) + term.setTextColour(headingColour) term.setCursorPos(w - 11, 1) - term.write( "DIFFICULTY " ) + term.write("DIFFICULTY ") - term.setTextColour( textColour ) + term.setTextColour(textColour) term.setCursorPos(w, 1) - term.write( tostring(nDifficulty or "?") ) + term.write(tostring(nDifficulty or "?")) - term.setTextColour( colours.white ) + term.setTextColour(colours.white) end local function update( ) @@ -150,9 +150,9 @@ local function update( ) end term.setCursorPos(xPos, yPos) - term.setBackgroundColour( wormColour ) + term.setBackgroundColour(wormColour) term.write(" ") - term.setBackgroundColour( colours.black ) + term.setBackgroundColour(colours.black) drawMenu() end @@ -163,29 +163,29 @@ local function drawFrontend() --term.setTextColour( titleColour ) --printCentred( math.floor(h/2) - 4, " W O R M " ) - term.setTextColour( headingColour ) - printCentred( math.floor(h / 2) - 3, "" ) - printCentred( math.floor(h / 2) - 2, " SELECT DIFFICULTY " ) - printCentred( math.floor(h / 2) - 1, "" ) + term.setTextColour(headingColour) + printCentred(math.floor(h / 2) - 3, "") + printCentred(math.floor(h / 2) - 2, " SELECT DIFFICULTY ") + printCentred(math.floor(h / 2) - 1, "") - printCentred( math.floor(h / 2) + 0, " " ) - printCentred( math.floor(h / 2) + 1, " " ) - printCentred( math.floor(h / 2) + 2, " " ) - printCentred( math.floor(h / 2) - 1 + nDifficulty, " [ ] " ) + printCentred(math.floor(h / 2) + 0, " ") + printCentred(math.floor(h / 2) + 1, " ") + printCentred(math.floor(h / 2) + 2, " ") + printCentred(math.floor(h / 2) - 1 + nDifficulty, " [ ] ") - term.setTextColour( textColour ) - printCentred( math.floor(h / 2) + 0, "EASY" ) - printCentred( math.floor(h / 2) + 1, "MEDIUM" ) - printCentred( math.floor(h / 2) + 2, "HARD" ) - printCentred( math.floor(h / 2) + 3, "" ) + term.setTextColour(textColour) + printCentred(math.floor(h / 2) + 0, "EASY") + printCentred(math.floor(h / 2) + 1, "MEDIUM") + printCentred(math.floor(h / 2) + 2, "HARD") + printCentred(math.floor(h / 2) + 3, "") - term.setTextColour( colours.white ) + term.setTextColour(colours.white) end drawMenu() drawFrontend() while true do - local _, key = os.pullEvent( "key" ) + local _, key = os.pullEvent("key") if key == keys.up or key == keys.w then -- Up if nDifficulty > 1 then @@ -226,7 +226,7 @@ while bRunning do local event, p1 = os.pullEvent() if event == "timer" and p1 == timer then timer = os.startTimer(nInterval) - update( false ) + update(false) elseif event == "key" then local key = p1 @@ -257,24 +257,24 @@ while bRunning do end -- Display the gameover screen -term.setTextColour( headingColour ) -printCentred( math.floor(h / 2) - 2, " " ) -printCentred( math.floor(h / 2) - 1, " G A M E O V E R " ) +term.setTextColour(headingColour) +printCentred(math.floor(h / 2) - 2, " ") +printCentred(math.floor(h / 2) - 1, " G A M E O V E R ") -term.setTextColour( textColour ) -printCentred( math.floor(h / 2) + 0, " " ) -printCentred( math.floor(h / 2) + 1, " FINAL SCORE " .. nScore .. " " ) -printCentred( math.floor(h / 2) + 2, " " ) -term.setTextColour( colours.white ) +term.setTextColour(textColour) +printCentred(math.floor(h / 2) + 0, " ") +printCentred(math.floor(h / 2) + 1, " FINAL SCORE " .. nScore .. " ") +printCentred(math.floor(h / 2) + 2, " ") +term.setTextColour(colours.white) local timer = os.startTimer(2.5) repeat local e, p = os.pullEvent() if e == "timer" and p == timer then - term.setTextColour( textColour ) - printCentred( math.floor(h / 2) + 2, " PRESS ANY KEY " ) - printCentred( math.floor(h / 2) + 3, " " ) - term.setTextColour( colours.white ) + term.setTextColour(textColour) + printCentred(math.floor(h / 2) + 2, " PRESS ANY KEY ") + printCentred(math.floor(h / 2) + 3, " ") + term.setTextColour(colours.white) end until e == "char" diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua index c5556c079..9e1ff0538 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua @@ -1,9 +1,9 @@ local function printUsage() - print( "Usages:" ) - print( "gps host" ) - print( "gps host " ) - print( "gps locate" ) + print("Usages:") + print("gps host") + print("gps host ") + print("gps locate") end local tArgs = { ... } @@ -16,27 +16,27 @@ end if sCommand == "locate" then -- "gps locate" -- Just locate this computer (this will print the results) - gps.locate( 2, true ) + gps.locate(2, true) elseif sCommand == "host" then -- "gps host" -- Act as a GPS host if pocket then - print( "GPS Hosts must be stationary" ) + print("GPS Hosts must be stationary") return end -- Find a modem local sModemSide = nil - for _, sSide in ipairs( rs.getSides() ) do - if peripheral.getType( sSide ) == "modem" and peripheral.call( sSide, "isWireless" ) then + for _, sSide in ipairs(rs.getSides()) do + if peripheral.getType(sSide) == "modem" and peripheral.call(sSide, "isWireless") then sModemSide = sSide break end end if sModemSide == nil then - print( "No wireless modems found. 1 required." ) + print("No wireless modems found. 1 required.") return end @@ -51,31 +51,31 @@ elseif sCommand == "host" then printUsage() return end - print( "Position is " .. x .. "," .. y .. "," .. z ) + print("Position is " .. x .. "," .. y .. "," .. z) else -- Position is to be determined using locate - x, y, z = gps.locate( 2, true ) + x, y, z = gps.locate(2, true) if x == nil then - print( "Run \"gps host \" to set position manually" ) + print("Run \"gps host \" to set position manually") return end end -- Open a channel - local modem = peripheral.wrap( sModemSide ) - print( "Opening channel on modem " .. sModemSide ) - modem.open( gps.CHANNEL_GPS ) + local modem = peripheral.wrap(sModemSide) + print("Opening channel on modem " .. sModemSide) + modem.open(gps.CHANNEL_GPS) -- Serve requests indefinately local nServed = 0 while true do - local e, p1, p2, p3, p4, p5 = os.pullEvent( "modem_message" ) + local e, p1, p2, p3, p4, p5 = os.pullEvent("modem_message") if e == "modem_message" then -- We received a message from a modem local sSide, sChannel, sReplyChannel, sMessage, nDistance = p1, p2, p3, p4, p5 if sSide == sModemSide and sChannel == gps.CHANNEL_GPS and sMessage == "PING" and nDistance then -- We received a ping message on the GPS channel, send a response - modem.transmit( sReplyChannel, gps.CHANNEL_GPS, { x, y, z } ) + modem.transmit(sReplyChannel, gps.CHANNEL_GPS, { x, y, z }) -- Print the number of requests handled nServed = nServed + 1 @@ -83,7 +83,7 @@ elseif sCommand == "host" then local _, y = term.getCursorPos() term.setCursorPos(1, y - 1) end - print( nServed .. " GPS requests served" ) + print(nServed .. " GPS requests served") end end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/help.lua b/src/main/resources/assets/computercraft/lua/rom/programs/help.lua index c8653616a..63ece3ab4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/help.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/help.lua @@ -7,20 +7,20 @@ else end if sTopic == "index" then - print( "Help topics available:" ) + print("Help topics available:") local tTopics = help.topics() - textutils.pagedTabulate( tTopics ) + textutils.pagedTabulate(tTopics) return end -local sFile = help.lookup( sTopic ) -local file = sFile ~= nil and io.open( sFile ) or nil +local sFile = help.lookup(sTopic) +local file = sFile ~= nil and io.open(sFile) or nil if file then local sContents = file:read("*a") file:close() local _, nHeight = term.getSize() - textutils.pagedPrint( sContents, nHeight - 3 ) + textutils.pagedPrint(sContents, nHeight - 3) else - print( "No help available" ) + print("No help available") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua index 49266c20e..a45ea1a2a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua @@ -1,9 +1,9 @@ local function printUsage() - print( "Usages:" ) - print( "pastebin put " ) - print( "pastebin get " ) - print( "pastebin run " ) + print("Usages:") + print("pastebin put ") + print("pastebin get ") + print("pastebin run ") end local tArgs = { ... } @@ -13,8 +13,8 @@ if #tArgs < 2 then end if not http then - printError( "Pastebin requires the http API" ) - printError( "Set http.enabled to true in CC: Tweaked's config" ) + printError("Pastebin requires the http API") + printError("Set http.enabled to true in CC: Tweaked's config") return end @@ -29,7 +29,7 @@ local function extractId(paste) } for i = 1, #patterns do - local code = paste:match( patterns[i] ) + local code = paste:match(patterns[i]) if code then return code end end @@ -37,36 +37,36 @@ local function extractId(paste) end local function get(url) - local paste = extractId( url ) + local paste = extractId(url) if not paste then - io.stderr:write( "Invalid pastebin code.\n" ) - io.write( "The code is the ID at the end of the pastebin.com URL.\n" ) + io.stderr:write("Invalid pastebin code.\n") + io.write("The code is the ID at the end of the pastebin.com URL.\n") return end - write( "Connecting to pastebin.com... " ) + write("Connecting to pastebin.com... ") -- Add a cache buster so that spam protection is re-checked local cacheBuster = ("%x"):format(math.random(0, 2 ^ 30)) local response, err = http.get( - "https://pastebin.com/raw/" .. textutils.urlEncode( paste ) .. "?cb=" .. cacheBuster + "https://pastebin.com/raw/" .. textutils.urlEncode(paste) .. "?cb=" .. cacheBuster ) if response then -- If spam protection is activated, we get redirected to /paste with Content-Type: text/html local headers = response.getResponseHeaders() - if not headers["Content-Type"] or not headers["Content-Type"]:find( "^text/plain" ) then - io.stderr:write( "Failed.\n" ) - print( "Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode( paste ) ) + if not headers["Content-Type"] or not headers["Content-Type"]:find("^text/plain") then + io.stderr:write("Failed.\n") + print("Pastebin blocked the download due to spam protection. Please complete the captcha in a web browser: https://pastebin.com/" .. textutils.urlEncode(paste)) return end - print( "Success." ) + print("Success.") local sResponse = response.readAll() response.close() return sResponse else - io.stderr:write( "Failed.\n" ) + io.stderr:write("Failed.\n") print(err) end end @@ -76,20 +76,20 @@ if sCommand == "put" then -- Upload a file to pastebin.com -- Determine file to upload local sFile = tArgs[2] - local sPath = shell.resolve( sFile ) - if not fs.exists( sPath ) or fs.isDir( sPath ) then - print( "No such file" ) + local sPath = shell.resolve(sFile) + if not fs.exists(sPath) or fs.isDir(sPath) then + print("No such file") return end -- Read in the file - local sName = fs.getName( sPath ) - local file = fs.open( sPath, "r" ) + local sName = fs.getName(sPath) + local file = fs.open(sPath, "r") local sText = file.readAll() file.close() -- POST the contents to pastebin - write( "Connecting to pastebin.com... " ) + write("Connecting to pastebin.com... ") local key = "0ec2eb25b6166c0c27a394ae118ad829" local response = http.post( "https://pastebin.com/api/api_post.php", @@ -101,17 +101,17 @@ if sCommand == "put" then ) if response then - print( "Success." ) + print("Success.") local sResponse = response.readAll() response.close() - local sCode = string.match( sResponse, "[^/]+$" ) - print( "Uploaded as " .. sResponse ) - print( "Run \"pastebin get " .. sCode .. "\" to download anywhere" ) + local sCode = string.match(sResponse, "[^/]+$") + print("Uploaded as " .. sResponse) + print("Run \"pastebin get " .. sCode .. "\" to download anywhere") else - print( "Failed." ) + print("Failed.") end elseif sCommand == "get" then @@ -124,20 +124,20 @@ elseif sCommand == "get" then -- Determine file to download local sCode = tArgs[2] local sFile = tArgs[3] - local sPath = shell.resolve( sFile ) - if fs.exists( sPath ) then - print( "File already exists" ) + local sPath = shell.resolve(sFile) + if fs.exists(sPath) then + print("File already exists") return end -- GET the contents from pastebin local res = get(sCode) if res then - local file = fs.open( sPath, "w" ) - file.write( res ) + local file = fs.open(sPath, "w") + file.write(res) file.close() - print( "Downloaded as " .. sFile ) + print("Downloaded as " .. sFile) end elseif sCommand == "run" then local sCode = tArgs[2] @@ -146,12 +146,12 @@ elseif sCommand == "run" then if res then local func, err = load(res, sCode, "t", _ENV) if not func then - printError( err ) + printError(err) return end local success, msg = pcall(func, select(3, ...)) if not success then - printError( msg ) + printError(msg) end end else diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua index 6c5894e77..dbfa3aeb7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua @@ -1,15 +1,15 @@ local function printUsage() - print( "Usage:" ) - print( "wget [filename]" ) - print( "wget run " ) + print("Usage:") + print("wget [filename]") + print("wget run ") end local tArgs = { ... } local run = false if tArgs[1] == "run" then - table.remove( tArgs, 1 ) + table.remove(tArgs, 1) run = true end @@ -18,36 +18,36 @@ if #tArgs < 1 then return end -local url = table.remove( tArgs, 1 ) +local url = table.remove(tArgs, 1) if not http then - printError( "wget requires the http API" ) - printError( "Set http.enabled to true in CC: Tweaked's config" ) + printError("wget requires the http API") + printError("Set http.enabled to true in CC: Tweaked's config") return end -local function getFilename( sUrl ) - sUrl = sUrl:gsub( "[#?].*" , "" ):gsub( "/+$" , "" ) - return sUrl:match( "/([^/]+)$" ) +local function getFilename(sUrl) + sUrl = sUrl:gsub("[#?].*" , ""):gsub("/+$" , "") + return sUrl:match("/([^/]+)$") end -local function get( sUrl ) +local function get(sUrl) -- Check if the URL is valid - local ok, err = http.checkURL( url ) + local ok, err = http.checkURL(url) if not ok then - printError( err or "Invalid URL." ) + printError(err or "Invalid URL.") return end - write( "Connecting to " .. sUrl .. "... " ) + write("Connecting to " .. sUrl .. "... ") - local response = http.get( sUrl , nil , true ) + local response = http.get(sUrl , nil , true) if not response then - print( "Failed." ) + print("Failed.") return nil end - print( "Success." ) + print("Success.") local sResponse = response.readAll() response.close() @@ -66,22 +66,22 @@ if run then local ok, err = pcall(func, table.unpack(tArgs)) if not ok then - printError( err ) + printError(err) end else - local sFile = tArgs[1] or getFilename( url ) - local sPath = shell.resolve( sFile ) - if fs.exists( sPath ) then - print( "File already exists" ) + local sFile = tArgs[1] or getFilename(url) + local sPath = shell.resolve(sFile) + if fs.exists(sPath) then + print("File already exists") return end local res = get(url) if not res then return end - local file = fs.open( sPath, "wb" ) - file.write( res ) + local file = fs.open(sPath, "wb") + file.write(res) file.close() - print( "Downloaded as " .. sFile ) + print("Downloaded as " .. sFile) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/id.lua b/src/main/resources/assets/computercraft/lua/rom/programs/id.lua index 439fc9f3c..dda736612 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/id.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/id.lua @@ -2,28 +2,28 @@ local sDrive = nil local tArgs = { ... } if #tArgs > 0 then - sDrive = tostring( tArgs[1] ) + sDrive = tostring(tArgs[1]) end if sDrive == nil then - print( "This is computer #" .. os.getComputerID() ) + print("This is computer #" .. os.getComputerID()) local label = os.getComputerLabel() if label then - print( "This computer is labelled \"" .. label .. "\"" ) + print("This computer is labelled \"" .. label .. "\"") end else - local bData = disk.hasData( sDrive ) + local bData = disk.hasData(sDrive) if not bData then - print( "No disk in drive " .. sDrive ) + print("No disk in drive " .. sDrive) return end - print( "The disk is #" .. disk.getID( sDrive ) ) + print("The disk is #" .. disk.getID(sDrive)) - local label = disk.getLabel( sDrive ) + local label = disk.getLabel(sDrive) if label then - print( "The disk is labelled \"" .. label .. "\"" ) + print("The disk is labelled \"" .. label .. "\"") end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/label.lua b/src/main/resources/assets/computercraft/lua/rom/programs/label.lua index ea23277a9..d0e712a05 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/label.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/label.lua @@ -1,67 +1,67 @@ local function printUsage() - print( "Usages:" ) - print( "label get" ) - print( "label get " ) - print( "label set " ) - print( "label set " ) - print( "label clear" ) - print( "label clear " ) + print("Usages:") + print("label get") + print("label get ") + print("label set ") + print("label set ") + print("label clear") + print("label clear ") end -local function checkDrive( sDrive ) - if peripheral.getType( sDrive ) == "drive" then +local function checkDrive(sDrive) + if peripheral.getType(sDrive) == "drive" then -- Check the disk exists - local bData = disk.hasData( sDrive ) + local bData = disk.hasData(sDrive) if not bData then - print( "No disk in " .. sDrive .. " drive" ) + print("No disk in " .. sDrive .. " drive") return false end else - print( "No disk drive named " .. sDrive ) + print("No disk drive named " .. sDrive) return false end return true end -local function get( sDrive ) +local function get(sDrive) if sDrive ~= nil then - if checkDrive( sDrive ) then - local sLabel = disk.getLabel( sDrive ) + if checkDrive(sDrive) then + local sLabel = disk.getLabel(sDrive) if sLabel then - print( "Disk label is \"" .. sLabel .. "\"" ) + print("Disk label is \"" .. sLabel .. "\"") else - print( "No Disk label" ) + print("No Disk label") end end else local sLabel = os.getComputerLabel() if sLabel then - print( "Computer label is \"" .. sLabel .. "\"" ) + print("Computer label is \"" .. sLabel .. "\"") else - print( "No Computer label" ) + print("No Computer label") end end end -local function set( sDrive, sText ) +local function set(sDrive, sText) if sDrive ~= nil then - if checkDrive( sDrive ) then - disk.setLabel( sDrive, sText ) - local sLabel = disk.getLabel( sDrive ) + if checkDrive(sDrive) then + disk.setLabel(sDrive, sText) + local sLabel = disk.getLabel(sDrive) if sLabel then - print( "Disk label set to \"" .. sLabel .. "\"" ) + print("Disk label set to \"" .. sLabel .. "\"") else - print( "Disk label cleared" ) + print("Disk label cleared") end end else - os.setComputerLabel( sText ) + os.setComputerLabel(sText) local sLabel = os.getComputerLabel() if sLabel then - print( "Computer label set to \"" .. sLabel .. "\"" ) + print("Computer label set to \"" .. sLabel .. "\"") else - print( "Computer label cleared" ) + print("Computer label cleared") end end end @@ -71,27 +71,27 @@ local sCommand = tArgs[1] if sCommand == "get" then -- Get a label if #tArgs == 1 then - get( nil ) + get(nil) elseif #tArgs == 2 then - get( tArgs[2] ) + get(tArgs[2]) else printUsage() end elseif sCommand == "set" then -- Set a label if #tArgs == 2 then - set( nil, tArgs[2] ) + set(nil, tArgs[2]) elseif #tArgs == 3 then - set( tArgs[2], tArgs[3] ) + set(tArgs[2], tArgs[3]) else printUsage() end elseif sCommand == "clear" then -- Clear a label if #tArgs == 1 then - set( nil, nil ) + set(nil, nil) elseif #tArgs == 2 then - set( tArgs[2], nil ) + set(tArgs[2], nil) else printUsage() end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/list.lua b/src/main/resources/assets/computercraft/lua/rom/programs/list.lua index f493d8ae5..759130bb6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/list.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/list.lua @@ -4,35 +4,35 @@ local tArgs = { ... } -- Get all the files in the directory local sDir = shell.dir() if tArgs[1] ~= nil then - sDir = shell.resolve( tArgs[1] ) + sDir = shell.resolve(tArgs[1]) end -if not fs.isDir( sDir ) then - printError( "Not a directory" ) +if not fs.isDir(sDir) then + printError("Not a directory") return end -- Sort into dirs/files, and calculate column count -local tAll = fs.list( sDir ) +local tAll = fs.list(sDir) local tFiles = {} local tDirs = {} -local bShowHidden = settings.get( "list.show_hidden" ) -for _, sItem in pairs( tAll ) do - if bShowHidden or string.sub( sItem, 1, 1 ) ~= "." then - local sPath = fs.combine( sDir, sItem ) - if fs.isDir( sPath ) then - table.insert( tDirs, sItem ) +local bShowHidden = settings.get("list.show_hidden") +for _, sItem in pairs(tAll) do + if bShowHidden or string.sub(sItem, 1, 1) ~= "." then + local sPath = fs.combine(sDir, sItem) + if fs.isDir(sPath) then + table.insert(tDirs, sItem) else - table.insert( tFiles, sItem ) + table.insert(tFiles, sItem) end end end -table.sort( tDirs ) -table.sort( tFiles ) +table.sort(tDirs) +table.sort(tFiles) if term.isColour() then - textutils.pagedTabulate( colors.green, tDirs, colors.white, tFiles ) + textutils.pagedTabulate(colors.green, tDirs, colors.white, tFiles) else - textutils.pagedTabulate( tDirs, tFiles ) + textutils.pagedTabulate(tDirs, tFiles) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 6514e6390..5eea4dd81 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -1,8 +1,8 @@ local tArgs = { ... } if #tArgs > 0 then - print( "This is an interactive Lua prompt." ) - print( "To run a lua program, just type its name." ) + print("This is an interactive Lua prompt.") + print("To run a lua program, just type its name.") return end @@ -15,11 +15,11 @@ local tEnv = { __tostring = function() return "Call exit() to exit." end, __call = function() bRunning = false end, }), - ["_echo"] = function( ... ) + ["_echo"] = function(...) return ... end, } -setmetatable( tEnv, { __index = _ENV } ) +setmetatable(tEnv, { __index = _ENV }) -- Replace our package.path, so that it loads from the current directory, rather -- than from /rom/programs. This makes it a little more friendly to use and @@ -39,38 +39,38 @@ do end if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end -print( "Interactive Lua prompt." ) -print( "Call exit() to exit." ) -term.setTextColour( colours.white ) +print("Interactive Lua prompt.") +print("Call exit() to exit.") +term.setTextColour(colours.white) while bRunning do --if term.isColour() then -- term.setTextColour( colours.yellow ) --end - write( "lua> " ) + write("lua> ") --term.setTextColour( colours.white ) - local s = read( nil, tCommandHistory, function( sLine ) - if settings.get( "lua.autocomplete" ) then - local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.:]+$" ) + local s = read(nil, tCommandHistory, function(sLine) + if settings.get("lua.autocomplete") then + local nStartPos = string.find(sLine, "[a-zA-Z0-9_%.:]+$") if nStartPos then - sLine = string.sub( sLine, nStartPos ) + sLine = string.sub(sLine, nStartPos) end if #sLine > 0 then - return textutils.complete( sLine, tEnv ) + return textutils.complete(sLine, tEnv) end end return nil - end ) + end) if s:match("%S") and tCommandHistory[#tCommandHistory] ~= s then - table.insert( tCommandHistory, s ) + table.insert(tCommandHistory, s) end local nForcePrint = 0 - local func, e = load( s, "=lua", "t", tEnv ) - local func2 = load( "return _echo(" .. s .. ");", "=lua", "t", tEnv ) + local func, e = load(s, "=lua", "t", tEnv) + local func2 = load("return _echo(" .. s .. ");", "=lua", "t", tEnv) if not func then if func2 then func = func2 @@ -84,11 +84,11 @@ while bRunning do end if func then - local tResults = table.pack( pcall( func ) ) + local tResults = table.pack(pcall(func)) if tResults[1] then local n = 1 while n < tResults.n or n <= nForcePrint do - local value = tResults[ n + 1 ] + local value = tResults[n + 1] local ok, serialised = pcall(pretty.pretty, value) if ok then pretty.print(serialised) @@ -98,10 +98,10 @@ while bRunning do n = n + 1 end else - printError( tResults[2] ) + printError(tResults[2]) end else - printError( e ) + printError(e) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua b/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua index 3bdb5e840..bbdd08002 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/mkdir.lua @@ -1,17 +1,17 @@ local tArgs = { ... } if #tArgs < 1 then - print( "Usage: mkdir " ) + print("Usage: mkdir ") return end -for _, v in ipairs( tArgs ) do - local sNewDir = shell.resolve( v ) - if fs.exists( sNewDir ) and not fs.isDir( sNewDir ) then - printError( v .. ": Destination exists" ) - elseif fs.isReadOnly( sNewDir ) then - printError( v .. ": Access denied" ) +for _, v in ipairs(tArgs) do + local sNewDir = shell.resolve(v) + if fs.exists(sNewDir) and not fs.isDir(sNewDir) then + printError(v .. ": Destination exists") + elseif fs.isReadOnly(sNewDir) then + printError(v .. ": Access denied") else - fs.makeDir( sNewDir ) + fs.makeDir(sNewDir) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua index 8860d8bde..e6daed9e8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua @@ -1,5 +1,5 @@ local function printUsage() - print( "Usage: monitor " ) + print("Usage: monitor ") return end @@ -10,65 +10,65 @@ if #tArgs < 2 then end local sName = tArgs[1] -if peripheral.getType( sName ) ~= "monitor" then - print( "No monitor named " .. sName ) +if peripheral.getType(sName) ~= "monitor" then + print("No monitor named " .. sName) return end local sProgram = tArgs[2] -local sPath = shell.resolveProgram( sProgram ) +local sPath = shell.resolveProgram(sProgram) if sPath == nil then - print( "No such program: " .. sProgram ) + print("No such program: " .. sProgram) return end -print( "Running " .. sProgram .. " on monitor " .. sName ) +print("Running " .. sProgram .. " on monitor " .. sName) -local monitor = peripheral.wrap( sName ) -local previousTerm = term.redirect( monitor ) +local monitor = peripheral.wrap(sName) +local previousTerm = term.redirect(monitor) -local co = coroutine.create( function() - shell.run( sProgram, table.unpack( tArgs, 3 ) ) -end ) +local co = coroutine.create(function() + shell.run(sProgram, table.unpack(tArgs, 3)) +end) -local function resume( ... ) - local ok, param = coroutine.resume( co, ... ) +local function resume(...) + local ok, param = coroutine.resume(co, ...) if not ok then - printError( param ) + printError(param) end return param end local timers = {} -local ok, param = pcall( function() +local ok, param = pcall(function() local sFilter = resume() - while coroutine.status( co ) ~= "dead" do - local tEvent = table.pack( os.pullEventRaw() ) + while coroutine.status(co) ~= "dead" do + local tEvent = table.pack(os.pullEventRaw()) if sFilter == nil or tEvent[1] == sFilter or tEvent[1] == "terminate" then - sFilter = resume( table.unpack( tEvent, 1, tEvent.n ) ) + sFilter = resume(table.unpack(tEvent, 1, tEvent.n)) end - if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then + if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "mouse_click") then if tEvent[1] == "monitor_touch" and tEvent[2] == sName then - timers[os.startTimer( 0.1 )] = { tEvent[3], tEvent[4] } - sFilter = resume( "mouse_click", 1, table.unpack( tEvent, 3, tEvent.n ) ) + timers[os.startTimer(0.1)] = { tEvent[3], tEvent[4] } + sFilter = resume("mouse_click", 1, table.unpack(tEvent, 3, tEvent.n)) end end - if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "term_resize") then + if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "term_resize") then if tEvent[1] == "monitor_resize" and tEvent[2] == sName then - sFilter = resume( "term_resize" ) + sFilter = resume("term_resize") end end - if coroutine.status( co ) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then + if coroutine.status(co) ~= "dead" and (sFilter == nil or sFilter == "mouse_up") then if tEvent[1] == "timer" and timers[tEvent[2]] then - sFilter = resume( "mouse_up", 1, table.unpack( timers[tEvent[2]], 1, 2 ) ) + sFilter = resume("mouse_up", 1, table.unpack(timers[tEvent[2]], 1, 2)) timers[tEvent[2]] = nil end end end -end ) +end) -term.redirect( previousTerm ) +term.redirect(previousTerm) if not ok then - printError( param ) + printError(param) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua b/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua index a7142fb85..c8c75a40b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/motd.lua @@ -1,6 +1,6 @@ local tMotd = {} -for sPath in string.gmatch(settings.get( "motd.path" ), "[^:]+") do +for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do if fs.exists(sPath) then for sLine in io.lines(sPath) do table.insert(tMotd, sLine) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua index 5b2dd6266..0ebc5f7f7 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua @@ -1,24 +1,24 @@ local tArgs = { ... } if #tArgs < 2 then - print( "Usage: mv " ) + print("Usage: mv ") return end -local sSource = shell.resolve( tArgs[1] ) -local sDest = shell.resolve( tArgs[2] ) -local tFiles = fs.find( sSource ) +local sSource = shell.resolve(tArgs[1]) +local sDest = shell.resolve(tArgs[2]) +local tFiles = fs.find(sSource) if #tFiles > 0 then - for _, sFile in ipairs( tFiles ) do - if fs.isDir( sDest ) then - fs.move( sFile, fs.combine( sDest, fs.getName(sFile) ) ) + for _, sFile in ipairs(tFiles) do + if fs.isDir(sDest) then + fs.move(sFile, fs.combine(sDest, fs.getName(sFile))) elseif #tFiles == 1 then - fs.move( sFile, sDest ) + fs.move(sFile, sDest) else - printError( "Cannot overwrite file multiple times" ) + printError("Cannot overwrite file multiple times") return end end else - printError( "No matching files" ) + printError("No matching files") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua b/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua index 33b7e9c9a..290619614 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/peripherals.lua @@ -1,10 +1,10 @@ local tPeripherals = peripheral.getNames() -print( "Attached Peripherals:" ) +print("Attached Peripherals:") if #tPeripherals > 0 then for n = 1, #tPeripherals do local sPeripheral = tPeripherals[n] - print( sPeripheral .. " (" .. peripheral.getType( sPeripheral ) .. ")" ) + print(sPeripheral .. " (" .. peripheral.getType(sPeripheral) .. ")") end else - print( "None" ) + print("None") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/equip.lua b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/equip.lua index 62aa7c98d..b4fdb399a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/equip.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/equip.lua @@ -1,11 +1,11 @@ if not pocket then - printError( "Requires a Pocket Computer" ) + printError("Requires a Pocket Computer") return end local ok, err = pocket.equipBack() if not ok then - printError( err ) + printError(err) else - print( "Item equipped" ) + print("Item equipped") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua index 330042936..deb01c380 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/falling.lua @@ -160,7 +160,7 @@ local block_T = { local blocks = { block_line, block_square, block_s1, block_s2, block_L1, block_L2, block_T } -local points = {4, 10, 30, 120} +local points = { 4, 10, 30, 120 } local function lpad(text, amt) text = tostring(text) @@ -456,7 +456,7 @@ local function playGame() sleep(.25) for r = 1, #rows do table.remove(pit, rows[r]) - table.insert(pit, 1, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) + table.insert(pit, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }) end redrawPit() lines = lines + #rows @@ -496,7 +496,7 @@ local function playGame() while not halt do - local e = {os.pullEvent()} + local e = { os.pullEvent() } if e[1] == "timer" then if e[2] == dropTimer then blockFall() @@ -517,7 +517,7 @@ local function playGame() elseif key == keys.space then hidePit() msgBox("Paused") - while ({os.pullEvent("key")})[2] ~= keys.space do end + while ({ os.pullEvent("key") })[2] ~= keys.space do end redrawPit() drawBlockAt(curBlock, curX, curY, curRot) dropTimer = os.startTimer(dropSpeed) @@ -606,7 +606,7 @@ local function runMenu() drawMenu() while true do - local event = {os.pullEvent()} + local event = { os.pullEvent() } if event[1] == "key" then local key = event[2] if key == keys.right or key == keys.d and selected == 1 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/unequip.lua b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/unequip.lua index 28308d407..8cd1ef444 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/pocket/unequip.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/pocket/unequip.lua @@ -1,11 +1,11 @@ if not pocket then - printError( "Requires a Pocket Computer" ) + printError("Requires a Pocket Computer") return end local ok, err = pocket.unequipBack() if not ok then - printError( err ) + printError(err) else - print( "Item unequipped" ) + print("Item unequipped") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua b/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua index 1fe382799..015264d94 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua @@ -5,5 +5,5 @@ if #tArgs > 0 and tArgs[1] == "all" then bAll = true end -local tPrograms = shell.programs( bAll ) -textutils.pagedTabulate( tPrograms ) +local tPrograms = shell.programs(bAll) +textutils.pagedTabulate(tPrograms) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/reboot.lua b/src/main/resources/assets/computercraft/lua/rom/programs/reboot.lua index 2ea87bb2e..2824cc0c6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/reboot.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/reboot.lua @@ -1,8 +1,8 @@ if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end -print( "Goodbye" ) -term.setTextColour( colours.white ) +print("Goodbye") +term.setTextColour(colours.white) -sleep( 1 ) +sleep(1) os.reboot() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index ac8f4bc65..c632104b1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -2,29 +2,29 @@ local tArgs = { ... } local function printUsage() - print( "Usages:" ) - print( "chat host " ) - print( "chat join " ) + print("Usages:") + print("chat host ") + print("chat join ") end local sOpenedModem = nil local function openModem() - for _, sModem in ipairs( peripheral.getNames() ) do - if peripheral.getType( sModem ) == "modem" then - if not rednet.isOpen( sModem ) then - rednet.open( sModem ) + for _, sModem in ipairs(peripheral.getNames()) do + if peripheral.getType(sModem) == "modem" then + if not rednet.isOpen(sModem) then + rednet.open(sModem) sOpenedModem = sModem end return true end end - print( "No modems found." ) + print("No modems found.") return false end local function closeModem() if sOpenedModem ~= nil then - rednet.close( sOpenedModem ) + rednet.close(sOpenedModem) sOpenedModem = nil end end @@ -53,54 +53,54 @@ if sCommand == "host" then if not openModem() then return end - rednet.host( "chat", sHostname ) - print( "0 users connected." ) + rednet.host("chat", sHostname) + print("0 users connected.") local tUsers = {} local nUsers = 0 - local function send( sText, nUserID ) + local function send(sText, nUserID) if nUserID then - local tUser = tUsers[ nUserID ] + local tUser = tUsers[nUserID] if tUser then - rednet.send( tUser.nID, { + rednet.send(tUser.nID, { sType = "text", nUserID = nUserID, sText = sText, - }, "chat" ) + }, "chat") end else - for nUserID, tUser in pairs( tUsers ) do - rednet.send( tUser.nID, { + for nUserID, tUser in pairs(tUsers) do + rednet.send(tUser.nID, { sType = "text", nUserID = nUserID, sText = sText, - }, "chat" ) + }, "chat") end end end -- Setup ping pong local tPingPongTimer = {} - local function ping( nUserID ) - local tUser = tUsers[ nUserID ] - rednet.send( tUser.nID, { + local function ping(nUserID) + local tUser = tUsers[nUserID] + rednet.send(tUser.nID, { sType = "ping to client", nUserID = nUserID, - }, "chat" ) + }, "chat") - local timer = os.startTimer( 15 ) + local timer = os.startTimer(15) tUser.bPingPonged = false - tPingPongTimer[ timer ] = nUserID + tPingPongTimer[timer] = nUserID end local function printUsers() local _, y = term.getCursorPos() - term.setCursorPos( 1, y - 1 ) + term.setCursorPos(1, y - 1) term.clearLine() if nUsers == 1 then - print( nUsers .. " user connected." ) + print(nUsers .. " user connected.") else - print( nUsers .. " users connected." ) + print(nUsers .. " users connected.") end end @@ -108,18 +108,18 @@ if sCommand == "host" then local ok, error = pcall(parallel.waitForAny, function() while true do - local _, timer = os.pullEvent( "timer" ) - local nUserID = tPingPongTimer[ timer ] - if nUserID and tUsers[ nUserID ] then - local tUser = tUsers[ nUserID ] + local _, timer = os.pullEvent("timer") + local nUserID = tPingPongTimer[timer] + if nUserID and tUsers[nUserID] then + local tUser = tUsers[nUserID] if tUser then if not tUser.bPingPonged then - send( "* " .. tUser.sUsername .. " has timed out" ) - tUsers[ nUserID ] = nil + send("* " .. tUser.sUsername .. " has timed out") + tUsers[nUserID] = nil nUsers = nUsers - 1 printUsers() else - ping( nUserID ) + ping(nUserID) end end end @@ -129,91 +129,91 @@ if sCommand == "host" then while true do local tCommands tCommands = { - ["me"] = function( tUser, sContent ) + ["me"] = function(tUser, sContent) if #sContent > 0 then - send( "* " .. tUser.sUsername .. " " .. sContent ) + send("* " .. tUser.sUsername .. " " .. sContent) else - send( "* Usage: /me [words]", tUser.nUserID ) + send("* Usage: /me [words]", tUser.nUserID) end end, - ["nick"] = function( tUser, sContent ) + ["nick"] = function(tUser, sContent) if #sContent > 0 then local sOldName = tUser.sUsername tUser.sUsername = sContent - send( "* " .. sOldName .. " is now known as " .. tUser.sUsername ) + send("* " .. sOldName .. " is now known as " .. tUser.sUsername) else - send( "* Usage: /nick [nickname]", tUser.nUserID ) + send("* Usage: /nick [nickname]", tUser.nUserID) end end, - ["users"] = function( tUser, sContent ) - send( "* Connected Users:", tUser.nUserID ) + ["users"] = function(tUser, sContent) + send("* Connected Users:", tUser.nUserID) local sUsers = "*" - for _, tUser in pairs( tUsers ) do + for _, tUser in pairs(tUsers) do sUsers = sUsers .. " " .. tUser.sUsername end - send( sUsers, tUser.nUserID ) + send(sUsers, tUser.nUserID) end, - ["help"] = function( tUser, sContent ) - send( "* Available commands:", tUser.nUserID ) + ["help"] = function(tUser, sContent) + send("* Available commands:", tUser.nUserID) local sCommands = "*" - for sCommand in pairs( tCommands ) do + for sCommand in pairs(tCommands) do sCommands = sCommands .. " /" .. sCommand end - send( sCommands .. " /logout", tUser.nUserID ) + send(sCommands .. " /logout", tUser.nUserID) end, } - local nSenderID, tMessage = rednet.receive( "chat" ) - if type( tMessage ) == "table" then + local nSenderID, tMessage = rednet.receive("chat") + if type(tMessage) == "table" then if tMessage.sType == "login" then -- Login from new client local nUserID = tMessage.nUserID local sUsername = tMessage.sUsername if nUserID and sUsername then - tUsers[ nUserID ] = { + tUsers[nUserID] = { nID = nSenderID, nUserID = nUserID, sUsername = sUsername, } nUsers = nUsers + 1 printUsers() - send( "* " .. sUsername .. " has joined the chat" ) - ping( nUserID ) + send("* " .. sUsername .. " has joined the chat") + ping(nUserID) end else -- Something else from existing client local nUserID = tMessage.nUserID - local tUser = tUsers[ nUserID ] + local tUser = tUsers[nUserID] if tUser and tUser.nID == nSenderID then if tMessage.sType == "logout" then - send( "* " .. tUser.sUsername .. " has left the chat" ) - tUsers[ nUserID ] = nil + send("* " .. tUser.sUsername .. " has left the chat") + tUsers[nUserID] = nil nUsers = nUsers - 1 printUsers() elseif tMessage.sType == "chat" then local sMessage = tMessage.sText if sMessage then - local sCommand = string.match( sMessage, "^/([a-z]+)" ) + local sCommand = string.match(sMessage, "^/([a-z]+)") if sCommand then - local fnCommand = tCommands[ sCommand ] + local fnCommand = tCommands[sCommand] if fnCommand then - local sContent = string.sub( sMessage, #sCommand + 3 ) - fnCommand( tUser, sContent ) + local sContent = string.sub(sMessage, #sCommand + 3) + fnCommand(tUser, sContent) else - send( "* Unrecognised command: /" .. sCommand, tUser.nUserID ) + send("* Unrecognised command: /" .. sCommand, tUser.nUserID) end else - send( "<" .. tUser.sUsername .. "> " .. tMessage.sText ) + send("<" .. tUser.sUsername .. "> " .. tMessage.sText) end end elseif tMessage.sType == "ping to server" then - rednet.send( tUser.nID, { + rednet.send(tUser.nID, { sType = "pong to client", nUserID = nUserID, - }, "chat" ) + }, "chat") elseif tMessage.sType == "pong to server" then tUser.bPingPonged = true @@ -226,17 +226,17 @@ if sCommand == "host" then end ) if not ok then - printError( error ) + printError(error) end -- Unhost server - for nUserID, tUser in pairs( tUsers ) do - rednet.send( tUser.nID, { + for nUserID, tUser in pairs(tUsers) do + rednet.send(tUser.nID, { sType = "kick", nUserID = nUserID, - }, "chat" ) + }, "chat") end - rednet.unhost( "chat" ) + rednet.unhost("chat") closeModem() elseif sCommand == "join" then @@ -253,80 +253,80 @@ elseif sCommand == "join" then if not openModem() then return end - write( "Looking up " .. sHostname .. "... " ) - local nHostID = rednet.lookup( "chat", sHostname ) + write("Looking up " .. sHostname .. "... ") + local nHostID = rednet.lookup("chat", sHostname) if nHostID == nil then - print( "Failed." ) + print("Failed.") return else - print( "Success." ) + print("Success.") end -- Login - local nUserID = math.random( 1, 2147483647 ) - rednet.send( nHostID, { + local nUserID = math.random(1, 2147483647) + rednet.send(nHostID, { sType = "login", nUserID = nUserID, sUsername = sUsername, - }, "chat" ) + }, "chat") -- Setup ping pong local bPingPonged = true - local pingPongTimer = os.startTimer( 0 ) + local pingPongTimer = os.startTimer(0) local function ping() - rednet.send( nHostID, { + rednet.send(nHostID, { sType = "ping to server", nUserID = nUserID, - }, "chat" ) + }, "chat") bPingPonged = false - pingPongTimer = os.startTimer( 15 ) + pingPongTimer = os.startTimer(15) end -- Handle messages local w, h = term.getSize() local parentTerm = term.current() - local titleWindow = window.create( parentTerm, 1, 1, w, 1, true ) - local historyWindow = window.create( parentTerm, 1, 2, w, h - 2, true ) - local promptWindow = window.create( parentTerm, 1, h, w, 1, true ) - historyWindow.setCursorPos( 1, h - 2 ) + local titleWindow = window.create(parentTerm, 1, 1, w, 1, true) + local historyWindow = window.create(parentTerm, 1, 2, w, h - 2, true) + local promptWindow = window.create(parentTerm, 1, h, w, 1, true) + historyWindow.setCursorPos(1, h - 2) term.clear() - term.setTextColour( textColour ) - term.redirect( promptWindow ) + term.setTextColour(textColour) + term.redirect(promptWindow) promptWindow.restoreCursor() local function drawTitle() local w = titleWindow.getSize() local sTitle = sUsername .. " on " .. sHostname - titleWindow.setTextColour( highlightColour ) - titleWindow.setCursorPos( math.floor( w / 2 - #sTitle / 2 ), 1 ) + titleWindow.setTextColour(highlightColour) + titleWindow.setCursorPos(math.floor(w / 2 - #sTitle / 2), 1) titleWindow.clearLine() - titleWindow.write( sTitle ) + titleWindow.write(sTitle) promptWindow.restoreCursor() end - local function printMessage( sMessage ) - term.redirect( historyWindow ) + local function printMessage(sMessage) + term.redirect(historyWindow) print() - if string.match( sMessage, "^%*" ) then + if string.match(sMessage, "^%*") then -- Information - term.setTextColour( highlightColour ) - write( sMessage ) - term.setTextColour( textColour ) + term.setTextColour(highlightColour) + write(sMessage) + term.setTextColour(textColour) else -- Chat - local sUsernameBit = string.match( sMessage, "^<[^>]*>" ) + local sUsernameBit = string.match(sMessage, "^<[^>]*>") if sUsernameBit then - term.setTextColour( highlightColour ) - write( sUsernameBit ) - term.setTextColour( textColour ) - write( string.sub( sMessage, #sUsernameBit + 1 ) ) + term.setTextColour(highlightColour) + write(sUsernameBit) + term.setTextColour(textColour) + write(string.sub(sMessage, #sUsernameBit + 1)) else - write( sMessage ) + write(sMessage) end end - term.redirect( promptWindow ) + term.redirect(promptWindow) promptWindow.restoreCursor() end @@ -339,7 +339,7 @@ elseif sCommand == "join" then if sEvent == "timer" then if timer == pingPongTimer then if not bPingPonged then - printMessage( "Server timeout." ) + printMessage("Server timeout.") return else ping() @@ -348,28 +348,28 @@ elseif sCommand == "join" then elseif sEvent == "term_resize" then local w, h = parentTerm.getSize() - titleWindow.reposition( 1, 1, w, 1 ) - historyWindow.reposition( 1, 2, w, h - 2 ) - promptWindow.reposition( 1, h, w, 1 ) + titleWindow.reposition(1, 1, w, 1) + historyWindow.reposition(1, 2, w, h - 2) + promptWindow.reposition(1, h, w, 1) end end end, function() while true do - local nSenderID, tMessage = rednet.receive( "chat" ) - if nSenderID == nHostID and type( tMessage ) == "table" and tMessage.nUserID == nUserID then + local nSenderID, tMessage = rednet.receive("chat") + if nSenderID == nHostID and type(tMessage) == "table" and tMessage.nUserID == nUserID then if tMessage.sType == "text" then local sText = tMessage.sText if sText then - printMessage( sText ) + printMessage(sText) end elseif tMessage.sType == "ping to client" then - rednet.send( nSenderID, { + rednet.send(nSenderID, { sType = "pong to server", nUserID = nUserID, - }, "chat" ) + }, "chat") elseif tMessage.sType == "pong to client" then bPingPonged = true @@ -384,48 +384,48 @@ elseif sCommand == "join" then function() local tSendHistory = {} while true do - promptWindow.setCursorPos( 1, 1 ) + promptWindow.setCursorPos(1, 1) promptWindow.clearLine() - promptWindow.setTextColor( highlightColour ) - promptWindow.write( ": " ) - promptWindow.setTextColor( textColour ) + promptWindow.setTextColor(highlightColour) + promptWindow.write(": ") + promptWindow.setTextColor(textColour) - local sChat = read( nil, tSendHistory ) - if string.match( sChat, "^/logout" ) then + local sChat = read(nil, tSendHistory) + if string.match(sChat, "^/logout") then break else - rednet.send( nHostID, { + rednet.send(nHostID, { sType = "chat", nUserID = nUserID, sText = sChat, - }, "chat" ) - table.insert( tSendHistory, sChat ) + }, "chat") + table.insert(tSendHistory, sChat) end end end ) -- Close the windows - term.redirect( parentTerm ) + term.redirect(parentTerm) -- Print error notice local _, h = term.getSize() - term.setCursorPos( 1, h ) + term.setCursorPos(1, h) term.clearLine() - term.setCursorBlink( false ) + term.setCursorBlink(false) if not ok then - printError( error ) + printError(error) end -- Logout - rednet.send( nHostID, { + rednet.send(nHostID, { sType = "logout", nUserID = nUserID, - }, "chat" ) + }, "chat") closeModem() -- Print disconnection notice - print( "Disconnected." ) + print("Disconnected.") else -- "chat somethingelse" diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua index c6bad5634..b9a9bcb94 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua @@ -1,40 +1,40 @@ -- Find modems local tModems = {} -for _, sModem in ipairs( peripheral.getNames() ) do - if peripheral.getType( sModem ) == "modem" then - table.insert( tModems, sModem ) +for _, sModem in ipairs(peripheral.getNames()) do + if peripheral.getType(sModem) == "modem" then + table.insert(tModems, sModem) end end if #tModems == 0 then - print( "No modems found." ) + print("No modems found.") return elseif #tModems == 1 then - print( "1 modem found." ) + print("1 modem found.") else - print( #tModems .. " modems found." ) + print(#tModems .. " modems found.") end -local function open( nChannel ) +local function open(nChannel) for n = 1, #tModems do local sModem = tModems[n] - peripheral.call( sModem, "open", nChannel ) + peripheral.call(sModem, "open", nChannel) end end -local function close( nChannel ) +local function close(nChannel) for n = 1, #tModems do local sModem = tModems[n] - peripheral.call( sModem, "close", nChannel ) + peripheral.call(sModem, "close", nChannel) end end -- Open channels -print( "0 messages repeated." ) -open( rednet.CHANNEL_REPEAT ) +print("0 messages repeated.") +open(rednet.CHANNEL_REPEAT) -- Main loop (terminate to break) -local ok, error = pcall( function() +local ok, error = pcall(function() local tReceivedMessages = {} local tReceivedMessageTimeouts = {} local nTransmittedMessages = 0 @@ -44,28 +44,28 @@ local ok, error = pcall( function() if sEvent == "modem_message" then -- Got a modem message, rebroadcast it if it's a rednet thing if nChannel == rednet.CHANNEL_REPEAT then - if type( tMessage ) == "table" and tMessage.nMessageID and tMessage.nRecipient and type(tMessage.nRecipient) == "number" then - if not tReceivedMessages[ tMessage.nMessageID ] then + if type(tMessage) == "table" and tMessage.nMessageID and tMessage.nRecipient and type(tMessage.nRecipient) == "number" then + if not tReceivedMessages[tMessage.nMessageID] then -- Ensure we only repeat a message once - tReceivedMessages[ tMessage.nMessageID ] = true - tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID + tReceivedMessages[tMessage.nMessageID] = true + tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID -- Send on all other open modems, to the target and to other repeaters for n = 1, #tModems do local sOtherModem = tModems[n] - peripheral.call( sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage ) - peripheral.call( sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage ) + peripheral.call(sOtherModem, "transmit", rednet.CHANNEL_REPEAT, nReplyChannel, tMessage) + peripheral.call(sOtherModem, "transmit", tMessage.nRecipient, nReplyChannel, tMessage) end -- Log the event nTransmittedMessages = nTransmittedMessages + 1 local _, y = term.getCursorPos() - term.setCursorPos( 1, y - 1 ) + term.setCursorPos(1, y - 1) term.clearLine() if nTransmittedMessages == 1 then - print( nTransmittedMessages .. " message repeated." ) + print(nTransmittedMessages .. " message repeated.") else - print( nTransmittedMessages .. " messages repeated." ) + print(nTransmittedMessages .. " messages repeated.") end end end @@ -74,18 +74,18 @@ local ok, error = pcall( function() elseif sEvent == "timer" then -- Got a timer event, use it to clear the message history local nTimer = sModem - local nMessageID = tReceivedMessageTimeouts[ nTimer ] + local nMessageID = tReceivedMessageTimeouts[nTimer] if nMessageID then - tReceivedMessageTimeouts[ nTimer ] = nil - tReceivedMessages[ nMessageID ] = nil + tReceivedMessageTimeouts[nTimer] = nil + tReceivedMessages[nMessageID] = nil end end end -end ) +end) if not ok then - printError( error ) + printError(error) end -- Close channels -close( rednet.CHANNEL_REPEAT ) +close(rednet.CHANNEL_REPEAT) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua index ff7f87a48..35fae9f04 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua @@ -2,64 +2,64 @@ local tArgs = { ... } local function printUsage() - print( "Usages:" ) - print( "redstone probe" ) - print( "redstone set " ) - print( "redstone set " ) - print( "redstone pulse " ) + print("Usages:") + print("redstone probe") + print("redstone set ") + print("redstone set ") + print("redstone pulse ") end local sCommand = tArgs[1] if sCommand == "probe" then -- "redstone probe" -- Regular input - print( "Redstone inputs: " ) + print("Redstone inputs: ") local count = 0 local bundledCount = 0 - for _, sSide in ipairs( redstone.getSides() ) do - if redstone.getBundledInput( sSide ) > 0 then + for _, sSide in ipairs(redstone.getSides()) do + if redstone.getBundledInput(sSide) > 0 then bundledCount = bundledCount + 1 end - if redstone.getInput( sSide ) then + if redstone.getInput(sSide) then if count > 0 then - io.write( ", " ) + io.write(", ") end - io.write( sSide ) + io.write(sSide) count = count + 1 end end if count > 0 then - print( "." ) + print(".") else - print( "None." ) + print("None.") end -- Bundled input if bundledCount > 0 then print() - print( "Bundled inputs:" ) - for _, sSide in ipairs( redstone.getSides() ) do - local nInput = redstone.getBundledInput( sSide ) + print("Bundled inputs:") + for _, sSide in ipairs(redstone.getSides()) do + local nInput = redstone.getBundledInput(sSide) if nInput ~= 0 then - write( sSide .. ": " ) + write(sSide .. ": ") local count = 0 - for sColour, nColour in pairs( colors ) do - if type( nColour ) == "number" and colors.test( nInput, nColour ) then + for sColour, nColour in pairs(colors) do + if type(nColour) == "number" and colors.test(nInput, nColour) then if count > 0 then - write( ", " ) + write(", ") end if term.isColour() then - term.setTextColour( nColour ) + term.setTextColour(nColour) end - write( sColour ) + write(sColour) if term.isColour() then - term.setTextColour( colours.white ) + term.setTextColour(colours.white) end count = count + 1 end end - print( "." ) + print(".") end end end @@ -67,13 +67,13 @@ if sCommand == "probe" then elseif sCommand == "pulse" then -- "redstone pulse" local sSide = tArgs[2] - local nCount = tonumber( tArgs[3] ) or 1 - local nPeriod = tonumber( tArgs[4] ) or 0.5 + local nCount = tonumber(tArgs[3]) or 1 + local nPeriod = tonumber(tArgs[4]) or 0.5 for _ = 1, nCount do - redstone.setOutput( sSide, true ) - sleep( nPeriod / 2 ) - redstone.setOutput( sSide, false ) - sleep( nPeriod / 2 ) + redstone.setOutput(sSide, true) + sleep(nPeriod / 2) + redstone.setOutput(sSide, false) + sleep(nPeriod / 2) end elseif sCommand == "set" then @@ -84,30 +84,30 @@ elseif sCommand == "set" then local sColour = tArgs[3] local nColour = colors[sColour] or colours[sColour] if type(nColour) ~= "number" then - printError( "No such color" ) + printError("No such color") return end local sValue = tArgs[4] if sValue == "true" then - rs.setBundledOutput( sSide, colors.combine( rs.getBundledOutput( sSide ), nColour ) ) + rs.setBundledOutput(sSide, colors.combine(rs.getBundledOutput(sSide), nColour)) elseif sValue == "false" then - rs.setBundledOutput( sSide, colors.subtract( rs.getBundledOutput( sSide ), nColour ) ) + rs.setBundledOutput(sSide, colors.subtract(rs.getBundledOutput(sSide), nColour)) else - print( "Value must be boolean" ) + print("Value must be boolean") end else -- Regular output local sValue = tArgs[3] local nValue = tonumber(sValue) if sValue == "true" then - rs.setOutput( sSide, true ) + rs.setOutput(sSide, true) elseif sValue == "false" then - rs.setOutput( sSide, false ) + rs.setOutput(sSide, false) elseif nValue and nValue >= 0 and nValue <= 15 then - rs.setAnalogOutput( sSide, nValue ) + rs.setAnalogOutput(sSide, nValue) else - print( "Value must be boolean or 0-15" ) + print("Value must be boolean or 0-15") end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua index 4583adf62..a90c1f8ad 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua @@ -1,21 +1,21 @@ local tArgs = { ... } if #tArgs < 2 then - print( "Usage: rename " ) + print("Usage: rename ") return end -local sSource = shell.resolve( tArgs[1] ) -local sDest = shell.resolve( tArgs[2] ) +local sSource = shell.resolve(tArgs[1]) +local sDest = shell.resolve(tArgs[2]) -if not fs.exists( sSource ) then - printError( "No matching files" ) +if not fs.exists(sSource) then + printError("No matching files") return -elseif fs.exists( sDest ) then - printError( "Destination exists" ) +elseif fs.exists(sDest) then + printError("Destination exists") return -elseif fs.isReadOnly( sDest ) then - printError( "Destination is read-only" ) +elseif fs.isReadOnly(sDest) then + printError("Destination is read-only") return end -fs.move( sSource, sDest ) +fs.move(sSource, sDest) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua index f2bacabcc..a826d8ad6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua @@ -4,7 +4,7 @@ if #tArgs == 0 then -- "set" local _, y = term.getCursorPos() local tSettings = {} - for n, sName in ipairs( settings.getNames() ) do + for n, sName in ipairs(settings.getNames()) do tSettings[n] = textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) end textutils.pagedPrint(table.concat(tSettings, "\n"), y - 3) @@ -12,7 +12,7 @@ if #tArgs == 0 then elseif #tArgs == 1 then -- "set foo" local sName = tArgs[1] - print( textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) ) + print(textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName))) else -- "set foo bar" @@ -31,15 +31,15 @@ else value = sValue end - local oldValue = settings.get( sValue ) + local oldValue = settings.get(sValue) if value ~= nil then - settings.set( sName, value ) - print( textutils.serialize(sName) .. " set to " .. textutils.serialize(value) ) + settings.set(sName, value) + print(textutils.serialize(sName) .. " set to " .. textutils.serialize(value)) else - settings.unset( sName ) - print( textutils.serialize(sName) .. " unset" ) + settings.unset(sName) + print(textutils.serialize(sName) .. " unset") end if value ~= oldValue then - settings.save( ".settings" ) + settings.save(".settings") end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 5628f0c6f..8a63138f8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -5,7 +5,7 @@ local parentShell = shell local parentTerm = term.current() if multishell then - multishell.setTitle( multishell.getCurrent(), "shell" ) + multishell.setTitle(multishell.getCurrent(), "shell") end local bExit = false @@ -16,10 +16,10 @@ local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {} local tProgramStack = {} local shell = {} -local function createShellEnv( sDir ) +local function createShellEnv(sDir) local tEnv = {} - tEnv[ "shell" ] = shell - tEnv[ "multishell" ] = multishell + tEnv.shell = shell + tEnv.multishell = multishell local package = {} package.loaded = { @@ -40,14 +40,14 @@ local function createShellEnv( sDir ) package.config = "/\n;\n?\n!\n-" package.preload = {} package.loaders = { - function( name ) + function(name) if package.preload[name] then return package.preload[name] else return nil, "no field package.preload['" .. name .. "']" end end, - function( name ) + function(name) local fname = string.gsub(name, "%.", "/") local sError = "" for pattern in string.gmatch(package.path, "[^;]+") do @@ -56,7 +56,7 @@ local function createShellEnv( sDir ) sPath = fs.combine(sDir, sPath) end if fs.exists(sPath) and not fs.isDir(sPath) then - local fnFile, sError = loadfile( sPath, nil, tEnv ) + local fnFile, sError = loadfile(sPath, nil, tEnv) if fnFile then return fnFile, sPath else @@ -74,7 +74,7 @@ local function createShellEnv( sDir ) } local sentinel = {} - local function require( name ) + local function require(name) expect(1, name, "string") if package.loaded[name] == sentinel then error("loop or previous error loading module '" .. name .. "'", 0) @@ -100,8 +100,8 @@ local function createShellEnv( sDir ) error(sError, 2) end - tEnv["package"] = package - tEnv["require"] = require + tEnv.package = package + tEnv.require = require return tEnv end @@ -118,52 +118,52 @@ else bgColour = colours.black end -local function run( _sCommand, ... ) - local sPath = shell.resolveProgram( _sCommand ) +local function run(_sCommand, ...) + local sPath = shell.resolveProgram(_sCommand) if sPath ~= nil then tProgramStack[#tProgramStack + 1] = sPath if multishell then - local sTitle = fs.getName( sPath ) + local sTitle = fs.getName(sPath) if sTitle:sub(-4) == ".lua" then sTitle = sTitle:sub(1, -5) end - multishell.setTitle( multishell.getCurrent(), sTitle ) + multishell.setTitle(multishell.getCurrent(), sTitle) end - local sDir = fs.getDir( sPath ) - local env = createShellEnv( sDir ) - env[ "arg" ] = { [0] = _sCommand, ... } - local result = os.run( env, sPath, ... ) + local sDir = fs.getDir(sPath) + local env = createShellEnv(sDir) + env.arg = { [0] = _sCommand, ... } + local result = os.run(env, sPath, ...) tProgramStack[#tProgramStack] = nil if multishell then if #tProgramStack > 0 then - local sTitle = fs.getName( tProgramStack[#tProgramStack] ) + local sTitle = fs.getName(tProgramStack[#tProgramStack]) if sTitle:sub(-4) == ".lua" then sTitle = sTitle:sub(1, -5) end - multishell.setTitle( multishell.getCurrent(), sTitle ) + multishell.setTitle(multishell.getCurrent(), sTitle) else - multishell.setTitle( multishell.getCurrent(), "shell" ) + multishell.setTitle(multishell.getCurrent(), "shell") end end return result else - printError( "No such program" ) + printError("No such program") return false end end -local function tokenise( ... ) - local sLine = table.concat( { ... }, " " ) +local function tokenise(...) + local sLine = table.concat({ ... }, " ") local tWords = {} local bQuoted = false - for match in string.gmatch( sLine .. "\"", "(.-)\"" ) do + for match in string.gmatch(sLine .. "\"", "(.-)\"") do if bQuoted then - table.insert( tWords, match ) + table.insert(tWords, match) else - for m in string.gmatch( match, "[^ \t]+" ) do - table.insert( tWords, m ) + for m in string.gmatch(match, "[^ \t]+") do + table.insert(tWords, m) end end bQuoted = not bQuoted @@ -172,11 +172,11 @@ local function tokenise( ... ) end -- Install shell API -function shell.run( ... ) - local tWords = tokenise( ... ) +function shell.run(...) + local tWords = tokenise(...) local sCommand = tWords[1] if sCommand then - return run( sCommand, table.unpack( tWords, 2 ) ) + return run(sCommand, table.unpack(tWords, 2)) end return false end @@ -189,10 +189,10 @@ function shell.dir() return sDir end -function shell.setDir( _sDir ) +function shell.setDir(_sDir) expect(1, _sDir, "string") - if not fs.isDir( _sDir ) then - error( "Not a directory", 2 ) + if not fs.isDir(_sDir) then + error("Not a directory", 2) end sDir = _sDir end @@ -201,46 +201,46 @@ function shell.path() return sPath end -function shell.setPath( _sPath ) +function shell.setPath(_sPath) expect(1, _sPath, "string") sPath = _sPath end -function shell.resolve( _sPath ) +function shell.resolve(_sPath) expect(1, _sPath, "string") - local sStartChar = string.sub( _sPath, 1, 1 ) + local sStartChar = string.sub(_sPath, 1, 1) if sStartChar == "/" or sStartChar == "\\" then - return fs.combine( "", _sPath ) + return fs.combine("", _sPath) else - return fs.combine( sDir, _sPath ) + return fs.combine(sDir, _sPath) end end -local function pathWithExtension( _sPath, _sExt ) +local function pathWithExtension(_sPath, _sExt) local nLen = #sPath - local sEndChar = string.sub( _sPath, nLen, nLen ) + local sEndChar = string.sub(_sPath, nLen, nLen) -- Remove any trailing slashes so we can add an extension to the path safely if sEndChar == "/" or sEndChar == "\\" then - _sPath = string.sub( _sPath, 1, nLen - 1 ) + _sPath = string.sub(_sPath, 1, nLen - 1) end return _sPath .. "." .. _sExt end -function shell.resolveProgram( _sCommand ) +function shell.resolveProgram(_sCommand) expect(1, _sCommand, "string") -- Substitute aliases firsts - if tAliases[ _sCommand ] ~= nil then - _sCommand = tAliases[ _sCommand ] + if tAliases[_sCommand] ~= nil then + _sCommand = tAliases[_sCommand] end -- If the path is a global path, use it directly if _sCommand:find("/") or _sCommand:find("\\") then - local sPath = shell.resolve( _sCommand ) - if fs.exists( sPath ) and not fs.isDir( sPath ) then + local sPath = shell.resolve(_sCommand) + if fs.exists(sPath) and not fs.isDir(sPath) then return sPath else - local sPathLua = pathWithExtension( sPath, "lua" ) - if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then + local sPathLua = pathWithExtension(sPath, "lua") + if fs.exists(sPathLua) and not fs.isDir(sPathLua) then return sPathLua end end @@ -249,12 +249,12 @@ function shell.resolveProgram( _sCommand ) -- Otherwise, look on the path variable for sPath in string.gmatch(sPath, "[^:]+") do - sPath = fs.combine( shell.resolve( sPath ), _sCommand ) - if fs.exists( sPath ) and not fs.isDir( sPath ) then + sPath = fs.combine(shell.resolve(sPath), _sCommand) + if fs.exists(sPath) and not fs.isDir(sPath) then return sPath else - local sPathLua = pathWithExtension( sPath, "lua" ) - if fs.exists( sPathLua ) and not fs.isDir( sPathLua ) then + local sPathLua = pathWithExtension(sPath, "lua") + if fs.exists(sPathLua) and not fs.isDir(sPathLua) then return sPathLua end end @@ -264,22 +264,22 @@ function shell.resolveProgram( _sCommand ) return nil end -function shell.programs( _bIncludeHidden ) +function shell.programs(_bIncludeHidden) local tItems = {} -- Add programs from the path for sPath in string.gmatch(sPath, "[^:]+") do - sPath = shell.resolve( sPath ) - if fs.isDir( sPath ) then - local tList = fs.list( sPath ) + sPath = shell.resolve(sPath) + if fs.isDir(sPath) then + local tList = fs.list(sPath) for n = 1, #tList do local sFile = tList[n] - if not fs.isDir( fs.combine( sPath, sFile ) ) and - (_bIncludeHidden or string.sub( sFile, 1, 1 ) ~= ".") then + if not fs.isDir(fs.combine(sPath, sFile)) and + (_bIncludeHidden or string.sub(sFile, 1, 1) ~= ".") then if #sFile > 4 and sFile:sub(-4) == ".lua" then sFile = sFile:sub(1, -5) end - tItems[ sFile ] = true + tItems[sFile] = true end end end @@ -287,40 +287,40 @@ function shell.programs( _bIncludeHidden ) -- Sort and return local tItemList = {} - for sItem in pairs( tItems ) do - table.insert( tItemList, sItem ) + for sItem in pairs(tItems) do + table.insert(tItemList, sItem) end - table.sort( tItemList ) + table.sort(tItemList) return tItemList end -local function completeProgram( sLine ) +local function completeProgram(sLine) if #sLine > 0 and (sLine:find("/") or sLine:find("\\")) then -- Add programs from the root - return fs.complete( sLine, sDir, true, false ) + return fs.complete(sLine, sDir, true, false) else local tResults = {} local tSeen = {} -- Add aliases - for sAlias in pairs( tAliases ) do - if #sAlias > #sLine and string.sub( sAlias, 1, #sLine ) == sLine then - local sResult = string.sub( sAlias, #sLine + 1 ) - if not tSeen[ sResult ] then - table.insert( tResults, sResult ) - tSeen[ sResult ] = true + for sAlias in pairs(tAliases) do + if #sAlias > #sLine and string.sub(sAlias, 1, #sLine) == sLine then + local sResult = string.sub(sAlias, #sLine + 1) + if not tSeen[sResult] then + table.insert(tResults, sResult) + tSeen[sResult] = true end end end -- Add all subdirectories. We don't include files as they will be added in the block below - local tDirs = fs.complete( sLine, sDir, false, false ) + local tDirs = fs.complete(sLine, sDir, false, false) for i = 1, #tDirs do local sResult = tDirs[i] - if not tSeen[ sResult ] then - table.insert ( tResults, sResult ) - tSeen [ sResult ] = true + if not tSeen[sResult] then + table.insert (tResults, sResult) + tSeen [sResult] = true end end @@ -328,48 +328,48 @@ local function completeProgram( sLine ) local tPrograms = shell.programs() for n = 1, #tPrograms do local sProgram = tPrograms[n] - if #sProgram > #sLine and string.sub( sProgram, 1, #sLine ) == sLine then - local sResult = string.sub( sProgram, #sLine + 1 ) - if not tSeen[ sResult ] then - table.insert( tResults, sResult ) - tSeen[ sResult ] = true + if #sProgram > #sLine and string.sub(sProgram, 1, #sLine) == sLine then + local sResult = string.sub(sProgram, #sLine + 1) + if not tSeen[sResult] then + table.insert(tResults, sResult) + tSeen[sResult] = true end end end -- Sort and return - table.sort( tResults ) + table.sort(tResults) return tResults end end -local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousParts ) - local tInfo = tCompletionInfo[ sProgram ] +local function completeProgramArgument(sProgram, nArgument, sPart, tPreviousParts) + local tInfo = tCompletionInfo[sProgram] if tInfo then - return tInfo.fnComplete( shell, nArgument, sPart, tPreviousParts ) + return tInfo.fnComplete(shell, nArgument, sPart, tPreviousParts) end return nil end -function shell.complete( sLine ) +function shell.complete(sLine) expect(1, sLine, "string") if #sLine > 0 then - local tWords = tokenise( sLine ) + local tWords = tokenise(sLine) local nIndex = #tWords - if string.sub( sLine, #sLine, #sLine ) == " " then + if string.sub(sLine, #sLine, #sLine) == " " then nIndex = nIndex + 1 end if nIndex == 1 then local sBit = tWords[1] or "" - local sPath = shell.resolveProgram( sBit ) - if tCompletionInfo[ sPath ] then + local sPath = shell.resolveProgram(sBit) + if tCompletionInfo[sPath] then return { " " } else - local tResults = completeProgram( sBit ) + local tResults = completeProgram(sBit) for n = 1, #tResults do local sResult = tResults[n] - local sPath = shell.resolveProgram( sBit .. sResult ) - if tCompletionInfo[ sPath ] then + local sPath = shell.resolveProgram(sBit .. sResult) + if tCompletionInfo[sPath] then tResults[n] = sResult .. " " end end @@ -377,26 +377,26 @@ function shell.complete( sLine ) end elseif nIndex > 1 then - local sPath = shell.resolveProgram( tWords[1] ) + local sPath = shell.resolveProgram(tWords[1]) local sPart = tWords[nIndex] or "" local tPreviousParts = tWords tPreviousParts[nIndex] = nil - return completeProgramArgument( sPath , nIndex - 1, sPart, tPreviousParts ) + return completeProgramArgument(sPath , nIndex - 1, sPart, tPreviousParts) end end return nil end -function shell.completeProgram( sProgram ) +function shell.completeProgram(sProgram) expect(1, sProgram, "string") - return completeProgram( sProgram ) + return completeProgram(sProgram) end -function shell.setCompletionFunction( sProgram, fnComplete ) +function shell.setCompletionFunction(sProgram, fnComplete) expect(1, sProgram, "string") expect(2, fnComplete, "function") - tCompletionInfo[ sProgram ] = { + tCompletionInfo[sProgram] = { fnComplete = fnComplete, } end @@ -412,45 +412,45 @@ function shell.getRunningProgram() return nil end -function shell.setAlias( _sCommand, _sProgram ) +function shell.setAlias(_sCommand, _sProgram) expect(1, _sCommand, "string") expect(2, _sProgram, "string") - tAliases[ _sCommand ] = _sProgram + tAliases[_sCommand] = _sProgram end -function shell.clearAlias( _sCommand ) +function shell.clearAlias(_sCommand) expect(1, _sCommand, "string") - tAliases[ _sCommand ] = nil + tAliases[_sCommand] = nil end function shell.aliases() -- Copy aliases local tCopy = {} - for sAlias, sCommand in pairs( tAliases ) do + for sAlias, sCommand in pairs(tAliases) do tCopy[sAlias] = sCommand end return tCopy end if multishell then - function shell.openTab( ... ) - local tWords = tokenise( ... ) + function shell.openTab(...) + local tWords = tokenise(...) local sCommand = tWords[1] if sCommand then - local sPath = shell.resolveProgram( sCommand ) + local sPath = shell.resolveProgram(sCommand) if sPath == "rom/programs/shell.lua" then - return multishell.launch( createShellEnv( "rom/programs" ), sPath, table.unpack( tWords, 2 ) ) + return multishell.launch(createShellEnv("rom/programs"), sPath, table.unpack(tWords, 2)) elseif sPath ~= nil then - return multishell.launch( createShellEnv( "rom/programs" ), "rom/programs/shell.lua", sCommand, table.unpack( tWords, 2 ) ) + return multishell.launch(createShellEnv("rom/programs"), "rom/programs/shell.lua", sCommand, table.unpack(tWords, 2)) else - printError( "No such program" ) + printError("No such program") end end end - function shell.switchTab( nID ) + function shell.switchTab(nID) expect(1, nID, "number") - multishell.setFocus( nID ) + multishell.setFocus(nID) end end @@ -458,40 +458,40 @@ local tArgs = { ... } if #tArgs > 0 then -- "shell x y z" -- Run the program specified on the commandline - shell.run( ... ) + shell.run(...) else -- "shell" -- Print the header - term.setBackgroundColor( bgColour ) - term.setTextColour( promptColour ) - print( os.version() ) - term.setTextColour( textColour ) + term.setBackgroundColor(bgColour) + term.setTextColour(promptColour) + print(os.version()) + term.setTextColour(textColour) -- Run the startup program if parentShell == nil then - shell.run( "/rom/startup.lua" ) + shell.run("/rom/startup.lua") end -- Read commands and execute them local tCommandHistory = {} while not bExit do - term.redirect( parentTerm ) - term.setBackgroundColor( bgColour ) - term.setTextColour( promptColour ) - write( shell.dir() .. "> " ) - term.setTextColour( textColour ) + term.redirect(parentTerm) + term.setBackgroundColor(bgColour) + term.setTextColour(promptColour) + write(shell.dir() .. "> ") + term.setTextColour(textColour) local sLine - if settings.get( "shell.autocomplete" ) then - sLine = read( nil, tCommandHistory, shell.complete ) + if settings.get("shell.autocomplete") then + sLine = read(nil, tCommandHistory, shell.complete) else - sLine = read( nil, tCommandHistory ) + sLine = read(nil, tCommandHistory) end if sLine:match("%S") and tCommandHistory[#tCommandHistory] ~= sLine then - table.insert( tCommandHistory, sLine ) + table.insert(tCommandHistory, sLine) end - shell.run( sLine ) + shell.run(sLine) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shutdown.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shutdown.lua index 052409eeb..b895c571f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shutdown.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shutdown.lua @@ -1,8 +1,8 @@ if term.isColour() then - term.setTextColour( colours.yellow ) + term.setTextColour(colours.yellow) end -print( "Goodbye" ) -term.setTextColour( colours.white ) +print("Goodbye") +term.setTextColour(colours.white) -sleep( 1 ) +sleep(1) os.shutdown() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/time.lua b/src/main/resources/assets/computercraft/lua/rom/programs/time.lua index ccd83d4ec..988846013 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/time.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/time.lua @@ -1,3 +1,3 @@ local nTime = os.time() local nDay = os.day() -print( "The time is " .. textutils.formatTime( nTime, false ) .. " on Day " .. nDay ) +print("The time is " .. textutils.formatTime(nTime, false) .. " on Day " .. nDay) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua index 8b8923e71..65f93104b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/craft.lua @@ -1,26 +1,26 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end if not turtle.craft then - print( "Requires a Crafty Turtle" ) + print("Requires a Crafty Turtle") return end local tArgs = { ... } local nLimit = nil if #tArgs < 1 then - print( "Usage: craft [number]" ) + print("Usage: craft [number]") return else - nLimit = tonumber( tArgs[1] ) + nLimit = tonumber(tArgs[1]) end local nCrafted = 0 -local nOldCount = turtle.getItemCount( turtle.getSelectedSlot() ) -if turtle.craft( nLimit ) then - local nNewCount = turtle.getItemCount( turtle.getSelectedSlot() ) +local nOldCount = turtle.getItemCount(turtle.getSelectedSlot()) +if turtle.craft(nLimit) then + local nNewCount = turtle.getItemCount(turtle.getSelectedSlot()) if nOldCount <= nLimit then nCrafted = nNewCount else @@ -29,9 +29,9 @@ if turtle.craft( nLimit ) then end if nCrafted > 1 then - print( nCrafted .. " items crafted" ) + print(nCrafted .. " items crafted") elseif nCrafted == 1 then - print( "1 item crafted" ) + print("1 item crafted") else - print( "No items crafted" ) + print("No items crafted") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua index 696c15747..9d539fde4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua @@ -1,5 +1,5 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") end local tMoves = { @@ -77,20 +77,20 @@ local tMoves = { end, } -textutils.slowWrite( "Preparing to get down." ) -textutils.slowPrint( "..", 0.75 ) +textutils.slowWrite("Preparing to get down.") +textutils.slowPrint("..", 0.75) local sAudio = nil -for _, sName in pairs( peripheral.getNames() ) do - if disk.hasAudio( sName ) then - disk.playAudio( sName ) - print( "Jamming to " .. disk.getAudioTitle( sName ) ) +for _, sName in pairs(peripheral.getNames()) do + if disk.hasAudio(sName) then + disk.playAudio(sName) + print("Jamming to " .. disk.getAudioTitle(sName)) sAudio = sName break end end -print( "Press any key to stop the groove" ) +print("Press any key to stop the groove") parallel.waitForAny( function() @@ -110,5 +110,5 @@ parallel.waitForAny( ) if sAudio then - disk.stopAudio( sAudio ) + disk.stopAudio(sAudio) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/equip.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/equip.lua index 0a8f2a480..b69ef4c45 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/equip.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/equip.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } local function printUsage() - print( "Usage: equip " ) + print("Usage: equip ") end if #tArgs ~= 2 then @@ -13,29 +13,29 @@ if #tArgs ~= 2 then return end -local function equip( nSlot, fnEquipFunction ) - turtle.select( nSlot ) - local nOldCount = turtle.getItemCount( nSlot ) +local function equip(nSlot, fnEquipFunction) + turtle.select(nSlot) + local nOldCount = turtle.getItemCount(nSlot) if nOldCount == 0 then - print( "Nothing to equip" ) + print("Nothing to equip") elseif fnEquipFunction() then - local nNewCount = turtle.getItemCount( nSlot ) + local nNewCount = turtle.getItemCount(nSlot) if nNewCount > 0 then - print( "Items swapped" ) + print("Items swapped") else - print( "Item equipped" ) + print("Item equipped") end else - print( "Item not equippable" ) + print("Item not equippable") end end -local nSlot = tonumber( tArgs[1] ) +local nSlot = tonumber(tArgs[1]) local sSide = tArgs[2] if sSide == "left" then - equip( nSlot, turtle.equipLeft ) + equip(nSlot, turtle.equipLeft) elseif sSide == "right" then - equip( nSlot, turtle.equipRight ) + equip(nSlot, turtle.equipRight) else printUsage() return diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua index 2edc5b1fa..9d4313eb1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/excavate.lua @@ -1,18 +1,18 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs ~= 1 then - print( "Usage: excavate " ) + print("Usage: excavate ") return end -- Mine in a quarry pattern until we hit something we can't dig -local size = tonumber( tArgs[1] ) +local size = tonumber(tArgs[1]) if size < 1 then - print( "Excavate diameter must be positive" ) + print("Excavate diameter must be positive") return end @@ -26,8 +26,8 @@ local xDir, zDir = 0, 1 local goTo -- Filled in further down local refuel -- Filled in further down -local function unload( _bKeepOneFuelStack ) - print( "Unloading items..." ) +local function unload(_bKeepOneFuelStack) + print("Unloading items...") for n = 1, 16 do local nCount = turtle.getItemCount(n) if nCount > 0 then @@ -49,22 +49,22 @@ end local function returnSupplies() local x, y, z, xd, zd = xPos, depth, zPos, xDir, zDir - print( "Returning to surface..." ) - goTo( 0, 0, 0, 0, -1 ) + print("Returning to surface...") + goTo(0, 0, 0, 0, -1) local fuelNeeded = 2 * (x + y + z) + 1 - if not refuel( fuelNeeded ) then - unload( true ) - print( "Waiting for fuel" ) - while not refuel( fuelNeeded ) do - os.pullEvent( "turtle_inventory" ) + if not refuel(fuelNeeded) then + unload(true) + print("Waiting for fuel") + while not refuel(fuelNeeded) do + os.pullEvent("turtle_inventory") end else - unload( true ) + unload(true) end - print( "Resuming mining..." ) - goTo( x, y, z, xd, zd ) + print("Resuming mining...") + goTo(x, y, z, xd, zd) end local function collect() @@ -81,18 +81,18 @@ local function collect() if nTotalItems > collected then collected = nTotalItems if math.fmod(collected + unloaded, 50) == 0 then - print( "Mined " .. collected + unloaded .. " items." ) + print("Mined " .. collected + unloaded .. " items.") end end if bFull then - print( "No empty slots left." ) + print("No empty slots left.") return false end return true end -function refuel( ammount ) +function refuel(ammount) local fuelLevel = turtle.getFuelLevel() if fuelLevel == "unlimited" then return true @@ -123,7 +123,7 @@ end local function tryForwards() if not refuel() then - print( "Not enough Fuel" ) + print("Not enough Fuel") returnSupplies() end @@ -141,7 +141,7 @@ local function tryForwards() returnSupplies() end else - sleep( 0.5 ) + sleep(0.5) end end @@ -152,7 +152,7 @@ end local function tryDown() if not refuel() then - print( "Not enough Fuel" ) + print("Not enough Fuel") returnSupplies() end @@ -170,13 +170,13 @@ local function tryDown() returnSupplies() end else - sleep( 0.5 ) + sleep(0.5) end end depth = depth + 1 - if math.fmod( depth, 10 ) == 0 then - print( "Descended " .. depth .. " metres." ) + if math.fmod(depth, 10) == 0 then + print("Descended " .. depth .. " metres.") end return true @@ -192,14 +192,14 @@ local function turnRight() xDir, zDir = zDir, -xDir end -function goTo( x, y, z, xd, zd ) +function goTo(x, y, z, xd, zd) while depth > y do if turtle.up() then depth = depth - 1 elseif turtle.digUp() or turtle.attackUp() then collect() else - sleep( 0.5 ) + sleep(0.5) end end @@ -213,7 +213,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end elseif xPos < x then @@ -226,7 +226,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end end @@ -241,7 +241,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end elseif zPos < z then @@ -254,7 +254,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.dig() or turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end end @@ -265,7 +265,7 @@ function goTo( x, y, z, xd, zd ) elseif turtle.digDown() or turtle.attackDown() then collect() else - sleep( 0.5 ) + sleep(0.5) end end @@ -275,11 +275,11 @@ function goTo( x, y, z, xd, zd ) end if not refuel() then - print( "Out of Fuel" ) + print("Out of Fuel") return end -print( "Excavating..." ) +print("Excavating...") local reseal = false turtle.select(1) @@ -341,16 +341,16 @@ while not done do end end -print( "Returning to surface..." ) +print("Returning to surface...") -- Return to where we started -goTo( 0, 0, 0, 0, -1 ) -unload( false ) -goTo( 0, 0, 0, 0, 1 ) +goTo(0, 0, 0, 0, -1) +unload(false) +goTo(0, 0, 0, 0, 1) -- Seal the hole if reseal then turtle.placeDown() end -print( "Mined " .. collected + unloaded .. " items total." ) +print("Mined " .. collected + unloaded .. " items total.") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua index c8b43b0e9..9c6de67ce 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/go.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs < 1 then - print( "Usage: go " ) + print("Usage: go ") return end @@ -29,7 +29,7 @@ while nArg <= #tArgs do local sDirection = tArgs[nArg] local nDistance = 1 if nArg < #tArgs then - local num = tonumber( tArgs[nArg + 1] ) + local num = tonumber(tArgs[nArg + 1]) if num then nDistance = num nArg = nArg + 1 @@ -43,15 +43,15 @@ while nArg <= #tArgs do if fnHandler() then nDistance = nDistance - 1 elseif turtle.getFuelLevel() == 0 then - print( "Out of fuel" ) + print("Out of fuel") return else sleep(0.5) end end else - print( "No such direction: " .. sDirection ) - print( "Try: forward, back, up, down" ) + print("No such direction: " .. sDirection) + print("Try: forward, back, up, down") return end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua index 77f796196..d9dd5b002 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/refuel.lua @@ -1,18 +1,18 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } local nLimit = 1 if #tArgs > 1 then - print( "Usage: refuel [number]" ) + print("Usage: refuel [number]") return elseif #tArgs > 0 then if tArgs[1] == "all" then nLimit = nil else - nLimit = tonumber( tArgs[1] ) + nLimit = tonumber(tArgs[1]) if not nLimit then print("Invalid limit, expected a number or \"all\"") return @@ -29,17 +29,17 @@ if turtle.getFuelLevel() ~= "unlimited" then local nCount = turtle.getItemCount(n) if nCount > 0 then - turtle.select( n ) - if turtle.refuel( nLimit ) and nLimit then + turtle.select(n) + if turtle.refuel(nLimit) and nLimit then local nNewCount = turtle.getItemCount(n) nLimit = nLimit - (nCount - nNewCount) end end end - print( "Fuel level is " .. turtle.getFuelLevel() ) + print("Fuel level is " .. turtle.getFuelLevel()) if turtle.getFuelLevel() == turtle.getFuelLimit() then - print( "Fuel limit reached" ) + print("Fuel limit reached") end else - print( "Fuel level is unlimited" ) + print("Fuel level is unlimited") end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua index 50183d013..34c0807d9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/tunnel.lua @@ -1,18 +1,18 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs ~= 1 then - print( "Usage: tunnel " ) + print("Usage: tunnel ") return end -- Mine in a quarry pattern until we hit something we can't dig -local length = tonumber( tArgs[1] ) +local length = tonumber(tArgs[1]) if length < 1 then - print( "Tunnel length must be positive" ) + print("Tunnel length must be positive") return end local collected = 0 @@ -20,7 +20,7 @@ local collected = 0 local function collect() collected = collected + 1 if math.fmod(collected, 25) == 0 then - print( "Mined " .. collected .. " items." ) + print("Mined " .. collected .. " items.") end end @@ -81,11 +81,11 @@ local function refuel() end if not tryRefuel() then - print( "Add more fuel to continue." ) + print("Add more fuel to continue.") while not tryRefuel() do - os.pullEvent( "turtle_inventory" ) + os.pullEvent("turtle_inventory") end - print( "Resuming Tunnel." ) + print("Resuming Tunnel.") end end @@ -99,7 +99,7 @@ local function tryUp() elseif turtle.attackUp() then collect() else - sleep( 0.5 ) + sleep(0.5) end end return true @@ -115,7 +115,7 @@ local function tryDown() elseif turtle.attackDown() then collect() else - sleep( 0.5 ) + sleep(0.5) end end return true @@ -131,13 +131,13 @@ local function tryForward() elseif turtle.attack() then collect() else - sleep( 0.5 ) + sleep(0.5) end end return true end -print( "Tunnelling..." ) +print("Tunnelling...") for n = 1, length do turtle.placeDown() @@ -156,11 +156,11 @@ for n = 1, length do if n < length then tryDig() if not tryForward() then - print( "Aborting Tunnel." ) + print("Aborting Tunnel.") break end else - print( "Tunnel complete." ) + print("Tunnel complete.") end end @@ -182,5 +182,5 @@ turtle.turnRight() turtle.turnRight() ]] -print( "Tunnel complete." ) -print( "Mined " .. collected .. " items total." ) +print("Tunnel complete.") +print("Mined " .. collected .. " items total.") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua index d34db5753..e3fbbcbd3 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/turn.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } if #tArgs < 1 then - print( "Usage: turn " ) + print("Usage: turn ") return end @@ -21,7 +21,7 @@ while nArg <= #tArgs do local sDirection = tArgs[nArg] local nDistance = 1 if nArg < #tArgs then - local num = tonumber( tArgs[nArg + 1] ) + local num = tonumber(tArgs[nArg + 1]) if num then nDistance = num nArg = nArg + 1 @@ -32,11 +32,11 @@ while nArg <= #tArgs do local fnHandler = tHandlers[string.lower(sDirection)] if fnHandler then for _ = 1, nDistance do - fnHandler( nArg ) + fnHandler(nArg) end else - print( "No such direction: " .. sDirection ) - print( "Try: left, right" ) + print("No such direction: " .. sDirection) + print("Try: left, right") return end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/unequip.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/unequip.lua index e19672577..97501aa42 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/unequip.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/unequip.lua @@ -1,11 +1,11 @@ if not turtle then - printError( "Requires a Turtle" ) + printError("Requires a Turtle") return end local tArgs = { ... } local function printUsage() - print( "Usage: unequip " ) + print("Usage: unequip ") end if #tArgs ~= 1 then @@ -13,31 +13,31 @@ if #tArgs ~= 1 then return end -local function unequip( fnEquipFunction ) +local function unequip(fnEquipFunction) for nSlot = 1, 16 do - local nOldCount = turtle.getItemCount( nSlot ) + local nOldCount = turtle.getItemCount(nSlot) if nOldCount == 0 then - turtle.select( nSlot ) + turtle.select(nSlot) if fnEquipFunction() then - local nNewCount = turtle.getItemCount( nSlot ) + local nNewCount = turtle.getItemCount(nSlot) if nNewCount > 0 then - print( "Item unequipped" ) + print("Item unequipped") return else - print( "Nothing to unequip" ) + print("Nothing to unequip") return end end end end - print( "No space to unequip item" ) + print("No space to unequip item") end local sSide = tArgs[1] if sSide == "left" then - unequip( turtle.equipLeft ) + unequip(turtle.equipLeft) elseif sSide == "right" then - unequip( turtle.equipRight ) + unequip(turtle.equipRight) else printUsage() return diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/type.lua b/src/main/resources/assets/computercraft/lua/rom/programs/type.lua index c2fabbbaf..ec0ebc0c5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/type.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/type.lua @@ -1,18 +1,18 @@ local tArgs = { ... } if #tArgs < 1 then - print( "Usage: type " ) + print("Usage: type ") return end -local sPath = shell.resolve( tArgs[1] ) -if fs.exists( sPath ) then - if fs.isDir( sPath ) then - print( "directory" ) +local sPath = shell.resolve(tArgs[1]) +if fs.exists(sPath) then + if fs.isDir(sPath) then + print("directory") else - print( "file" ) + print("file") end else - print( "No such path" ) + print("No such path") end diff --git a/src/main/resources/assets/computercraft/lua/rom/startup.lua b/src/main/resources/assets/computercraft/lua/rom/startup.lua index e19eb0317..1b3046092 100644 --- a/src/main/resources/assets/computercraft/lua/rom/startup.lua +++ b/src/main/resources/assets/computercraft/lua/rom/startup.lua @@ -22,130 +22,130 @@ end if http then sPath = sPath .. ":/rom/programs/http" end -shell.setPath( sPath ) -help.setPath( "/rom/help" ) +shell.setPath(sPath) +help.setPath("/rom/help") -- Setup aliases -shell.setAlias( "ls", "list" ) -shell.setAlias( "dir", "list" ) -shell.setAlias( "cp", "copy" ) -shell.setAlias( "mv", "move" ) -shell.setAlias( "rm", "delete" ) -shell.setAlias( "clr", "clear" ) -shell.setAlias( "rs", "redstone" ) -shell.setAlias( "sh", "shell" ) +shell.setAlias("ls", "list") +shell.setAlias("dir", "list") +shell.setAlias("cp", "copy") +shell.setAlias("mv", "move") +shell.setAlias("rm", "delete") +shell.setAlias("clr", "clear") +shell.setAlias("rs", "redstone") +shell.setAlias("sh", "shell") if term.isColor() then - shell.setAlias( "background", "bg" ) - shell.setAlias( "foreground", "fg" ) + shell.setAlias("background", "bg") + shell.setAlias("foreground", "fg") end -- Setup completion functions local function completePastebinPut(shell, text, previous) if previous[2] == "put" then - return fs.complete( text, shell.dir(), true, false ) + return fs.complete(text, shell.dir(), true, false) end end -shell.setCompletionFunction( "rom/programs/alias.lua", completion.build(nil, completion.program) ) -shell.setCompletionFunction( "rom/programs/cd.lua", completion.build(completion.dir) ) -shell.setCompletionFunction( "rom/programs/copy.lua", completion.build( +shell.setCompletionFunction("rom/programs/alias.lua", completion.build(nil, completion.program)) +shell.setCompletionFunction("rom/programs/cd.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/copy.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile -) ) -shell.setCompletionFunction( "rom/programs/delete.lua", completion.build({ completion.dirOrFile, many = true }) ) -shell.setCompletionFunction( "rom/programs/drive.lua", completion.build(completion.dir) ) -shell.setCompletionFunction( "rom/programs/edit.lua", completion.build(completion.file) ) -shell.setCompletionFunction( "rom/programs/eject.lua", completion.build(completion.peripheral) ) -shell.setCompletionFunction( "rom/programs/gps.lua", completion.build({ completion.choice, { "host", "host ", "locate" } }) ) -shell.setCompletionFunction( "rom/programs/help.lua", completion.build(completion.help) ) -shell.setCompletionFunction( "rom/programs/id.lua", completion.build(completion.peripheral) ) -shell.setCompletionFunction( "rom/programs/label.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/delete.lua", completion.build({ completion.dirOrFile, many = true })) +shell.setCompletionFunction("rom/programs/drive.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/edit.lua", completion.build(completion.file)) +shell.setCompletionFunction("rom/programs/eject.lua", completion.build(completion.peripheral)) +shell.setCompletionFunction("rom/programs/gps.lua", completion.build({ completion.choice, { "host", "host ", "locate" } })) +shell.setCompletionFunction("rom/programs/help.lua", completion.build(completion.help)) +shell.setCompletionFunction("rom/programs/id.lua", completion.build(completion.peripheral)) +shell.setCompletionFunction("rom/programs/label.lua", completion.build( { completion.choice, { "get", "get ", "set ", "clear", "clear " } }, completion.peripheral -) ) -shell.setCompletionFunction( "rom/programs/list.lua", completion.build(completion.dir) ) -shell.setCompletionFunction( "rom/programs/mkdir.lua", completion.build({ completion.dir, many = true }) ) -shell.setCompletionFunction( "rom/programs/monitor.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/list.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/mkdir.lua", completion.build({ completion.dir, many = true })) +shell.setCompletionFunction("rom/programs/monitor.lua", completion.build( { completion.peripheral, true }, completion.program -) ) -shell.setCompletionFunction( "rom/programs/move.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/move.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile -) ) -shell.setCompletionFunction( "rom/programs/redstone.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/redstone.lua", completion.build( { completion.choice, { "probe", "set ", "pulse " } }, completion.side -) ) -shell.setCompletionFunction( "rom/programs/rename.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/rename.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile -) ) -shell.setCompletionFunction( "rom/programs/shell.lua", completion.build(completion.program) ) -shell.setCompletionFunction( "rom/programs/type.lua", completion.build(completion.dirOrFile) ) -shell.setCompletionFunction( "rom/programs/set.lua", completion.build({ completion.setting, true }) ) -shell.setCompletionFunction( "rom/programs/advanced/bg.lua", completion.build(completion.program) ) -shell.setCompletionFunction( "rom/programs/advanced/fg.lua", completion.build(completion.program) ) -shell.setCompletionFunction( "rom/programs/fun/dj.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/shell.lua", completion.build(completion.program)) +shell.setCompletionFunction("rom/programs/type.lua", completion.build(completion.dirOrFile)) +shell.setCompletionFunction("rom/programs/set.lua", completion.build({ completion.setting, true })) +shell.setCompletionFunction("rom/programs/advanced/bg.lua", completion.build(completion.program)) +shell.setCompletionFunction("rom/programs/advanced/fg.lua", completion.build(completion.program)) +shell.setCompletionFunction("rom/programs/fun/dj.lua", completion.build( { completion.choice, { "play", "play ", "stop " } }, completion.peripheral -) ) -shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completion.build(completion.file) ) -shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completion.build( +)) +shell.setCompletionFunction("rom/programs/fun/advanced/paint.lua", completion.build(completion.file)) +shell.setCompletionFunction("rom/programs/http/pastebin.lua", completion.build( { completion.choice, { "put ", "get ", "run " } }, completePastebinPut -) ) -shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completion.build({ completion.choice, { "host ", "join " } }) ) -shell.setCompletionFunction( "rom/programs/command/exec.lua", completion.build(completion.command) ) -shell.setCompletionFunction( "rom/programs/http/wget.lua", completion.build({ completion.choice, { "run " } }) ) +)) +shell.setCompletionFunction("rom/programs/rednet/chat.lua", completion.build({ completion.choice, { "host ", "join " } })) +shell.setCompletionFunction("rom/programs/command/exec.lua", completion.build(completion.command)) +shell.setCompletionFunction("rom/programs/http/wget.lua", completion.build({ completion.choice, { "run " } })) if turtle then - shell.setCompletionFunction( "rom/programs/turtle/go.lua", completion.build( + shell.setCompletionFunction("rom/programs/turtle/go.lua", completion.build( { completion.choice, { "left", "right", "forward", "back", "down", "up" }, true, many = true } - ) ) - shell.setCompletionFunction( "rom/programs/turtle/turn.lua", completion.build( + )) + shell.setCompletionFunction("rom/programs/turtle/turn.lua", completion.build( { completion.choice, { "left", "right" }, true, many = true } - ) ) - shell.setCompletionFunction( "rom/programs/turtle/equip.lua", completion.build( + )) + shell.setCompletionFunction("rom/programs/turtle/equip.lua", completion.build( nil, { completion.choice, { "left", "right" } } - ) ) - shell.setCompletionFunction( "rom/programs/turtle/unequip.lua", completion.build( + )) + shell.setCompletionFunction("rom/programs/turtle/unequip.lua", completion.build( { completion.choice, { "left", "right" } } - ) ) + )) end -- Run autorun files -if fs.exists( "/rom/autorun" ) and fs.isDir( "/rom/autorun" ) then - local tFiles = fs.list( "/rom/autorun" ) - for _, sFile in ipairs( tFiles ) do - if string.sub( sFile, 1, 1 ) ~= "." then +if fs.exists("/rom/autorun") and fs.isDir("/rom/autorun") then + local tFiles = fs.list("/rom/autorun") + for _, sFile in ipairs(tFiles) do + if string.sub(sFile, 1, 1) ~= "." then local sPath = "/rom/autorun/" .. sFile - if not fs.isDir( sPath ) then - shell.run( sPath ) + if not fs.isDir(sPath) then + shell.run(sPath) end end end end -local function findStartups( sBaseDir ) +local function findStartups(sBaseDir) local tStartups = nil - local sBasePath = "/" .. fs.combine( sBaseDir, "startup" ) - local sStartupNode = shell.resolveProgram( sBasePath ) + local sBasePath = "/" .. fs.combine(sBaseDir, "startup") + local sStartupNode = shell.resolveProgram(sBasePath) if sStartupNode then tStartups = { sStartupNode } end -- It's possible that there is a startup directory and a startup.lua file, so this has to be -- executed even if a file has already been found. - if fs.isDir( sBasePath ) then + if fs.isDir(sBasePath) then if tStartups == nil then tStartups = {} end - for _, v in pairs( fs.list( sBasePath ) ) do - local sPath = "/" .. fs.combine( sBasePath, v ) - if not fs.isDir( sPath ) then - tStartups[ #tStartups + 1 ] = sPath + for _, v in pairs(fs.list(sBasePath)) do + local sPath = "/" .. fs.combine(sBasePath, v) + if not fs.isDir(sPath) then + tStartups[#tStartups + 1] = sPath end end end @@ -153,19 +153,19 @@ local function findStartups( sBaseDir ) end -- Show MOTD -if settings.get( "motd.enable" ) then - shell.run( "motd" ) +if settings.get("motd.enable") then + shell.run("motd") end -- Run the user created startup, either from disk drives or the root local tUserStartups = nil -if settings.get( "shell.allow_startup" ) then - tUserStartups = findStartups( "/" ) +if settings.get("shell.allow_startup") then + tUserStartups = findStartups("/") end -if settings.get( "shell.allow_disk_startup" ) then - for _, sName in pairs( peripheral.getNames() ) do - if disk.isPresent( sName ) and disk.hasData( sName ) then - local startups = findStartups( disk.getMountPath( sName ) ) +if settings.get("shell.allow_disk_startup") then + for _, sName in pairs(peripheral.getNames()) do + if disk.isPresent(sName) and disk.hasData(sName) then + local startups = findStartups(disk.getMountPath(sName)) if startups then tUserStartups = startups break @@ -174,7 +174,7 @@ if settings.get( "shell.allow_disk_startup" ) then end end if tUserStartups then - for _, v in pairs( tUserStartups ) do - shell.run( v ) + for _, v in pairs(tUserStartups) do + shell.run(v) end end diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index ecb01eaac..81e5afb3c 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -238,8 +238,8 @@ local function matches(eq, exact, left, right) -- If we've already explored/are exploring the left and right then return if eq[left] and eq[left][right] then return true end - if not eq[left] then eq[left] = {[right] = true} else eq[left][right] = true end - if not eq[right] then eq[right] = {[left] = true} else eq[right][left] = true end + if not eq[left] then eq[left] = { [right] = true } else eq[left][right] = true end + if not eq[right] then eq[right] = { [left] = true } else eq[right][left] = true end -- Verify all pairs in left are equal to those in right for k, v in pairs(left) do diff --git a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua index 0c12b18a7..ba714629f 100644 --- a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua +++ b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua @@ -15,7 +15,7 @@ describe("The exec program", function() it("runs a command", function() stub(_G, "commands", { - exec = function() return true, {"Hello World!"} end, + exec = function() return true, { "Hello World!" } end, }) expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) @@ -24,7 +24,7 @@ describe("The exec program", function() it("reports command failures", function() stub(_G, "commands", { - exec = function() return false, {"Hello World!"} end, + exec = function() return false, { "Hello World!" } end, }) expect(capture(stub, "/rom/programs/command/exec.lua computercraft")) diff --git a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua index 61bfe833b..192ba7007 100644 --- a/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua +++ b/src/test/resources/test-rom/spec/programs/http/pastebin_spec.lua @@ -49,7 +49,7 @@ describe("The pastebin program", function() it("upload a program to pastebin", function() setup_request() - local file = fs.open( "testup", "w" ) + local file = fs.open("testup", "w") file.close() expect(capture(stub, "pastebin", "put", "testup")) From 10a27a7a250eea160a8c172e63d8153c792bb53b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Apr 2020 14:38:20 +0100 Subject: [PATCH 171/711] Add utility to check table keys expect.field acts very similarly to expect.expect, though checks a specific table key rather than a function argument. --- .../lua/rom/modules/main/cc/expect.lua | 61 +++++++++++++----- .../test-rom/spec/modules/cc/expect_spec.lua | 62 +++++++++++++------ 2 files changed, 87 insertions(+), 36 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua index 2f4c648b6..24ca66d56 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/expect.lua @@ -5,28 +5,29 @@ local native_select, native_type = select, type ---- Expect an argument to have a specific type. --- --- @tparam number index The 1-based argument index. --- @param value The argument's value. --- @tparam string ... The allowed types of the argument. --- @throws If the value is not one of the allowed types. -local function expect(index, value, ...) - local t = native_type(value) - for i = 1, native_select("#", ...) do - if t == native_select(i, ...) then return true end - end - +local function get_type_names(...) local types = table.pack(...) for i = types.n, 1, -1 do if types[i] == "nil" then table.remove(types, i) end end - local type_names if #types <= 1 then - type_names = tostring(...) + return tostring(...) else - type_names = table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] + return table.concat(types, ", ", 1, #types - 1) .. " or " .. types[#types] + end +end +--- Expect an argument to have a specific type. +-- +-- @tparam number index The 1-based argument index. +-- @param value The argument's value. +-- @tparam string ... The allowed types of the argument. +-- @return The given `value`. +-- @throws If the value is not one of the allowed types. +local function expect(index, value, ...) + local t = native_type(value) + for i = 1, native_select("#", ...) do + if t == native_select(i, ...) then return value end end -- If we can determine the function name with a high level of confidence, try to include it. @@ -36,6 +37,7 @@ local function expect(index, value, ...) if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end end + local type_names = get_type_names(...) if name then error(("bad argument #%d to '%s' (expected %s, got %s)"):format(index, name, type_names, t), 3) else @@ -43,4 +45,31 @@ local function expect(index, value, ...) end end -return { expect = expect } +--- Expect an field to have a specific type. +-- +-- @tparam table tbl The table to index. +-- @tparam string index The field name to check. +-- @tparam string ... The allowed types of the argument. +-- @return The contents of the given field. +-- @throws If the field is not one of the allowed types. +local function field(tbl, index, ...) + expect(1, tbl, "table") + expect(2, index, "string") + + local value = tbl[index] + local t = native_type(value) + for i = 1, native_select("#", ...) do + if t == native_select(i, ...) then return value end + end + + if value == nil then + error(("field '%s' missing from table"):format(index), 3) + else + error(("bad field '%s' (expected %s, got %s)"):format(index, get_type_names(...), t), 3) + end +end + +return { + expect = expect, + field = field, +} diff --git a/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua index 36f076f60..125e43640 100644 --- a/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua @@ -1,31 +1,53 @@ describe("cc.expect", function() local e = require("cc.expect") - it("checks a single type", function() - expect(e.expect(1, "test", "string")):eq(true) - expect(e.expect(1, 2, "number")):eq(true) + describe("expect", function() + it("checks a single type", function() + expect(e.expect(1, "test", "string")):eq("test") + expect(e.expect(1, 2, "number")):eq(2) - expect.error(e.expect, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)") - expect.error(e.expect, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)") + expect.error(e.expect, 1, nil, "string"):eq("bad argument #1 (expected string, got nil)") + expect.error(e.expect, 2, 1, "nil"):eq("bad argument #2 (expected nil, got number)") + end) + + it("checks multiple types", function() + expect(e.expect(1, "test", "string", "number")):eq("test") + expect(e.expect(1, 2, "string", "number")):eq(2) + + expect.error(e.expect, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)") + expect.error(e.expect, 2, false, "string", "table", "number", "nil") + :eq("bad argument #2 (expected string, table or number, got boolean)") + end) + + it("includes the function name", function() + local function worker() + expect(e.expect(1, nil, "string")):eq(true) + end + local function trampoline() + worker() + end + + expect.error(trampoline):eq("expect_spec.lua:27: bad argument #1 to 'worker' (expected string, got nil)") + end) end) - it("checks multiple types", function() - expect(e.expect(1, "test", "string", "number")):eq(true) - expect(e.expect(1, 2, "string", "number")):eq(true) + describe("field", function() + it("checks a single type", function() + expect(e.field({ k = "test" }, "k", "string")):eq("test") + expect(e.field({ k = 2 }, "k", "number")):eq(2) - expect.error(e.expect, 1, nil, "string", "number"):eq("bad argument #1 (expected string or number, got nil)") - expect.error(e.expect, 2, false, "string", "table", "number", "nil") - :eq("bad argument #2 (expected string, table or number, got boolean)") - end) + expect.error(e.field, { k = nil }, "k", "string"):eq("field 'k' missing from table") + expect.error(e.field, { l = 1 }, "l", "nil"):eq("bad field 'l' (expected nil, got number)") + end) - it("includes the function name", function() - local function worker() - expect(e.expect(1, nil, "string")):eq(true) - end - local function trampoline() - worker() - end + it("checks multiple types", function() + expect(e.field({ k = "test" }, "k", "string", "number")):eq("test") + expect(e.field({ k = 2 }, "k", "string", "number")):eq(2) - expect.error(trampoline):eq("expect_spec.lua:26: bad argument #1 to 'worker' (expected string, got nil)") + expect.error(e.field, { k = nil }, "k", "string", "number") + :eq("field 'k' missing from table") + expect.error(e.field, { l = false }, "l", "string", "table", "number", "nil") + :eq("bad field 'l' (expected string, table or number, got boolean)") + end) end) end) From eead8b575569be841f535cc2e44c9f9f2e671c18 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Apr 2020 21:42:59 +0100 Subject: [PATCH 172/711] A small amount of Lua documentation I'd forgotten how tedious this was. I can't say any of these docs are especially good, but it's something. --- doc/stub/http.lua | 22 +- doc/stub/turtle.lua | 226 ++++++++++++++++-- .../computercraft/lua/rom/apis/peripheral.lua | 6 +- .../lua/rom/apis/turtle/turtle.lua | 2 +- .../computercraft/lua/rom/apis/window.lua | 95 +++++--- 5 files changed, 297 insertions(+), 54 deletions(-) diff --git a/doc/stub/http.lua b/doc/stub/http.lua index 8e7df608f..8e8a24c08 100644 --- a/doc/stub/http.lua +++ b/doc/stub/http.lua @@ -199,8 +199,6 @@ function websocket(url, headers) end -- of the initial websocket connection. function websocketAsync(url, headers) end - - --- A websocket, which can be used to send an receive messages with a web -- server. -- @@ -208,6 +206,24 @@ function websocketAsync(url, headers) end -- @see http.websocket On how to open a websocket. local Websocket = {} +--- Send a websocket message to the connected server. +-- +-- @tparam string message The message to send. +-- @tparam[opt] boolean binary Whether this message should be treated as a +-- binary string, rather than encoded text. +-- @throws If the websocket has been closed. function Websocket.send(message, binary) end -function Websocket.receive() end + +--- Wait for a message from the server. +-- +-- @tparam[opt] number timeout The number of seconds to wait if no message is +-- received. +-- @treturn[1] string The received message. +-- @treturn boolean If this was a binary message. +-- @treturn[2] nil If the websocket was closed while waiting, or if we timed out. +-- @throws If the websocket has been closed. +function Websocket.receive(timeout) end + +--- Close this websocket. This will terminate the connection, meaning messages +-- can no longer be sent or received along it. function Websocket.close() end diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua index 0baa4c6fa..7fabd2a8a 100644 --- a/doc/stub/turtle.lua +++ b/doc/stub/turtle.lua @@ -1,42 +1,230 @@ +--- Move the turtle forward one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. function forward() end + +--- Move the turtle backwards one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. function back() end + +--- Move the turtle up one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. function up() end + +--- Move the turtle down one block. +-- @treturn boolean Whether the turtle could successfully move. +-- @treturn string|nil The reason the turtle could not move. function down() end + +--- Rotate the turtle 90 degress to the left. function turnLeft() end + +--- Rotate the turtle 90 degress to the right. function turnRight() end + +--- Attempt to break the block in front of the turtle. +-- +-- This requires a turtle tool capable of breaking the block. Diamond pickaxes +-- (mining turtles) can break any vanilla block, but other tools (such as axes) +-- are more limited. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether a block was broken. +-- @treturn string|nil The reason no block was broken. function dig(side) end + +--- Attempt to break the block above the turtle. See @{dig} for full details. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether a block was broken. +-- @treturn string|nil The reason no block was broken. function digUp(side) end + +--- Attempt to break the block below the turtle. See @{dig} for full details. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether a block was broken. +-- @treturn string|nil The reason no block was broken. function digDown(side) end + +--- Attack the entity in front of the turtle. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether an entity was attacked. +-- @treturn string|nil The reason nothing was attacked. +function attack(side) end + +--- Attack the entity above the turtle. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether an entity was attacked. +-- @treturn string|nil The reason nothing was attacked. +function attackUp(side) end + +--- Attack the entity below the turtle. +-- +-- @tparam[opt] "left"|"right" side The specific tool to use. +-- @treturn boolean Whether an entity was attacked. +-- @treturn string|nil The reason nothing was attacked. +function attackDown(side) end + +--- Place a block or item into the world in front of the turtle. +-- +-- @treturn boolean Whether the block could be placed. +-- @treturn string|nil The reason the block was not placed. function place() end + +--- Place a block or item into the world above the turtle. +-- +-- @treturn boolean Whether the block could be placed. +-- @treturn string|nil The reason the block was not placed. function placeUp() end + +--- Place a block or item into the world below the turtle. +-- +-- @treturn boolean Whether the block could be placed. +-- @treturn string|nil The reason the block was not placed. function placeDown() end + +--- Drop the currently selected stack into the inventory in front of the turtle, +-- or as an item into the world if there is no inventory. +-- +-- @tparam[opt] number count The number of items to drop. If not given, the +-- entire stack will be dropped. +-- @treturn boolean Whether items were dropped. +-- @treturn string|nil The reason the no items were dropped. +-- @see select function drop(count) end -function select(slot) end -function getItemCount(slot) end -function getItemSpace(slot) end + +--- Drop the currently selected stack into the inventory above the turtle, or as +-- an item into the world if there is no inventory. +-- +-- @tparam[opt] number count The number of items to drop. If not given, the +-- entire stack will be dropped. +-- @treturn boolean Whether items were dropped. +-- @treturn string|nil The reason the no items were dropped. +-- @see select +function dropUp(count) end + +--- Drop the currently selected stack into the inventory below the turtle, or as +-- an item into the world if there is no inventory. +-- +-- @tparam[opt] number count The number of items to drop. If not given, the +-- entire stack will be dropped. +-- @treturn boolean Whether items were dropped. +-- @treturn string|nil The reason the no items were dropped. +-- @see select +function dropDown(count) end + +--- Suck an item from the inventory in front of the turtle, or from an item +-- floating in the world. +-- +-- This will pull items into the first acceptable slot, starting at the +-- @{select|currently selected} one. +-- +-- @tparam[opt] number count The number of items to suck. If not given, up to a +-- stack of items will be picked up. +-- @treturn boolean Whether items were picked up. +-- @treturn string|nil The reason the no items were picked up. +function suck(count) end + +--- Suck an item from the inventory above the turtle, or from an item floating +-- in the world. +-- +-- @tparam[opt] number count The number of items to suck. If not given, up to a +-- stack of items will be picked up. +-- @treturn boolean Whether items were picked up. +-- @treturn string|nil The reason the no items were picked up. +function suckUp(count) end + +--- Suck an item from the inventory below the turtle, or from an item floating +-- in the world. +-- +-- @tparam[opt] number count The number of items to suck. If not given, up to a +-- stack of items will be picked up. +-- @treturn boolean Whether items were picked up. +-- @treturn string|nil The reason the no items were picked up. +function suckDown(count) end + +--- Check if there is a solid block in front of the turtle. In this case, solid +-- refers to any non-air or liquid block. +-- +-- @treturn boolean If there is a solid block in front. function detect() end + +--- Check if there is a solid block above the turtle. +-- +-- @treturn boolean If there is a solid block above. function detectUp() end + +--- Check if there is a solid block below the turtle. +-- +-- @treturn boolean If there is a solid block below. function detectDown() end + function compare() end function compareUp() end function compareDown() end -function attack(side) end -function attackUp(side) end -function attackDown(side) end -function dropUp(count) end -function dropDown(count) end -function suck(count) end -function suckUp(count) end -function suckDown(count) end -function getFuelLevel() end -function refuel(count) end -function compareTo(slot) end -function transferTo(slot, count) end -function getSelectedSlot() end -function getFuelLimit() end -function equipLeft() end -function equipRight() end + function inspect() end function inspectUp() end function inspectDown() end + + +--- Change the currently selected slot. +-- +-- The selected slot is determines what slot actions like @{drop} or +-- @{getItemCount} act on. +-- +-- @tparam number slot The slot to select. +-- @see getSelectedSlot +function select(slot) end + +--- Get the currently selected slot. +-- +-- @treturn number The current slot. +-- @see select +function getSelectedSlot() end + +--- Get the number of items in the given slot. +-- +-- @tparam[opt] number slot The slot we wish to check. Defaults to the @{turtle.select|selected slot}. +-- @treturn number The number of items in this slot. +function getItemCount(slot) end + +--- Get the remaining number of items which may be stored in this stack. +-- +-- For instance, if a slot contains 13 blocks of dirt, it has room for another 51. +-- +-- @tparam[opt] number slot The slot we wish to check. Defaults to the @{turtle.select|selected slot}. +-- @treturn number The space left in this slot. +function getItemSpace(slot) end + + +--- Get detailed information about the items in the given slot. +-- +-- @tparam[opt] number slot The slot to get information about. Defaults to the @{turtle.select|selected slot}. +-- @treturn nil|table Information about the given slot, or @{nil} if it is empty. +-- @usage Print the current slot, assuming it contains 13 dirt. +-- +-- print(textutils.serialize(turtle.getItemDetail())) +-- -- => { +-- -- name = "minecraft:dirt", +-- -- damage = 0, +-- -- count = 13, +-- -- } function getItemDetail(slot) end + +function getFuelLevel() end + +function refuel(count) end +function compareTo(slot) end +function transferTo(slot, count) end + +function getFuelLimit() end +function equipLeft() end +function equipRight() end + +function craft(limit) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index c3c71ff65..b9039a52f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -105,14 +105,16 @@ function getMethods(name) return nil end ---- Call a method on a peripheral with a given name +--- Call a method on the peripheral with the given name. -- -- @tparam string name The name of the peripheral to invoke the method on. -- @tparam string method The name of the method -- @param ... Additional arguments to pass to the method -- @return The return values of the peripheral method. -- --- @usage peripheral.call("top", "open", 1) +-- @usage Open the modem on the top of this computer. +-- +-- peripheral.call("top", "open", 1) function call(name, method, ...) expect(1, name, "string") expect(2, method, "string") diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua index f52645524..32852f718 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua @@ -5,7 +5,7 @@ if not turtle then error("Cannot load turtle API on computer", 2) end -native = turtle.native or turtle +native = turtle.native or turtle --- @local local function addCraftMethod(object) if peripheral.getType("left") == "workbench" then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index aa6e5aab6..57bd70c54 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -68,7 +68,7 @@ local string_sub = string.sub -- @tparam number nWidth The width of this window -- @tparam number nHeight The height of this window -- @tparam[opt] boolean bStartVisible Whether this window is visible by --- default. Defaults to `true`. +-- default. Defaults to `true`. -- @treturn Window The constructed window function create(parent, nX, nY, nWidth, nHeight, bStartVisible) expect(1, parent, "table") @@ -229,9 +229,11 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end end - --- Terminal implementation + --- The window object. Refer to the @{window|module's documentation} for + -- a full description. -- -- @type Window + -- @see term.Redirect local window = {} function window.write(sText) @@ -437,6 +439,13 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) return nBackgroundColor end + --- Get the buffered contents of a line in this window. + --- + -- @tparam number y The y position of the line to get. + -- @treturn string The textual content of this line. + -- @treturn string The text colours of this line, suitable for use with @{term.blit}. + -- @treturn string The background colours of this line, suitable for use with @{term.blit}. + -- @throws If `y` is a valid line. function window.getLine(y) if type(y) ~= "number" then expect(1, y, "number") end @@ -448,16 +457,26 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end -- Other functions - function window.setVisible(bVis) - if type(bVis) ~= "boolean" then expect(1, bVis, "boolean") end - if bVisible ~= bVis then - bVisible = bVis + + --- Set whether this window is visible. Invisible windows will not be drawn + -- to the screen until they are made visible again. + -- + -- Making an invisible window visible will immediately draw it. + -- + -- @tparam boolean visible Whether this window is visible. + function window.setVisible(visible) + if type(visible) ~= "boolean" then expect(1, visible, "boolean") end + if bVisible ~= visible then + bVisible = visible if bVisible then window.redraw() end end end + --- Draw this window. This does nothing if the window is not visible. + -- + -- @see Window:setVisible function window.redraw() if bVisible then redraw() @@ -468,6 +487,8 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end end + --- Set the current terminal's cursor to where this window's cursor is. This + -- does nothing if the window is not visible. function window.restoreCursor() if bVisible then updateCursorBlink() @@ -476,31 +497,47 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end end + --- Get the position of the top left corner of this window. + -- + -- @treturn number The x position of this window. + -- @treturn number The y position of this window. function window.getPosition() return nX, nY end - function window.reposition(nNewX, nNewY, nNewWidth, nNewHeight, newParent) - if type(nNewX) ~= "number" then expect(1, nNewX, "number") end - if type(nNewY) ~= "number" then expect(2, nNewY, "number") end - if nNewWidth ~= nil or nNewHeight ~= nil then - expect(3, nNewWidth, "number") - expect(4, nNewHeight, "number") + --- Reposition or resize the given window. + -- + -- This function also accepts arguments to change the size of this window. + -- It is recommended that you fire a `term_resize` event after changing a + -- window's, to allow programs to adjust their sizing. + -- + -- @tparam number new_x The new x position of this window. + -- @tparam number new_y The new y position of this window. + -- @tparam[opt] number new_width The new width of this window. + -- @tparam number new_height The new height of this window. + -- @tparam[opt] term.Redirect new_parent The new redirect object this + -- window should draw to. + function window.reposition(new_x, new_y, new_width, new_height, new_parent) + if type(new_x) ~= "number" then expect(1, new_x, "number") end + if type(new_y) ~= "number" then expect(2, new_y, "number") end + if new_width ~= nil or new_height ~= nil then + expect(3, new_width, "number") + expect(4, new_height, "number") end - if newParent ~= nil and type(newParent) ~= "table" then expect(5, newParent, "table") end + if new_parent ~= nil and type(new_parent) ~= "table" then expect(5, new_parent, "table") end - nX = nNewX - nY = nNewY + nX = new_x + nY = new_y - if newParent then parent = newParent end + if new_parent then parent = new_parent end - if nNewWidth and nNewHeight then + if new_width and new_height then local tNewLines = {} - createEmptyLines(nNewWidth) + createEmptyLines(new_width) local sEmptyText = sEmptySpaceLine local sEmptyTextColor = tEmptyColorLines[nTextColor] local sEmptyBackgroundColor = tEmptyColorLines[nBackgroundColor] - for y = 1, nNewHeight do + for y = 1, new_height do if y > nHeight then tNewLines[y] = { text = sEmptyText, @@ -509,25 +546,25 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) } else local tOldLine = tLines[y] - if nNewWidth == nWidth then + if new_width == nWidth then tNewLines[y] = tOldLine - elseif nNewWidth < nWidth then + elseif new_width < nWidth then tNewLines[y] = { - text = string_sub(tOldLine.text, 1, nNewWidth), - textColor = string_sub(tOldLine.textColor, 1, nNewWidth), - backgroundColor = string_sub(tOldLine.backgroundColor, 1, nNewWidth), + text = string_sub(tOldLine.text, 1, new_width), + textColor = string_sub(tOldLine.textColor, 1, new_width), + backgroundColor = string_sub(tOldLine.backgroundColor, 1, new_width), } else tNewLines[y] = { - text = tOldLine.text .. string_sub(sEmptyText, nWidth + 1, nNewWidth), - textColor = tOldLine.textColor .. string_sub(sEmptyTextColor, nWidth + 1, nNewWidth), - backgroundColor = tOldLine.backgroundColor .. string_sub(sEmptyBackgroundColor, nWidth + 1, nNewWidth), + text = tOldLine.text .. string_sub(sEmptyText, nWidth + 1, new_width), + textColor = tOldLine.textColor .. string_sub(sEmptyTextColor, nWidth + 1, new_width), + backgroundColor = tOldLine.backgroundColor .. string_sub(sEmptyBackgroundColor, nWidth + 1, new_width), } end end end - nWidth = nNewWidth - nHeight = nNewHeight + nWidth = new_width + nHeight = new_height tLines = tNewLines end if bVisible then From b14c7842fc06924d18fc65f0c43ef2acbb53e231 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 19 Apr 2020 15:08:46 +0100 Subject: [PATCH 173/711] Add textutils.unserialiseJSON (#407) This is relatively unoptimised right now, but should be efficient enough for most practical applications. - Add textutils.json_null. This will be serialized into a literal `null`. When deserializing, and parse_null is true, this will be returned instead of a nil. - Add textutils.unserializeJSON (and textutils.unserializeJSON). This is a standard compliant JSON parser (hopefully). - Passing in nbt_style to textutils.unserializeJSON will handle stringified NBT (no quotes around object keys, numeric suffices). We don't currently support byte/long/int arrays - something to add in a future commit. --- .../computercraft/lua/rom/apis/textutils.lua | 237 +++++++++++++++++- .../core/ComputerTestDelegate.java | 4 +- .../test-rom/data/json-parsing/LICENSE | 21 ++ .../test-rom/data/json-parsing/README.md | 9 + .../i_number_double_huge_neg_exp.json | 1 + .../data/json-parsing/i_number_huge_exp.json | 1 + .../i_number_neg_int_huge_exp.json | 1 + .../i_number_pos_double_huge_exp.json | 1 + .../i_number_real_neg_overflow.json | 1 + .../i_number_real_pos_overflow.json | 1 + .../json-parsing/i_number_real_underflow.json | 1 + .../i_number_too_big_neg_int.json | 1 + .../i_number_too_big_pos_int.json | 1 + .../i_number_very_big_negative_int.json | 1 + .../i_object_key_lone_2nd_surrogate.json | 1 + ..._string_1st_surrogate_but_2nd_missing.json | 1 + ...tring_1st_valid_surrogate_2nd_invalid.json | 1 + .../i_string_UTF-16LE_with_BOM.json | Bin 0 -> 12 bytes .../i_string_UTF-8_invalid_sequence.json | 1 + .../i_string_UTF8_surrogate_U+D800.json | 1 + ...incomplete_surrogate_and_escape_valid.json | 1 + .../i_string_incomplete_surrogate_pair.json | 1 + ...ng_incomplete_surrogates_escape_valid.json | 1 + .../i_string_invalid_lonely_surrogate.json | 1 + .../i_string_invalid_surrogate.json | 1 + .../json-parsing/i_string_invalid_utf-8.json | 1 + .../i_string_inverted_surrogates_U+1D11E.json | 1 + .../json-parsing/i_string_iso_latin_1.json | 1 + .../i_string_lone_second_surrogate.json | 1 + .../i_string_lone_utf8_continuation_byte.json | 1 + .../i_string_not_in_unicode_range.json | 1 + .../i_string_overlong_sequence_2_bytes.json | 1 + .../i_string_overlong_sequence_6_bytes.json | 1 + ...string_overlong_sequence_6_bytes_null.json | 1 + .../i_string_truncated-utf-8.json | 1 + .../json-parsing/i_string_utf16BE_no_BOM.json | Bin 0 -> 10 bytes .../json-parsing/i_string_utf16LE_no_BOM.json | Bin 0 -> 10 bytes .../i_structure_500_nested_arrays.json | 1 + .../i_structure_UTF-8_BOM_empty_object.json | 1 + .../n_array_1_true_without_comma.json | 1 + .../json-parsing/n_array_a_invalid_utf8.json | 1 + .../n_array_colon_instead_of_comma.json | 1 + .../n_array_comma_after_close.json | 1 + .../n_array_comma_and_number.json | 1 + .../json-parsing/n_array_double_comma.json | 1 + .../n_array_double_extra_comma.json | 1 + .../json-parsing/n_array_extra_close.json | 1 + .../json-parsing/n_array_extra_comma.json | 1 + .../data/json-parsing/n_array_incomplete.json | 1 + .../n_array_incomplete_invalid_value.json | 1 + .../n_array_inner_array_no_comma.json | 1 + .../json-parsing/n_array_invalid_utf8.json | 1 + .../n_array_items_separated_by_semicolon.json | 1 + .../data/json-parsing/n_array_just_comma.json | 1 + .../data/json-parsing/n_array_just_minus.json | 1 + .../json-parsing/n_array_missing_value.json | 1 + .../n_array_newlines_unclosed.json | 3 + .../n_array_number_and_comma.json | 1 + .../n_array_number_and_several_commas.json | 1 + .../n_array_spaces_vertical_tab_formfeed.json | 1 + .../json-parsing/n_array_star_inside.json | 1 + .../data/json-parsing/n_array_unclosed.json | 1 + .../n_array_unclosed_trailing_comma.json | 1 + .../n_array_unclosed_with_new_lines.json | 3 + .../n_array_unclosed_with_object_inside.json | 1 + .../data/json-parsing/n_incomplete_false.json | 1 + .../data/json-parsing/n_incomplete_null.json | 1 + .../data/json-parsing/n_incomplete_true.json | 1 + .../n_multidigit_number_then_00.json | Bin 0 -> 4 bytes .../data/json-parsing/n_number_++.json | 1 + .../data/json-parsing/n_number_+1.json | 1 + .../data/json-parsing/n_number_+Inf.json | 1 + .../data/json-parsing/n_number_-01.json | 1 + .../data/json-parsing/n_number_-1.0..json | 1 + .../data/json-parsing/n_number_-2..json | 1 + .../data/json-parsing/n_number_-NaN.json | 1 + .../data/json-parsing/n_number_.-1.json | 1 + .../data/json-parsing/n_number_.2e-3.json | 1 + .../data/json-parsing/n_number_0.1.2.json | 1 + .../data/json-parsing/n_number_0.3e+.json | 1 + .../data/json-parsing/n_number_0.3e.json | 1 + .../data/json-parsing/n_number_0.e1.json | 1 + .../json-parsing/n_number_0_capital_E+.json | 1 + .../json-parsing/n_number_0_capital_E.json | 1 + .../data/json-parsing/n_number_0e+.json | 1 + .../data/json-parsing/n_number_0e.json | 1 + .../data/json-parsing/n_number_1.0e+.json | 1 + .../data/json-parsing/n_number_1.0e-.json | 1 + .../data/json-parsing/n_number_1.0e.json | 1 + .../data/json-parsing/n_number_1_000.json | 1 + .../data/json-parsing/n_number_1eE2.json | 1 + .../data/json-parsing/n_number_2.e+3.json | 1 + .../data/json-parsing/n_number_2.e-3.json | 1 + .../data/json-parsing/n_number_2.e3.json | 1 + .../data/json-parsing/n_number_9.e+.json | 1 + .../data/json-parsing/n_number_Inf.json | 1 + .../data/json-parsing/n_number_NaN.json | 1 + .../n_number_U+FF11_fullwidth_digit_one.json | 1 + .../json-parsing/n_number_expression.json | 1 + .../json-parsing/n_number_hex_1_digit.json | 1 + .../json-parsing/n_number_hex_2_digits.json | 1 + .../data/json-parsing/n_number_infinity.json | 1 + .../data/json-parsing/n_number_invalid+-.json | 1 + .../n_number_invalid-negative-real.json | 1 + .../n_number_invalid-utf-8-in-bigger-int.json | 1 + .../n_number_invalid-utf-8-in-exponent.json | 1 + .../n_number_invalid-utf-8-in-int.json | 1 + .../json-parsing/n_number_minus_infinity.json | 1 + ...mber_minus_sign_with_trailing_garbage.json | 1 + .../json-parsing/n_number_minus_space_1.json | 1 + .../n_number_neg_int_starting_with_zero.json | 1 + .../n_number_neg_real_without_int_part.json | 1 + .../n_number_neg_with_garbage_at_end.json | 1 + .../n_number_real_garbage_after_e.json | 1 + ...number_real_with_invalid_utf8_after_e.json | 1 + ...n_number_real_without_fractional_part.json | 1 + .../n_number_starting_with_dot.json | 1 + .../json-parsing/n_number_with_alpha.json | 1 + .../n_number_with_alpha_char.json | 1 + .../n_number_with_leading_zero.json | 1 + .../data/json-parsing/n_object_bad_value.json | 1 + .../json-parsing/n_object_bracket_key.json | 1 + .../n_object_comma_instead_of_colon.json | 1 + .../json-parsing/n_object_double_colon.json | 1 + .../data/json-parsing/n_object_emoji.json | 1 + .../json-parsing/n_object_garbage_at_end.json | 1 + .../n_object_key_with_single_quotes.json | 1 + ...uation_byte_in_key_and_trailing_comma.json | 1 + .../json-parsing/n_object_missing_colon.json | 1 + .../json-parsing/n_object_missing_key.json | 1 + .../n_object_missing_semicolon.json | 1 + .../json-parsing/n_object_missing_value.json | 1 + .../data/json-parsing/n_object_no-colon.json | 1 + .../json-parsing/n_object_non_string_key.json | 1 + ...on_string_key_but_huge_number_instead.json | 1 + .../n_object_repeated_null_null.json | 1 + .../n_object_several_trailing_commas.json | 1 + .../json-parsing/n_object_single_quote.json | 1 + .../json-parsing/n_object_trailing_comma.json | 1 + .../n_object_trailing_comment.json | 1 + .../n_object_trailing_comment_open.json | 1 + .../n_object_trailing_comment_slash_open.json | 1 + ...railing_comment_slash_open_incomplete.json | 1 + .../n_object_two_commas_in_a_row.json | 1 + .../json-parsing/n_object_unquoted_key.json | 1 + .../n_object_unterminated-value.json | 1 + .../n_object_with_single_string.json | 1 + .../n_object_with_trailing_garbage.json | 1 + .../data/json-parsing/n_single_space.json | 1 + .../n_string_1_surrogate_then_escape.json | 1 + .../n_string_1_surrogate_then_escape_u.json | 1 + .../n_string_1_surrogate_then_escape_u1.json | 1 + .../n_string_1_surrogate_then_escape_u1x.json | 1 + .../n_string_accentuated_char_no_quotes.json | 1 + .../json-parsing/n_string_backslash_00.json | Bin 0 -> 6 bytes .../data/json-parsing/n_string_escape_x.json | 1 + .../n_string_escaped_backslash_bad.json | 1 + .../n_string_escaped_ctrl_char_tab.json | 1 + .../json-parsing/n_string_escaped_emoji.json | 1 + .../n_string_incomplete_escape.json | 1 + ...n_string_incomplete_escaped_character.json | 1 + .../n_string_incomplete_surrogate.json | 1 + ...g_incomplete_surrogate_escape_invalid.json | 1 + .../n_string_invalid-utf-8-in-escape.json | 1 + .../n_string_invalid_backslash_esc.json | 1 + .../n_string_invalid_unicode_escape.json | 1 + .../n_string_invalid_utf8_after_escape.json | 1 + .../n_string_leading_uescaped_thinspace.json | 1 + .../n_string_no_quotes_with_bad_escape.json | 1 + .../n_string_single_doublequote.json | 1 + .../json-parsing/n_string_single_quote.json | 1 + ...string_single_string_no_double_quotes.json | 1 + .../n_string_start_escape_unclosed.json | 1 + .../n_string_unescaped_crtl_char.json | Bin 0 -> 7 bytes .../n_string_unescaped_newline.json | 2 + .../json-parsing/n_string_unescaped_tab.json | 1 + .../n_string_unicode_CapitalU.json | 1 + .../n_string_with_trailing_garbage.json | 1 + .../n_structure_100000_opening_arrays.json | 1 + .../n_structure_U+2060_word_joined.json | 1 + .../n_structure_UTF8_BOM_no_data.json | 1 + .../n_structure_angle_bracket_..json | 1 + .../n_structure_angle_bracket_null.json | 1 + .../n_structure_array_trailing_garbage.json | 1 + ...tructure_array_with_extra_array_close.json | 1 + ..._structure_array_with_unclosed_string.json | 1 + .../n_structure_ascii-unicode-identifier.json | 1 + .../n_structure_capitalized_True.json | 1 + .../n_structure_close_unopened_array.json | 1 + ...ucture_comma_instead_of_closing_brace.json | 1 + .../n_structure_double_array.json | 1 + .../json-parsing/n_structure_end_array.json | 1 + .../n_structure_incomplete_UTF8_BOM.json | 1 + .../n_structure_lone-invalid-utf-8.json | 1 + .../n_structure_lone-open-bracket.json | 1 + .../json-parsing/n_structure_no_data.json | 0 .../n_structure_null-byte-outside-string.json | Bin 0 -> 3 bytes ...tructure_number_with_trailing_garbage.json | 1 + ...ure_object_followed_by_closing_object.json | 1 + .../n_structure_object_unclosed_no_value.json | 1 + .../n_structure_object_with_comment.json | 1 + ...tructure_object_with_trailing_garbage.json | 1 + .../n_structure_open_array_apostrophe.json | 1 + .../n_structure_open_array_comma.json | 1 + .../n_structure_open_array_object.json | 1 + .../n_structure_open_array_open_object.json | 1 + .../n_structure_open_array_open_string.json | 1 + .../n_structure_open_array_string.json | 1 + .../json-parsing/n_structure_open_object.json | 1 + .../n_structure_open_object_close_array.json | 1 + .../n_structure_open_object_comma.json | 1 + .../n_structure_open_object_open_array.json | 1 + .../n_structure_open_object_open_string.json | 1 + ...e_open_object_string_with_apostrophes.json | 1 + .../json-parsing/n_structure_open_open.json | 1 + .../n_structure_single_eacute.json | 1 + .../json-parsing/n_structure_single_star.json | 1 + .../json-parsing/n_structure_trailing_#.json | 1 + ...n_structure_uescaped_LF_before_string.json | 1 + .../n_structure_unclosed_array.json | 1 + ...structure_unclosed_array_partial_null.json | 1 + ...cture_unclosed_array_unfinished_false.json | 1 + ...ucture_unclosed_array_unfinished_true.json | 1 + .../n_structure_unclosed_object.json | 1 + .../n_structure_unicode-identifier.json | 1 + ...ructure_whitespace_U+2060_word_joiner.json | 1 + .../n_structure_whitespace_formfeed.json | 1 + .../test-rom/data/json-parsing/skip.lua | 21 ++ .../y_array_arraysWithSpaces.json | 1 + .../json-parsing/y_array_empty-string.json | 1 + .../data/json-parsing/y_array_empty.json | 1 + .../y_array_ending_with_newline.json | 1 + .../data/json-parsing/y_array_false.json | 1 + .../json-parsing/y_array_heterogeneous.json | 1 + .../data/json-parsing/y_array_null.json | 1 + .../y_array_with_1_and_newline.json | 2 + .../y_array_with_leading_space.json | 1 + .../y_array_with_several_null.json | 1 + .../y_array_with_trailing_space.json | 1 + .../test-rom/data/json-parsing/y_number.json | 1 + .../data/json-parsing/y_number_0e+1.json | 1 + .../data/json-parsing/y_number_0e1.json | 1 + .../json-parsing/y_number_after_space.json | 1 + .../y_number_double_close_to_zero.json | 1 + .../json-parsing/y_number_int_with_exp.json | 1 + .../json-parsing/y_number_minus_zero.json | 1 + .../json-parsing/y_number_negative_int.json | 1 + .../json-parsing/y_number_negative_one.json | 1 + .../json-parsing/y_number_negative_zero.json | 1 + .../json-parsing/y_number_real_capital_e.json | 1 + .../y_number_real_capital_e_neg_exp.json | 1 + .../y_number_real_capital_e_pos_exp.json | 1 + .../json-parsing/y_number_real_exponent.json | 1 + .../y_number_real_fraction_exponent.json | 1 + .../json-parsing/y_number_real_neg_exp.json | 1 + .../y_number_real_pos_exponent.json | 1 + .../json-parsing/y_number_simple_int.json | 1 + .../json-parsing/y_number_simple_real.json | 1 + .../test-rom/data/json-parsing/y_object.json | 1 + .../data/json-parsing/y_object_basic.json | 1 + .../json-parsing/y_object_duplicated_key.json | 1 + .../y_object_duplicated_key_and_value.json | 1 + .../data/json-parsing/y_object_empty.json | 1 + .../data/json-parsing/y_object_empty_key.json | 1 + .../y_object_escaped_null_in_key.json | 1 + .../y_object_extreme_numbers.json | 1 + .../json-parsing/y_object_long_strings.json | 1 + .../data/json-parsing/y_object_simple.json | 1 + .../json-parsing/y_object_string_unicode.json | 1 + .../json-parsing/y_object_with_newlines.json | 3 + .../y_string_1_2_3_bytes_UTF-8_sequences.json | 1 + .../y_string_accepted_surrogate_pair.json | 1 + .../y_string_accepted_surrogate_pairs.json | 1 + .../y_string_allowed_escapes.json | 1 + ...y_string_backslash_and_u_escaped_zero.json | 1 + .../y_string_backslash_doublequotes.json | 1 + .../data/json-parsing/y_string_comments.json | 1 + .../y_string_double_escape_a.json | 1 + .../y_string_double_escape_n.json | 1 + .../y_string_escaped_control_character.json | 1 + .../y_string_escaped_noncharacter.json | 1 + .../data/json-parsing/y_string_in_array.json | 1 + .../y_string_in_array_with_leading_space.json | 1 + .../y_string_last_surrogates_1_and_2.json | 1 + .../json-parsing/y_string_nbsp_uescaped.json | 1 + ...y_string_nonCharacterInUTF-8_U+10FFFF.json | 1 + .../y_string_nonCharacterInUTF-8_U+FFFF.json | 1 + .../json-parsing/y_string_null_escape.json | 1 + .../json-parsing/y_string_one-byte-utf-8.json | 1 + .../data/json-parsing/y_string_pi.json | 1 + ...ring_reservedCharacterInUTF-8_U+1BFFF.json | 1 + .../json-parsing/y_string_simple_ascii.json | 1 + .../data/json-parsing/y_string_space.json | 1 + ...rogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json | 1 + .../y_string_three-byte-utf-8.json | 1 + .../json-parsing/y_string_two-byte-utf-8.json | 1 + .../y_string_u+2028_line_sep.json | 1 + .../json-parsing/y_string_u+2029_par_sep.json | 1 + .../data/json-parsing/y_string_uEscape.json | 1 + .../y_string_uescaped_newline.json | 1 + .../y_string_unescaped_char_delete.json | 1 + .../data/json-parsing/y_string_unicode.json | 1 + .../y_string_unicodeEscapedBackslash.json | 1 + .../data/json-parsing/y_string_unicode_2.json | 1 + .../y_string_unicode_U+10FFFE_nonchar.json | 1 + .../y_string_unicode_U+1FFFE_nonchar.json | 1 + ...tring_unicode_U+200B_ZERO_WIDTH_SPACE.json | 1 + ..._string_unicode_U+2064_invisible_plus.json | 1 + .../y_string_unicode_U+FDD0_nonchar.json | 1 + .../y_string_unicode_U+FFFE_nonchar.json | 1 + ...y_string_unicode_escaped_double_quote.json | 1 + .../data/json-parsing/y_string_utf8.json | 1 + .../y_string_with_del_character.json | 1 + .../y_structure_lonely_false.json | 1 + .../json-parsing/y_structure_lonely_int.json | 1 + .../y_structure_lonely_negative_real.json | 1 + .../json-parsing/y_structure_lonely_null.json | 1 + .../y_structure_lonely_string.json | 1 + .../json-parsing/y_structure_lonely_true.json | 1 + .../y_structure_string_empty.json | 1 + .../y_structure_trailing_newline.json | 1 + .../y_structure_true_in_array.json | 1 + .../y_structure_whitespace_array.json | 1 + .../test-rom/spec/apis/textutils_spec.lua | 63 +++++ tools/check-lines.py | 6 +- 325 files changed, 666 insertions(+), 13 deletions(-) create mode 100644 src/test/resources/test-rom/data/json-parsing/LICENSE create mode 100644 src/test/resources/test-rom/data/json-parsing/README.md create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_UTF-16LE_with_BOM.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_utf16BE_no_BOM.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_string_utf16LE_no_BOM.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_structure_500_nested_arrays.json create mode 100644 src/test/resources/test-rom/data/json-parsing/i_structure_UTF-8_BOM_empty_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_1_true_without_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_a_invalid_utf8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_colon_instead_of_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_comma_after_close.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_comma_and_number.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_double_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_double_extra_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_extra_close.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_extra_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_incomplete.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_incomplete_invalid_value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_inner_array_no_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_invalid_utf8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_items_separated_by_semicolon.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_just_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_just_minus.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_missing_value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_newlines_unclosed.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_number_and_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_number_and_several_commas.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_spaces_vertical_tab_formfeed.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_star_inside.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_unclosed.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_unclosed_trailing_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_new_lines.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_array_unclosed_with_object_inside.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_incomplete_false.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_incomplete_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_incomplete_true.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_multidigit_number_then_00.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_++.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_+1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_+Inf.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_-01.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_-1.0..json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_-2..json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_-NaN.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_.-1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_.2e-3.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0.1.2.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0.3e+.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0.3e.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0.e1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E+.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0_capital_E.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0e+.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_0e.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_1.0e+.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_1.0e-.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_1.0e.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_1_000.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_1eE2.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_2.e+3.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_2.e-3.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_2.e3.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_9.e+.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_Inf.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_NaN.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_U+FF11_fullwidth_digit_one.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_expression.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_hex_1_digit.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_hex_2_digits.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_infinity.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_invalid+-.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_invalid-negative-real.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-bigger-int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-exponent.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_invalid-utf-8-in-int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_minus_infinity.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_minus_sign_with_trailing_garbage.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_minus_space_1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_neg_int_starting_with_zero.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_neg_real_without_int_part.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_neg_with_garbage_at_end.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_real_garbage_after_e.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_real_with_invalid_utf8_after_e.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_real_without_fractional_part.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_starting_with_dot.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_with_alpha.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_with_alpha_char.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_number_with_leading_zero.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_bad_value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_bracket_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_comma_instead_of_colon.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_double_colon.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_emoji.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_garbage_at_end.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_key_with_single_quotes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_lone_continuation_byte_in_key_and_trailing_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_missing_colon.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_missing_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_missing_semicolon.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_missing_value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_no-colon.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_non_string_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_non_string_key_but_huge_number_instead.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_repeated_null_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_several_trailing_commas.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_single_quote.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_trailing_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_open.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_trailing_comment_slash_open_incomplete.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_two_commas_in_a_row.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_unquoted_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_unterminated-value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_with_single_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_object_with_trailing_garbage.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_single_space.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_1_surrogate_then_escape_u1x.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_accentuated_char_no_quotes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_backslash_00.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_escape_x.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_escaped_backslash_bad.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_escaped_ctrl_char_tab.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_escaped_emoji.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_incomplete_escaped_character.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_incomplete_surrogate_escape_invalid.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_invalid-utf-8-in-escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_invalid_backslash_esc.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_invalid_unicode_escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_invalid_utf8_after_escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_leading_uescaped_thinspace.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_no_quotes_with_bad_escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_single_doublequote.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_single_quote.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_single_string_no_double_quotes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_start_escape_unclosed.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_unescaped_crtl_char.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_no_data.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_null-byte-outside-string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json create mode 100644 src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json create mode 100644 src/test/resources/test-rom/data/json-parsing/skip.lua create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_empty.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_false.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_0e1.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_after_space.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_basic.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_empty.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_simple.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_comments.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_in_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_pi.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_space.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_utf8.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json create mode 100644 src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua index 1ef4fb1ae..d087c570c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/textutils.lua @@ -3,7 +3,8 @@ -- -- @module textutils -local expect = dofile("rom/modules/main/cc/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua") +local expect, field = expect.expect, expect.field --- Slowly writes string text at current cursor position, -- character-by-character. @@ -307,6 +308,14 @@ local function serializeImpl(t, tTracking, sIndent) end end +local function mk_tbl(str, name) + local msg = "attempt to mutate textutils." .. name + return setmetatable({}, { + __newindex = function() error(msg, 2) end, + __tostring = function() return str end, + }) +end + --- A table representing an empty JSON array, in order to distinguish it from an -- empty JSON object. -- @@ -314,16 +323,22 @@ end -- -- @usage textutils.serialiseJSON(textutils.empty_json_array) -- @see textutils.serialiseJSON -empty_json_array = setmetatable({}, { - __newindex = function() - error("attempt to mutate textutils.empty_json_array", 2) - end, -}) +-- @see textutils.unserialiseJSON +empty_json_array = mk_tbl("[]", "empty_json_array") + +--- A table representing the JSON null value. +-- +-- The contents of this table should not be modified. +-- +-- @usage textutils.serialiseJSON(textutils.json_null) +-- @see textutils.serialiseJSON +-- @see textutils.unserialiseJSON +json_null = mk_tbl("null", "json_null") local function serializeJSONImpl(t, tTracking, bNBTStyle) local sType = type(t) - if t == empty_json_array then - return "[]" + if t == empty_json_array then return "[]" + elseif t == json_null then return "null" elseif sType == "table" then if tTracking[t] ~= nil then @@ -386,6 +401,209 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) end end +local unserialise_json +do + local sub, find, match, concat, tonumber = string.sub, string.find, string.match, table.concat, tonumber + + --- Skip any whitespace + local function skip(str, pos) + local _, last = find(str, "^[ \n\r\v]+", pos) + if last then return last + 1 else return pos end + end + + local escapes = { + ["b"] = '\b', ["f"] = '\f', ["n"] = '\n', ["r"] = '\r', ["t"] = '\t', + ["\""] = "\"", ["/"] = "/", ["\\"] = "\\", + } + + local mt = {} + + local function error_at(pos, msg, ...) + if select('#', ...) > 0 then msg = msg:format(...) end + error(setmetatable({ pos = pos, msg = msg }, mt)) + end + + local function expected(pos, actual, exp) + if actual == "" then actual = "end of input" else actual = ("%q"):format(actual) end + error_at(pos, "Unexpected %s, expected %s.", actual, exp) + end + + local function parse_string(str, pos) + local buf, n = {}, 1 + + while true do + local c = sub(str, pos, pos) + if c == "" then error_at(pos, "Unexpected end of input, expected '\"'.") end + if c == '"' then break end + + if c == '\\' then + -- Handle the various escapes + c = sub(str, pos + 1, pos + 1) + if c == "" then error_at(pos, "Unexpected end of input, expected escape sequence.") end + + if c == "u" then + local num_str = match(str, "^%x%x%x%x", pos + 2) + if not num_str then error_at(pos, "Malformed unicode escape %q.", sub(str, pos + 2, pos + 5)) end + buf[n], n, pos = utf8.char(tonumber(num_str, 16)), n + 1, pos + 6 + else + local unesc = escapes[c] + if not unesc then error_at(pos + 1, "Unknown escape character %q.", unesc) end + buf[n], n, pos = unesc, n + 1, pos + 2 + end + elseif c >= '\x20' then + buf[n], n, pos = c, n + 1, pos + 1 + else + error_at(pos + 1, "Unescaped whitespace %q.", c) + end + end + + return concat(buf, "", 1, n - 1), pos + 1 + end + + local valid = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true } + local function parse_number(str, pos, opts) + local _, last, num_str = find(str, '^(-?%d+%.?%d*[eE]?[+-]?%d*)', pos) + local val = tonumber(num_str) + if not val then error_at(pos, "Malformed number %q.", num_str) end + + if opts.nbt_style and valid[sub(str, pos + 1, pos + 1)] then return val, last + 2 end + + return val, last + 1 + end + + local function parse_ident(str, pos) + local _, last, val = find(str, '^([%a][%w_]*)', pos) + return val, last + 1 + end + + local function decode_impl(str, pos, opts) + local c = sub(str, pos, pos) + if c == '"' then return parse_string(str, pos + 1) + elseif c == "-" or c >= "0" and c <= "9" then return parse_number(str, pos, opts) + elseif c == "t" then + if sub(str, pos + 1, pos + 3) == "rue" then return true, pos + 4 end + elseif c == 'f' then + if sub(str, pos + 1, pos + 4) == "alse" then return false, pos + 5 end + elseif c == 'n' then + if sub(str, pos + 1, pos + 3) == "ull" then + if opts.parse_null then + return json_null, pos + 4 + else + return nil, pos + 4 + end + end + elseif c == "{" then + local obj = {} + + pos = skip(str, pos + 1) + c = sub(str, pos, pos) + + if c == "" then return error_at(pos, "Unexpected end of input, expected '}'.") end + if c == "}" then return obj, pos + 1 end + + while true do + local key, value + if c == "\"" then key, pos = parse_string(str, pos + 1) + elseif opts.nbt_style then key, pos = parse_ident(str, pos) + else return expected(pos, c, "object key") + end + + pos = skip(str, pos) + + c = sub(str, pos, pos) + if c ~= ":" then return expected(pos, c, "':'") end + + value, pos = decode_impl(str, skip(str, pos + 1), opts) + obj[key] = value + + -- Consume the next delimiter + pos = skip(str, pos) + c = sub(str, pos, pos) + if c == "}" then break + elseif c == "," then pos = skip(str, pos + 1) + else return expected(pos, c, "',' or '}'") + end + + c = sub(str, pos, pos) + end + + return obj, pos + 1 + + elseif c == "[" then + local arr, n = {}, 1 + + pos = skip(str, pos + 1) + c = sub(str, pos, pos) + + if c == "" then return expected(pos, c, "']'") end + if c == "]" then return empty_json_array, pos + 1 end + + while true do + n, arr[n], pos = n + 1, decode_impl(str, pos, opts) + + -- Consume the next delimiter + pos = skip(str, pos) + c = sub(str, pos, pos) + if c == "]" then break + elseif c == "," then pos = skip(str, pos + 1) + else return expected(pos, c, "',' or ']'") + end + end + + return arr, pos + 1 + elseif c == "" then error_at(pos, 'Unexpected end of input.') + end + + error_at(pos, "Unexpected character %q.", c) + end + + --- Converts a serialised JSON string back into a reassembled Lua object. + -- + -- This may be used with @{textutils.serializeJSON}, or when communicating + -- with command blocks or web APIs. + -- + -- @tparam string s The serialised string to deserialise. + -- @tparam[opt] { nbt_style? = boolean, parse_null? = boolean } options + -- Options which control how this JSON object is parsed. + -- + -- - `nbt_style`: When true, this will accept [stringified NBT][nbt] strings, + -- as produced by many commands. + -- - `parse_null`: When true, `null` will be parsed as @{json_null}, rather + -- than `nil`. + -- + -- [nbt]: https://minecraft.gamepedia.com/NBT_format + -- @return[1] The deserialised object + -- @treturn[2] nil If the object could not be deserialised. + -- @treturn string A message describing why the JSON string is invalid. + unserialise_json = function(s, options) + expect(1, s, "string") + expect(2, options, "table", "nil") + + if options then + field(options, "nbt_style", "boolean", "nil") + field(options, "nbt_style", "boolean", "nil") + else + options = {} + end + + local ok, res, pos = pcall(decode_impl, s, skip(s, 1), options) + if not ok then + if type(res) == "table" and getmetatable(res) == mt then + return nil, ("Malformed JSON at position %d: %s"):format(res.pos, res.msg) + end + + error(res, 0) + end + + pos = skip(s, pos) + if pos <= #s then + return nil, ("Malformed JSON at position %d: Unexpected trailing character %q."):format(pos, sub(s, pos, pos)) + end + return res + + end +end + --- Convert a Lua object into a textual representation, suitable for -- saving in a file or pretty-printing. -- @@ -449,6 +667,9 @@ end serialiseJSON = serializeJSON -- GB version +unserializeJSON = unserialise_json +unserialiseJSON = unserialise_json + --- Replaces certain characters in a string to make it safe for use in URLs or POST data. -- -- @tparam string str The string to encode diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index fec45a318..a3410f04e 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -96,7 +96,7 @@ public class ComputerTestDelegate try( WritableByteChannel channel = mount.openChannelForWrite( "startup.lua" ); Writer writer = Channels.newWriter( channel, StandardCharsets.UTF_8.newEncoder(), -1 ) ) { - writer.write( "loadfile('test/mcfly.lua', nil, _ENV)('test/spec') cct_test.finish()" ); + writer.write( "loadfile('test-rom/mcfly.lua', nil, _ENV)('test-rom/spec') cct_test.finish()" ); } computer = new Computer( new BasicEnvironment( mount ), term, 0 ); @@ -122,7 +122,7 @@ public class ComputerTestDelegate try { computer.getAPIEnvironment().getFileSystem().mount( - "test-rom", "test", + "test-rom", "test-rom", BasicEnvironment.createMount( ComputerTestDelegate.class, "test-rom", "test" ) ); } diff --git a/src/test/resources/test-rom/data/json-parsing/LICENSE b/src/test/resources/test-rom/data/json-parsing/LICENSE new file mode 100644 index 000000000..c4b3621d5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Nicolas Seriot + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/test/resources/test-rom/data/json-parsing/README.md b/src/test/resources/test-rom/data/json-parsing/README.md new file mode 100644 index 000000000..d0d801887 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/README.md @@ -0,0 +1,9 @@ +# JSON Parsing Test Suite + +This is a collection of JSON test cases from [nst/JSONTestSuite][gh]. We simply +determine whether an object is succesfully parsed or not, and do not check the +contents. + +See `LICENSE` for copyright information. + +[gh]: https://github.com/nst/JSONTestSuite diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json new file mode 100644 index 000000000..ae4c7b71f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_double_huge_neg_exp.json @@ -0,0 +1 @@ +[123.456e-789] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json new file mode 100644 index 000000000..9b5efa236 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_huge_exp.json @@ -0,0 +1 @@ +[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json new file mode 100644 index 000000000..3abd58a5c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_neg_int_huge_exp.json @@ -0,0 +1 @@ +[-1e+9999] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json b/src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json new file mode 100644 index 000000000..e10a7eb62 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_pos_double_huge_exp.json @@ -0,0 +1 @@ +[1.5e+9999] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json b/src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json new file mode 100644 index 000000000..3d628a994 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_real_neg_overflow.json @@ -0,0 +1 @@ +[-123123e100000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json b/src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json new file mode 100644 index 000000000..54d7d3dcd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_real_pos_overflow.json @@ -0,0 +1 @@ +[123123e100000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json b/src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json new file mode 100644 index 000000000..c5236eb26 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_real_underflow.json @@ -0,0 +1 @@ +[123e-10000000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json new file mode 100644 index 000000000..dfa384619 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_neg_int.json @@ -0,0 +1 @@ +[-123123123123123123123123123123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json new file mode 100644 index 000000000..338a8c3c0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_too_big_pos_int.json @@ -0,0 +1 @@ +[100000000000000000000] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json b/src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json new file mode 100644 index 000000000..e2d9738c2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_number_very_big_negative_int.json @@ -0,0 +1 @@ +[-237462374673276894279832749832423479823246327846] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json new file mode 100644 index 000000000..5be7ebaf9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_object_key_lone_2nd_surrogate.json @@ -0,0 +1 @@ +{"\uDFAA":0} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json b/src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json new file mode 100644 index 000000000..3b9e37c67 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_1st_surrogate_but_2nd_missing.json @@ -0,0 +1 @@ +["\uDADA"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json b/src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json new file mode 100644 index 000000000..487592832 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_1st_valid_surrogate_2nd_invalid.json @@ -0,0 +1 @@ +["\uD888\u1234"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_UTF-16LE_with_BOM.json b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-16LE_with_BOM.json new file mode 100644 index 0000000000000000000000000000000000000000..2a79c0629a49133d8f715bddbef19cfb3ef025bd GIT binary patch literal 12 TcmezWFPcG#;U$9-Lo5RTB0vM< literal 0 HcmV?d00001 diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json new file mode 100644 index 000000000..e2a968a15 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_UTF-8_invalid_sequence.json @@ -0,0 +1 @@ +["日шú"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json b/src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json new file mode 100644 index 000000000..916bff920 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_UTF8_surrogate_U+D800.json @@ -0,0 +1 @@ +["í €"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json new file mode 100644 index 000000000..3cb11d229 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_and_escape_valid.json @@ -0,0 +1 @@ +["\uD800\n"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json new file mode 100644 index 000000000..38ec23bb0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogate_pair.json @@ -0,0 +1 @@ +["\uDd1ea"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json new file mode 100644 index 000000000..c9cd6f6c3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_incomplete_surrogates_escape_valid.json @@ -0,0 +1 @@ +["\uD800\uD800\n"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json new file mode 100644 index 000000000..3abbd8d8d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_lonely_surrogate.json @@ -0,0 +1 @@ +["\ud800"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json new file mode 100644 index 000000000..ffddc04f5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_surrogate.json @@ -0,0 +1 @@ +["\ud800abc"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json new file mode 100644 index 000000000..8e45a7eca --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_invalid_utf-8.json @@ -0,0 +1 @@ +["ÿ"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json b/src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json new file mode 100644 index 000000000..0d5456cc3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_inverted_surrogates_U+1D11E.json @@ -0,0 +1 @@ +["\uDd1e\uD834"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json b/src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json new file mode 100644 index 000000000..9389c9823 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_iso_latin_1.json @@ -0,0 +1 @@ +["é"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json b/src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json new file mode 100644 index 000000000..1dbd397f3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_lone_second_surrogate.json @@ -0,0 +1 @@ +["\uDFAA"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json b/src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json new file mode 100644 index 000000000..729337c0a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_lone_utf8_continuation_byte.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json b/src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json new file mode 100644 index 000000000..df90a2916 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_not_in_unicode_range.json @@ -0,0 +1 @@ +["ô¿¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json new file mode 100644 index 000000000..c8cee5e0a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_2_bytes.json @@ -0,0 +1 @@ +["À¯"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json new file mode 100644 index 000000000..9a91da791 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes.json @@ -0,0 +1 @@ +["üƒ¿¿¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json new file mode 100644 index 000000000..d24fffdd9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_overlong_sequence_6_bytes_null.json @@ -0,0 +1 @@ +["ü€€€€€"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json b/src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json new file mode 100644 index 000000000..63c7777fb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/i_string_truncated-utf-8.json @@ -0,0 +1 @@ +["àÿ"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/i_string_utf16BE_no_BOM.json b/src/test/resources/test-rom/data/json-parsing/i_string_utf16BE_no_BOM.json new file mode 100644 index 0000000000000000000000000000000000000000..57e5392ff6309134268c7e3ec2a9289b99ff7148 GIT binary patch literal 10 RcmZRGW>8{y$)Lm#3jhgw0piUj}$`2oKG literal 0 HcmV?d00001 diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json new file mode 100644 index 000000000..700d36086 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_newline.json @@ -0,0 +1,2 @@ +["new +line"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json new file mode 100644 index 000000000..160264a2d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_unescaped_tab.json @@ -0,0 +1 @@ +[" "] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json b/src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json new file mode 100644 index 000000000..17332bb17 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_unicode_CapitalU.json @@ -0,0 +1 @@ +"\UA66D" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json new file mode 100644 index 000000000..efe3bd272 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_string_with_trailing_garbage.json @@ -0,0 +1 @@ +""x \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json b/src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json new file mode 100644 index 000000000..a4823eecc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_100000_opening_arrays.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json b/src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json new file mode 100644 index 000000000..81156a699 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_U+2060_word_joined.json @@ -0,0 +1 @@ +[â ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json b/src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json new file mode 100644 index 000000000..5f282702b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_UTF8_BOM_no_data.json @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json new file mode 100644 index 000000000..a56fef0b0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_..json @@ -0,0 +1 @@ +<.> \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json new file mode 100644 index 000000000..617f26254 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_angle_bracket_null.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json new file mode 100644 index 000000000..5a745e6f3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_array_trailing_garbage.json @@ -0,0 +1 @@ +[1]x \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json new file mode 100644 index 000000000..6cfb1398d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_extra_array_close.json @@ -0,0 +1 @@ +[1]] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json new file mode 100644 index 000000000..ba6b1788b --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_array_with_unclosed_string.json @@ -0,0 +1 @@ +["asd] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json b/src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json new file mode 100644 index 000000000..ef2ab62fe --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_ascii-unicode-identifier.json @@ -0,0 +1 @@ +aÃ¥ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json b/src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json new file mode 100644 index 000000000..7cd88469a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_capitalized_True.json @@ -0,0 +1 @@ +[True] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json new file mode 100644 index 000000000..d2af0c646 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_close_unopened_array.json @@ -0,0 +1 @@ +1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json b/src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json new file mode 100644 index 000000000..ac61b8200 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_comma_instead_of_closing_brace.json @@ -0,0 +1 @@ +{"x": true, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json new file mode 100644 index 000000000..058d1626e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_double_array.json @@ -0,0 +1 @@ +[][] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json new file mode 100644 index 000000000..54caf60b1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_end_array.json @@ -0,0 +1 @@ +] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json b/src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json new file mode 100644 index 000000000..bfcdd514f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_incomplete_UTF8_BOM.json @@ -0,0 +1 @@ +ï»{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json new file mode 100644 index 000000000..8b1296cad --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-invalid-utf-8.json @@ -0,0 +1 @@ +å \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json new file mode 100644 index 000000000..8e2f0bef1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_lone-open-bracket.json @@ -0,0 +1 @@ +[ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_no_data.json b/src/test/resources/test-rom/data/json-parsing/n_structure_no_data.json new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_null-byte-outside-string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_null-byte-outside-string.json new file mode 100644 index 0000000000000000000000000000000000000000..326db14422a756e9bd39221edf37b844cb8471c7 GIT binary patch literal 3 Kcma!Mhy?%vaR9jh literal 0 HcmV?d00001 diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json new file mode 100644 index 000000000..0746539d2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_number_with_trailing_garbage.json @@ -0,0 +1 @@ +2@ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json new file mode 100644 index 000000000..aa9ebaec5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_followed_by_closing_object.json @@ -0,0 +1 @@ +{}} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json new file mode 100644 index 000000000..17d045147 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_unclosed_no_value.json @@ -0,0 +1 @@ +{"": \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json new file mode 100644 index 000000000..ed1b569b7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_comment.json @@ -0,0 +1 @@ +{"a":/*comment*/"b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json new file mode 100644 index 000000000..9ca2336d7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_object_with_trailing_garbage.json @@ -0,0 +1 @@ +{"a": true} "x" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json new file mode 100644 index 000000000..8bebe3af0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_apostrophe.json @@ -0,0 +1 @@ +[' \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json new file mode 100644 index 000000000..6295fdc36 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_comma.json @@ -0,0 +1 @@ +[, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json new file mode 100644 index 000000000..e870445b2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_object.json @@ -0,0 +1 @@ +[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"":[{"": diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json new file mode 100644 index 000000000..7a63c8c57 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_object.json @@ -0,0 +1 @@ +[{ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json new file mode 100644 index 000000000..9822a6baf --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_open_string.json @@ -0,0 +1 @@ +["a \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json new file mode 100644 index 000000000..42a619362 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_array_string.json @@ -0,0 +1 @@ +["a" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json new file mode 100644 index 000000000..81750b96f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object.json @@ -0,0 +1 @@ +{ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json new file mode 100644 index 000000000..eebc700a1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_close_array.json @@ -0,0 +1 @@ +{] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json new file mode 100644 index 000000000..47bc9106f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_comma.json @@ -0,0 +1 @@ +{, \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json new file mode 100644 index 000000000..381ede5de --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_array.json @@ -0,0 +1 @@ +{[ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json new file mode 100644 index 000000000..328c30cd7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_open_string.json @@ -0,0 +1 @@ +{"a \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json new file mode 100644 index 000000000..9dba17090 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_object_string_with_apostrophes.json @@ -0,0 +1 @@ +{'a' \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json b/src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json new file mode 100644 index 000000000..841fd5f86 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_open_open.json @@ -0,0 +1 @@ +["\{["\{["\{["\{ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json b/src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json new file mode 100644 index 000000000..92a39f398 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_single_eacute.json @@ -0,0 +1 @@ +é \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json b/src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json new file mode 100644 index 000000000..f59ec20aa --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_single_star.json @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json b/src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json new file mode 100644 index 000000000..898611087 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_trailing_#.json @@ -0,0 +1 @@ +{"a":"b"}#{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json b/src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json new file mode 100644 index 000000000..df2f0f242 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_uescaped_LF_before_string.json @@ -0,0 +1 @@ +[\u000A""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json new file mode 100644 index 000000000..11209515c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array.json @@ -0,0 +1 @@ +[1 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json new file mode 100644 index 000000000..0d591762c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_partial_null.json @@ -0,0 +1 @@ +[ false, nul \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json new file mode 100644 index 000000000..a2ff8504a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_false.json @@ -0,0 +1 @@ +[ true, fals \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json new file mode 100644 index 000000000..3149e8f5a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_array_unfinished_true.json @@ -0,0 +1 @@ +[ false, tru \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json new file mode 100644 index 000000000..694d69dbd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unclosed_object.json @@ -0,0 +1 @@ +{"asd":"asd" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json b/src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json new file mode 100644 index 000000000..7284aea33 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_unicode-identifier.json @@ -0,0 +1 @@ +Ã¥ \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json new file mode 100644 index 000000000..81156a699 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_U+2060_word_joiner.json @@ -0,0 +1 @@ +[â ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json new file mode 100644 index 000000000..a9ea535d1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/n_structure_whitespace_formfeed.json @@ -0,0 +1 @@ +[ ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/skip.lua b/src/test/resources/test-rom/data/json-parsing/skip.lua new file mode 100644 index 000000000..3b147c7b4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/skip.lua @@ -0,0 +1,21 @@ +local skip = { + -- Should fail, but pass. + -- We're too flexible on number formatting, but it's not a major concern. + "n_number_-01", + "n_number_-2.", + "n_number_0.e1", + "n_number_2.e3", + "n_number_2.e+3", + "n_number_2.e-3", + "n_number_neg_int_starting_with_zero", + "n_number_real_without_fractional_part", + "n_number_with_leading_zero", + + -- Should pass, but fail. + -- These two are due to stack overflows within the parser. + "n_structure_open_array_object", + "n_structure_100000_opening_arrays", +} + +for _, k in pairs(skip) do skip[k] = true end +return skip diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json b/src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json new file mode 100644 index 000000000..582290798 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_arraysWithSpaces.json @@ -0,0 +1 @@ +[[] ] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json b/src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json new file mode 100644 index 000000000..93b6be2bc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_empty-string.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_empty.json b/src/test/resources/test-rom/data/json-parsing/y_array_empty.json new file mode 100644 index 000000000..0637a088a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json b/src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json new file mode 100644 index 000000000..eac5f7b46 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_ending_with_newline.json @@ -0,0 +1 @@ +["a"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_false.json b/src/test/resources/test-rom/data/json-parsing/y_array_false.json new file mode 100644 index 000000000..67b2f0760 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_false.json @@ -0,0 +1 @@ +[false] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json b/src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json new file mode 100644 index 000000000..d3c1e2648 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_heterogeneous.json @@ -0,0 +1 @@ +[null, 1, "1", {}] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_null.json b/src/test/resources/test-rom/data/json-parsing/y_array_null.json new file mode 100644 index 000000000..500db4a86 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_null.json @@ -0,0 +1 @@ +[null] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json new file mode 100644 index 000000000..994825500 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_1_and_newline.json @@ -0,0 +1,2 @@ +[1 +] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json new file mode 100644 index 000000000..18bfe6422 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_leading_space.json @@ -0,0 +1 @@ + [1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json new file mode 100644 index 000000000..99f6c5d1d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_several_null.json @@ -0,0 +1 @@ +[1,null,null,null,2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json b/src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json new file mode 100644 index 000000000..de9e7a944 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_array_with_trailing_space.json @@ -0,0 +1 @@ +[2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number.json b/src/test/resources/test-rom/data/json-parsing/y_number.json new file mode 100644 index 000000000..e5f5cc334 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number.json @@ -0,0 +1 @@ +[123e65] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json b/src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json new file mode 100644 index 000000000..d1d396706 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_0e+1.json @@ -0,0 +1 @@ +[0e+1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_0e1.json b/src/test/resources/test-rom/data/json-parsing/y_number_0e1.json new file mode 100644 index 000000000..3283a7936 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_0e1.json @@ -0,0 +1 @@ +[0e1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_after_space.json b/src/test/resources/test-rom/data/json-parsing/y_number_after_space.json new file mode 100644 index 000000000..623570d96 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_after_space.json @@ -0,0 +1 @@ +[ 4] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json b/src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json new file mode 100644 index 000000000..96555ff78 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_double_close_to_zero.json @@ -0,0 +1 @@ +[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json new file mode 100644 index 000000000..a4ca9e754 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_int_with_exp.json @@ -0,0 +1 @@ +[20e1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json b/src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json new file mode 100644 index 000000000..37af1312a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_minus_zero.json @@ -0,0 +1 @@ +[-0] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json b/src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json new file mode 100644 index 000000000..8e30f8bd9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_negative_int.json @@ -0,0 +1 @@ +[-123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json b/src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json new file mode 100644 index 000000000..99d21a2a0 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_negative_one.json @@ -0,0 +1 @@ +[-1] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json b/src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json new file mode 100644 index 000000000..37af1312a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_negative_zero.json @@ -0,0 +1 @@ +[-0] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json new file mode 100644 index 000000000..6edbdfcb1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e.json @@ -0,0 +1 @@ +[1E22] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json new file mode 100644 index 000000000..0a01bd3ef --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_neg_exp.json @@ -0,0 +1 @@ +[1E-2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json new file mode 100644 index 000000000..5a8fc0972 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_capital_e_pos_exp.json @@ -0,0 +1 @@ +[1E+2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json new file mode 100644 index 000000000..da2522d61 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_exponent.json @@ -0,0 +1 @@ +[123e45] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json new file mode 100644 index 000000000..3944a7a45 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_fraction_exponent.json @@ -0,0 +1 @@ +[123.456e78] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json new file mode 100644 index 000000000..ca40d3c25 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_neg_exp.json @@ -0,0 +1 @@ +[1e-2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json b/src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json new file mode 100644 index 000000000..343601d51 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_real_pos_exponent.json @@ -0,0 +1 @@ +[1e+2] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json b/src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json new file mode 100644 index 000000000..e47f69afc --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_simple_int.json @@ -0,0 +1 @@ +[123] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json b/src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json new file mode 100644 index 000000000..b02878e5f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_number_simple_real.json @@ -0,0 +1 @@ +[123.456789] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object.json b/src/test/resources/test-rom/data/json-parsing/y_object.json new file mode 100644 index 000000000..78262eda3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object.json @@ -0,0 +1 @@ +{"asd":"sdf", "dfg":"fgh"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_basic.json b/src/test/resources/test-rom/data/json-parsing/y_object_basic.json new file mode 100644 index 000000000..646bbe7bb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_basic.json @@ -0,0 +1 @@ +{"asd":"sdf"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json new file mode 100644 index 000000000..bbc2e1ce4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key.json @@ -0,0 +1 @@ +{"a":"b","a":"c"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json new file mode 100644 index 000000000..211581c20 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_duplicated_key_and_value.json @@ -0,0 +1 @@ +{"a":"b","a":"b"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_empty.json b/src/test/resources/test-rom/data/json-parsing/y_object_empty.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_empty.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json b/src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json new file mode 100644 index 000000000..c0013d3b8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_empty_key.json @@ -0,0 +1 @@ +{"":0} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json b/src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json new file mode 100644 index 000000000..593f0f67f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_escaped_null_in_key.json @@ -0,0 +1 @@ +{"foo\u0000bar": 42} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json b/src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json new file mode 100644 index 000000000..a0d3531c3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_extreme_numbers.json @@ -0,0 +1 @@ +{ "min": -1.0e+28, "max": 1.0e+28 } \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json b/src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json new file mode 100644 index 000000000..bdc4a0871 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_long_strings.json @@ -0,0 +1 @@ +{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_simple.json b/src/test/resources/test-rom/data/json-parsing/y_object_simple.json new file mode 100644 index 000000000..dacac917f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_simple.json @@ -0,0 +1 @@ +{"a":[]} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json b/src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json new file mode 100644 index 000000000..8effdb297 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_string_unicode.json @@ -0,0 +1 @@ +{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json b/src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json new file mode 100644 index 000000000..246ec6b34 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_object_with_newlines.json @@ -0,0 +1,3 @@ +{ +"a": "b" +} \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json b/src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json new file mode 100644 index 000000000..9967ddeb8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_1_2_3_bytes_UTF-8_sequences.json @@ -0,0 +1 @@ +["\u0060\u012a\u12AB"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json new file mode 100644 index 000000000..996875cc8 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pair.json @@ -0,0 +1 @@ +["\uD801\udc37"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json new file mode 100644 index 000000000..3401021ec --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_accepted_surrogate_pairs.json @@ -0,0 +1 @@ +["\ud83d\ude39\ud83d\udc8d"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json b/src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json new file mode 100644 index 000000000..7f495532f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_allowed_escapes.json @@ -0,0 +1 @@ +["\"\\\/\b\f\n\r\t"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json new file mode 100644 index 000000000..d4439eda7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_and_u_escaped_zero.json @@ -0,0 +1 @@ +["\\u0000"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json new file mode 100644 index 000000000..ae03243b6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_backslash_doublequotes.json @@ -0,0 +1 @@ +["\""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_comments.json b/src/test/resources/test-rom/data/json-parsing/y_string_comments.json new file mode 100644 index 000000000..2260c20c2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_comments.json @@ -0,0 +1 @@ +["a/*b*/c/*d//e"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json new file mode 100644 index 000000000..6715d6f40 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_a.json @@ -0,0 +1 @@ +["\\a"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json new file mode 100644 index 000000000..44ca56c4d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_double_escape_n.json @@ -0,0 +1 @@ +["\\n"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json new file mode 100644 index 000000000..5b014a9c2 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_control_character.json @@ -0,0 +1 @@ +["\u0012"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json new file mode 100644 index 000000000..2ff52e2c5 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_escaped_noncharacter.json @@ -0,0 +1 @@ +["\uFFFF"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_in_array.json b/src/test/resources/test-rom/data/json-parsing/y_string_in_array.json new file mode 100644 index 000000000..21d7ae4cd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_in_array.json @@ -0,0 +1 @@ +["asd"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json b/src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json new file mode 100644 index 000000000..9e1887c1e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_in_array_with_leading_space.json @@ -0,0 +1 @@ +[ "asd"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json b/src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json new file mode 100644 index 000000000..3919cef76 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_last_surrogates_1_and_2.json @@ -0,0 +1 @@ +["\uDBFF\uDFFF"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json b/src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json new file mode 100644 index 000000000..2085ab1a1 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_nbsp_uescaped.json @@ -0,0 +1 @@ +["new\u00A0line"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json new file mode 100644 index 000000000..059e4d9dd --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json @@ -0,0 +1 @@ +["ô¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json new file mode 100644 index 000000000..4c913bd41 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_nonCharacterInUTF-8_U+FFFF.json @@ -0,0 +1 @@ +["ï¿¿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json b/src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json new file mode 100644 index 000000000..c1ad84404 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_null_escape.json @@ -0,0 +1 @@ +["\u0000"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json b/src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json new file mode 100644 index 000000000..157185923 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_one-byte-utf-8.json @@ -0,0 +1 @@ +["\u002c"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_pi.json b/src/test/resources/test-rom/data/json-parsing/y_string_pi.json new file mode 100644 index 000000000..9df11ae88 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_pi.json @@ -0,0 +1 @@ +["Ï€"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json b/src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json new file mode 100644 index 000000000..10a33a171 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_reservedCharacterInUTF-8_U+1BFFF.json @@ -0,0 +1 @@ +["𛿿"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json b/src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json new file mode 100644 index 000000000..8cadf7d05 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_simple_ascii.json @@ -0,0 +1 @@ +["asd "] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_space.json b/src/test/resources/test-rom/data/json-parsing/y_string_space.json new file mode 100644 index 000000000..efd782cc3 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_space.json @@ -0,0 +1 @@ +" " \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json b/src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json new file mode 100644 index 000000000..7620b6655 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json @@ -0,0 +1 @@ +["\uD834\uDd1e"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json b/src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json new file mode 100644 index 000000000..108f1d67d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_three-byte-utf-8.json @@ -0,0 +1 @@ +["\u0821"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json b/src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json new file mode 100644 index 000000000..461503c31 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_two-byte-utf-8.json @@ -0,0 +1 @@ +["\u0123"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json b/src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json new file mode 100644 index 000000000..897b6021a --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_u+2028_line_sep.json @@ -0,0 +1 @@ +["
"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json b/src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json new file mode 100644 index 000000000..8cd998c89 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_u+2029_par_sep.json @@ -0,0 +1 @@ +["
"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json b/src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json new file mode 100644 index 000000000..f7b41a02f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_uEscape.json @@ -0,0 +1 @@ +["\u0061\u30af\u30EA\u30b9"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json b/src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json new file mode 100644 index 000000000..3a5a220b6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_uescaped_newline.json @@ -0,0 +1 @@ +["new\u000Aline"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json b/src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json new file mode 100644 index 000000000..7d064f498 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unescaped_char_delete.json @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode.json new file mode 100644 index 000000000..3598095b7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode.json @@ -0,0 +1 @@ +["\uA66D"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json new file mode 100644 index 000000000..0bb3b51e7 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicodeEscapedBackslash.json @@ -0,0 +1 @@ +["\u005C"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json new file mode 100644 index 000000000..a7dcb9768 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_2.json @@ -0,0 +1 @@ +["â‚㈴â‚"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json new file mode 100644 index 000000000..9a8370b96 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+10FFFE_nonchar.json @@ -0,0 +1 @@ +["\uDBFF\uDFFE"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json new file mode 100644 index 000000000..c51f8ae45 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+1FFFE_nonchar.json @@ -0,0 +1 @@ +["\uD83F\uDFFE"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json new file mode 100644 index 000000000..626d5f815 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json @@ -0,0 +1 @@ +["\u200B"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json new file mode 100644 index 000000000..1e23972c6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+2064_invisible_plus.json @@ -0,0 +1 @@ +["\u2064"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json new file mode 100644 index 000000000..18ef151b4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FDD0_nonchar.json @@ -0,0 +1 @@ +["\uFDD0"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json new file mode 100644 index 000000000..13d261fda --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_U+FFFE_nonchar.json @@ -0,0 +1 @@ +["\uFFFE"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json new file mode 100644 index 000000000..4e6257856 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_unicode_escaped_double_quote.json @@ -0,0 +1 @@ +["\u0022"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_utf8.json b/src/test/resources/test-rom/data/json-parsing/y_string_utf8.json new file mode 100644 index 000000000..40878435f --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_utf8.json @@ -0,0 +1 @@ +["€ð„ž"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json b/src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json new file mode 100644 index 000000000..8bd24907d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_string_with_del_character.json @@ -0,0 +1 @@ +["aa"] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json new file mode 100644 index 000000000..02e4a84d6 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_false.json @@ -0,0 +1 @@ +false \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json new file mode 100644 index 000000000..f70d7bba4 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_int.json @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json new file mode 100644 index 000000000..b5135a207 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_negative_real.json @@ -0,0 +1 @@ +-0.1 \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json new file mode 100644 index 000000000..ec747fa47 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_null.json @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json new file mode 100644 index 000000000..b6e982ca9 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_string.json @@ -0,0 +1 @@ +"asd" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json new file mode 100644 index 000000000..f32a5804e --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_lonely_true.json @@ -0,0 +1 @@ +true \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json b/src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json new file mode 100644 index 000000000..3cc762b55 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_string_empty.json @@ -0,0 +1 @@ +"" \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json b/src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json new file mode 100644 index 000000000..0c3426d4c --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_trailing_newline.json @@ -0,0 +1 @@ +["a"] diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json b/src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json new file mode 100644 index 000000000..de601e305 --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_true_in_array.json @@ -0,0 +1 @@ +[true] \ No newline at end of file diff --git a/src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json b/src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json new file mode 100644 index 000000000..2bedf7f2d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_structure_whitespace_array.json @@ -0,0 +1 @@ + [] \ No newline at end of file diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index ab881d60b..bdef2dbd2 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -70,6 +70,69 @@ describe("The textutils library", function() expect.error(textutils.serialiseJSON, nil):eq("bad argument #1 (expected table, string, number or boolean, got nil)") expect.error(textutils.serialiseJSON, "", 1):eq("bad argument #2 (expected boolean, got number)") end) + + it("serializes empty arrays", function() + expect(textutils.serializeJSON(textutils.empty_json_array)):eq("[]") + end) + + it("serializes null", function() + expect(textutils.serializeJSON(textutils.json_null)):eq("null") + end) + end) + + describe("textutils.unserializeJSON", function() + describe("parses", function() + it("a list of primitives", function() + expect(textutils.unserializeJSON('[1, true, false, "hello"]')):same { 1, true, false, "hello" } + end) + + it("null when parse_null is true", function() + expect(textutils.unserializeJSON("null", { parse_null = true })):eq(textutils.json_null) + end) + + it("null when parse_null is false", function() + expect(textutils.unserializeJSON("null", { parse_null = false })):eq(nil) + end) + + it("an empty array", function() + expect(textutils.unserializeJSON("[]", { parse_null = false })):eq(textutils.empty_json_array) + end) + + it("basic objects", function() + expect(textutils.unserializeJSON([[{ "a": 1, "b":2 }]])):same { a = 1, b = 2 } + end) + end) + + describe("parses using NBT-style syntax", function() + it("basic objects", function() + expect(textutils.unserializeJSON([[{ a: 1, b:2 }]], { nbt_style = true })):same { a = 1, b = 2 } + end) + + it("suffixed numbers", function() + expect(textutils.unserializeJSON("1b", { nbt_style = true })):eq(1) + end) + end) + + describe("passes nst/JSONTestSuite", function() + local search_path = "test-rom/data/json-parsing" + local skip = dofile(search_path .. "/skip.lua") + for _, file in pairs(fs.find(search_path .. "/*.json")) do + local name = fs.getName(file):sub(1, -6); + (skip[name] and pending or it)(name, function() + local h = io.open(file, "r") + local contents = h:read("*a") + h:close() + + local res, err = textutils.unserializeJSON(contents) + local kind = fs.getName(file):sub(1, 1) + if kind == "n" then + expect(res):eq(nil) + elseif kind == "y" then + if err ~= nil then fail("Expected test to pass, but failed with " .. err) end + end + end) + end + end) end) describe("textutils.urlEncode", function() diff --git a/tools/check-lines.py b/tools/check-lines.py index e1fcba620..d50d4610d 100644 --- a/tools/check-lines.py +++ b/tools/check-lines.py @@ -3,10 +3,10 @@ import pathlib, sys problems = False # Skip images and files without extensions -exclude = [ ".png", "" ] +exclude = [ "*.png", "**/data/json-parsing/*.json" ] -for path in pathlib.Path(".").glob("src/**/*"): - if path.is_dir() or path.suffix in exclude: +for path in pathlib.Path("src").glob("**/*"): + if path.is_dir() or path.suffix == "" or any(path.match(x) for x in exclude): continue with path.open(encoding="utf-8") as file: From c5f918ad9519db6040dd69daaff5eb34116d9b46 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 19 Apr 2020 20:11:49 +0100 Subject: [PATCH 174/711] Increase the maximum limit for websocket messages The constructor for the websocket handshaker has a default maxFramePayloadLength of 64kb, hence me being confused. Closes #376 --- src/main/java/dan200/computercraft/ComputerCraft.java | 3 +-- .../computercraft/core/apis/http/websocket/Websocket.java | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 626d387f0..430208196 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -22,7 +22,6 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.AddressPredicate; import dan200.computercraft.core.apis.ApiFactories; -import dan200.computercraft.core.apis.http.websocket.Websocket; import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.filesystem.ComboMount; import dan200.computercraft.core.filesystem.FileMount; @@ -128,7 +127,7 @@ public class ComputerCraft public static long httpMaxDownload = 16 * 1024 * 1024; public static long httpMaxUpload = 4 * 1024 * 1024; public static int httpMaxWebsockets = 4; - public static int httpMaxWebsocketMessage = Websocket.MAX_MESSAGE_SIZE; + public static int httpMaxWebsocketMessage = 128 * 1024; public static boolean enableCommandBlock = false; public static int modem_range = 64; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index 67a15e963..c1d91a078 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -40,7 +40,11 @@ import java.util.concurrent.Future; */ public class Websocket extends Resource { - public static final int MAX_MESSAGE_SIZE = 64 * 1024; + /** + * We declare the maximum size to be 2^30 bytes. While messages can be much longer, we set an arbitrary limit as + * working with larger messages (especially within a Lua VM) is absurd. + */ + public static final int MAX_MESSAGE_SIZE = 1 << 30; static final String SUCCESS_EVENT = "websocket_success"; static final String FAILURE_EVENT = "websocket_failure"; From cea8be7efab3ac40c7acbf3a92fa4c1fd384f92d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 20 Apr 2020 12:01:44 +0100 Subject: [PATCH 175/711] Fix terrible grammar in the README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 78a9cb32e..67bfd5644 100644 --- a/README.md +++ b/README.md @@ -37,8 +37,8 @@ several features have been included, such as full block modems, the Cobalt runti computers. ## Contributing -Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to developing the -mod, [check out the instructions here](CONTRIBUTING.md#developing). +Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started +developing the mod, [check out the instructions here](CONTRIBUTING.md#developing). ## Community If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about From 524b6f1d8ae57875f7e330813d96c836f6f27e8e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 20 Apr 2020 20:24:16 +0100 Subject: [PATCH 176/711] Make a bunch of config fields private --- .../dan200/computercraft/shared/Config.java | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 60e0e454a..949f73835 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -36,43 +36,43 @@ public final class Config private static final String TRANSLATION_PREFIX = "gui.computercraft.config."; - private static ConfigValue computerSpaceLimit; - private static ConfigValue floppySpaceLimit; - private static ConfigValue maximumFilesOpen; - private static ConfigValue disableLua51Features; - private static ConfigValue defaultComputerSettings; - private static ConfigValue debugEnabled; - private static ConfigValue logComputerErrors; + private static final ConfigValue computerSpaceLimit; + private static final ConfigValue floppySpaceLimit; + private static final ConfigValue maximumFilesOpen; + private static final ConfigValue disableLua51Features; + private static final ConfigValue defaultComputerSettings; + private static final ConfigValue debugEnabled; + private static final ConfigValue logComputerErrors; - private static ConfigValue computerThreads; - private static ConfigValue maxMainGlobalTime; - private static ConfigValue maxMainComputerTime; + private static final ConfigValue computerThreads; + private static final ConfigValue maxMainGlobalTime; + private static final ConfigValue maxMainComputerTime; - private static ConfigValue httpEnabled; - private static ConfigValue httpWebsocketEnabled; - private static ConfigValue> httpWhitelist; - private static ConfigValue> httpBlacklist; + private static final ConfigValue httpEnabled; + private static final ConfigValue httpWebsocketEnabled; + private static final ConfigValue> httpWhitelist; + private static final ConfigValue> httpBlacklist; - private static ConfigValue httpTimeout; - private static ConfigValue httpMaxRequests; - private static ConfigValue httpMaxDownload; - private static ConfigValue httpMaxUpload; - private static ConfigValue httpMaxWebsockets; - private static ConfigValue httpMaxWebsocketMessage; + private static final ConfigValue httpTimeout; + private static final ConfigValue httpMaxRequests; + private static final ConfigValue httpMaxDownload; + private static final ConfigValue httpMaxUpload; + private static final ConfigValue httpMaxWebsockets; + private static final ConfigValue httpMaxWebsocketMessage; - private static ConfigValue commandBlockEnabled; - private static ConfigValue modemRange; - private static ConfigValue modemHighAltitudeRange; - private static ConfigValue modemRangeDuringStorm; - private static ConfigValue modemHighAltitudeRangeDuringStorm; - private static ConfigValue maxNotesPerTick; + private static final ConfigValue commandBlockEnabled; + private static final ConfigValue modemRange; + private static final ConfigValue modemHighAltitudeRange; + private static final ConfigValue modemRangeDuringStorm; + private static final ConfigValue modemHighAltitudeRangeDuringStorm; + private static final ConfigValue maxNotesPerTick; - private static ConfigValue turtlesNeedFuel; - private static ConfigValue turtleFuelLimit; - private static ConfigValue advancedTurtleFuelLimit; - private static ConfigValue turtlesObeyBlockProtection; - private static ConfigValue turtlesCanPush; - private static ConfigValue> turtleDisabledActions; + private static final ConfigValue turtlesNeedFuel; + private static final ConfigValue turtleFuelLimit; + private static final ConfigValue advancedTurtleFuelLimit; + private static final ConfigValue turtlesObeyBlockProtection; + private static final ConfigValue turtlesCanPush; + private static final ConfigValue> turtleDisabledActions; private static final ForgeConfigSpec spec; From df557e03fa40bbe9fc2ad61a45caf99815a04757 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 20 Apr 2020 20:25:09 +0100 Subject: [PATCH 177/711] Fix turtles incorrectly handling waterlogged blocks This would return true for any block with a fluid in it, including waterlogged blocks. This resulted in much broken behaviour - Turtles cannot place blocks when waterlogged (fixedd #385) - Turtles could move into waterlogged blocks (such as fences), replacing them. --- src/main/java/dan200/computercraft/shared/util/WorldUtil.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index d80c28b99..2c6d69fb6 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.util; import com.google.common.base.Predicate; import com.google.common.collect.MapMaker; -import net.minecraft.block.BlockState; import net.minecraft.entity.*; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; @@ -54,8 +53,7 @@ public final class WorldUtil public static boolean isLiquidBlock( World world, BlockPos pos ) { if( !World.isValid( pos ) ) return false; - BlockState state = world.getBlockState( pos ); - return !state.getFluidState().isEmpty(); + return world.getBlockState( pos ).getMaterial().isLiquid(); } public static boolean isVecInside( VoxelShape shape, Vec3d vec ) From 7c1154ddfc88ba93c6830b94a83c8c44da18403c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 21 Apr 2020 08:51:49 +0100 Subject: [PATCH 178/711] Avoid shadowing of names in peripheral.isPresent Fixes #415 --- .../assets/computercraft/lua/rom/apis/peripheral.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index b9039a52f..53b849adc 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -54,9 +54,9 @@ function isPresent(name) end for n = 1, #sides do - local name = sides[n] - if native.getType(name) == "modem" and not native.call(name, "isWireless") and - native.call(name, "isPresentRemote", name) + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", name) then return true end From 11bf601db905e7880c413fdf5b58fb01e812f9c0 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 21 Apr 2020 10:43:26 +0100 Subject: [PATCH 179/711] Backport 1.15's terminal rendering code (#412) This is a backport of 1.15's terminal rendering code with some further improvements. This duplicates a fair bit of code, and is much more efficient. I expect the work done in #409 will supersede this, but that's unlikely to make its way into the next release so it's worth getting this in for now. - Refactor a lot of common terminal code into `FixedWithFontRenderer`. This shouldn't change any behaviour, but makes a lot of our terminal renderers (printed pages, terminals, monitors) a lot cleaner. - Terminal rendering is done using a single mode/vertex format. Rather than drawing an untextured quad for the background colours, we use an entirely white piece of the terminal font. This allows us to batch draws together more elegantly. - Some minor optimisations: - Skip rendering `"\0"` and `" "` characters. These characters occur pretty often, especially on blank monitors and, as the font is empty here, it is safe to skip them. - Batch together adjacent background cells of the same colour. Again, most terminals will have large runs of the same colour, so this is a worthwhile optimisation. These optimisations do mean that terminal performance is no longer consistent as "noisy" terminals will have worse performance. This is annoying, but still worthwhile. - Switch monitor rendering over to use VBOs. We also add a config option to switch between rendering backends. By default we'll choose the best one compatible with your GPU, but there is a config option to switch between VBOS (reasonable performance) and display lists (bad). When benchmarking 30 full-sized monitors rendering a static image, this improves my FPS[^1] from 7 to 95. This is obviously an extreme case - monitor updates are still slow, and so more frequently updating screens will still be less than stellar. [^1]: My graphics card is an Intel HD Graphics 520. Obviously numbers will vary. --- .../dan200/computercraft/ComputerCraft.java | 2 + .../client/gui/FixedWidthFontRenderer.java | 359 +++++++++++------ .../client/gui/widgets/WidgetTerminal.java | 101 +---- .../client/render/ItemPocketRenderer.java | 67 +--- .../client/render/PrintoutRenderer.java | 15 +- .../render/TileEntityMonitorRenderer.java | 361 +++++++----------- .../dan200/computercraft/shared/Config.java | 11 +- .../peripheral/monitor/ClientMonitor.java | 86 +++-- .../peripheral/monitor/MonitorRenderer.java | 105 +++++ .../computercraft/shared/util/Palette.java | 4 +- .../assets/computercraft/lang/en_us.lang | 4 + .../textures/gui/term_background.png | Bin 123 -> 0 bytes .../computercraft/textures/gui/term_font.png | Bin 1245 -> 3904 bytes 13 files changed, 594 insertions(+), 521 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java delete mode 100644 src/main/resources/assets/computercraft/textures/gui/term_background.png diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 430208196..2f3e85b66 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -46,6 +46,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.ItemCable; import dan200.computercraft.shared.peripheral.modem.wireless.BlockAdvancedModem; import dan200.computercraft.shared.peripheral.modem.wireless.ItemAdvancedModem; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; @@ -135,6 +136,7 @@ public class ComputerCraft public static int modem_rangeDuringStorm = 64; public static int modem_highAltitudeRangeDuringStorm = 384; public static int maxNotesPerTick = 8; + public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; public static boolean turtlesNeedFuel = true; public static int turtleFuelLimit = 20000; diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 57760da3f..c214505d7 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -5,195 +5,324 @@ */ package dan200.computercraft.client.gui; +import dan200.computercraft.client.FrameInfo; +import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.TextBuffer; +import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; -import java.util.Arrays; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class FixedWidthFontRenderer { private static final ResourceLocation FONT = new ResourceLocation( "computercraft", "textures/gui/term_font.png" ); - public static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/term_background.png" ); + + /** + * Like {@link DefaultVertexFormats#POSITION_TEX_COLOR}, but flipped. This is backported from 1.15, hence the + * custom format. + */ + public static final VertexFormat POSITION_COLOR_TEX = new VertexFormat(); + + static + { + POSITION_COLOR_TEX.addElement( DefaultVertexFormats.POSITION_3F ); + POSITION_COLOR_TEX.addElement( DefaultVertexFormats.COLOR_4UB ); + POSITION_COLOR_TEX.addElement( DefaultVertexFormats.TEX_2F ); + } public static final int FONT_HEIGHT = 9; public static final int FONT_WIDTH = 6; + public static final float WIDTH = 256.0f; - private static FixedWidthFontRenderer instance; - - public static FixedWidthFontRenderer instance() - { - if( instance != null ) return instance; - return instance = new FixedWidthFontRenderer(); - } - - private final TextureManager m_textureManager; + public static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH; + public static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH; private FixedWidthFontRenderer() { - m_textureManager = Minecraft.getMinecraft().getTextureManager(); } - private static void greyscaleify( double[] rgb ) + private static float toGreyscale( double[] rgb ) { - Arrays.fill( rgb, (rgb[0] + rgb[1] + rgb[2]) / 3.0f ); + return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); } - private void drawChar( BufferBuilder renderer, double x, double y, int index, int color, Palette p, boolean greyscale ) + private static int getColour( char c ) { + int i = "0123456789abcdef".indexOf( c ); + return i < 0 ? 0 : 15 - i; + } + + private static void drawChar( BufferBuilder buffer, float x, float y, int index, float r, float g, float b ) + { + // Short circuit to avoid the common case - the texture should be blank here after all. + if( index == '\0' || index == ' ' ) return; + int column = index % 16; int row = index / 16; - double[] colour = p.getColour( 15 - color ); - if( greyscale ) - { - greyscaleify( colour ); - } - float r = (float) colour[0]; - float g = (float) colour[1]; - float b = (float) colour[2]; - int xStart = 1 + column * (FONT_WIDTH + 2); int yStart = 1 + row * (FONT_HEIGHT + 2); - renderer.pos( x, y, 0.0 ).tex( xStart / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( xStart / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + FONT_WIDTH, y, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, yStart / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).tex( xStart / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + FONT_WIDTH, y + FONT_HEIGHT, 0.0 ).tex( (xStart + FONT_WIDTH) / 256.0, (yStart + FONT_HEIGHT) / 256.0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( x, y, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, yStart / WIDTH ).endVertex(); + buffer.pos( x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); + buffer.pos( x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex(); + buffer.pos( x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex(); + buffer.pos( x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); + buffer.pos( x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex(); } - private void drawQuad( BufferBuilder renderer, double x, double y, int color, double width, Palette p, boolean greyscale ) + private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, float r, float g, float b ) { - double[] colour = p.getColour( 15 - color ); + buffer.pos( x, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_START ).endVertex(); + buffer.pos( x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex(); + buffer.pos( x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex(); + buffer.pos( x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex(); + buffer.pos( x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex(); + buffer.pos( x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_END ).endVertex(); + } + + private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) + { + double[] colour = palette.getColour( getColour( colourIndex ) ); + float r, g, b; if( greyscale ) { - greyscaleify( colour ); + r = g = b = toGreyscale( colour ); + } + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; } - float r = (float) colour[0]; - float g = (float) colour[1]; - float b = (float) colour[2]; - renderer.pos( x, y, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + width, y, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + width, y, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( x + width, y + FONT_HEIGHT, 0.0 ).color( r, g, b, 1.0f ).endVertex(); + drawQuad( buffer, x, y, width, height, r, g, b ); } - private boolean isGreyScale( int colour ) + private static void drawBackground( + @Nonnull BufferBuilder renderer, float x, float y, + @Nonnull TextBuffer backgroundColour, @Nonnull Palette palette, boolean greyscale, + float leftMarginSize, float rightMarginSize, float height + ) { - return colour == 0 || colour == 15 || colour == 7 || colour == 8; - } + if( leftMarginSize > 0 ) + { + drawQuad( renderer, x - leftMarginSize, y, leftMarginSize, height, palette, greyscale, backgroundColour.charAt( 0 ) ); + } - public void drawStringBackgroundPart( int x, int y, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale, Palette p ) - { - // Draw the quads - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder renderer = tessellator.getBuffer(); - renderer.begin( GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_COLOR ); - if( leftMarginSize > 0.0 ) + if( rightMarginSize > 0 ) { - int colour1 = "0123456789abcdef".indexOf( backgroundColour.charAt( 0 ) ); - if( colour1 < 0 || (greyScale && !isGreyScale( colour1 )) ) - { - colour1 = 15; - } - drawQuad( renderer, x - leftMarginSize, y, colour1, leftMarginSize, p, greyScale ); - } - if( rightMarginSize > 0.0 ) - { - int colour2 = "0123456789abcdef".indexOf( backgroundColour.charAt( backgroundColour.length() - 1 ) ); - if( colour2 < 0 || (greyScale && !isGreyScale( colour2 )) ) - { - colour2 = 15; - } - drawQuad( renderer, x + backgroundColour.length() * FONT_WIDTH, y, colour2, rightMarginSize, p, greyScale ); + drawQuad( renderer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, greyscale, backgroundColour.charAt( backgroundColour.length() - 1 ) ); } + + // Batch together runs of identical background cells. + int blockStart = 0; + char blockColour = '\0'; for( int i = 0; i < backgroundColour.length(); i++ ) { - int colour = "0123456789abcdef".indexOf( backgroundColour.charAt( i ) ); - if( colour < 0 || (greyScale && !isGreyScale( colour )) ) + char colourIndex = backgroundColour.charAt( i ); + if( colourIndex == blockColour ) continue; + + if( blockColour != '\0' ) { - colour = 15; + drawQuad( renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, greyscale, blockColour ); } - drawQuad( renderer, x + i * FONT_WIDTH, y, colour, FONT_WIDTH, p, greyScale ); + + blockColour = colourIndex; + blockStart = i; + } + + if( blockColour != '\0' ) + { + drawQuad( renderer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, greyscale, blockColour ); } - GlStateManager.disableTexture2D(); - tessellator.draw(); - GlStateManager.enableTexture2D(); } - public void drawStringTextPart( int x, int y, TextBuffer s, TextBuffer textColour, boolean greyScale, Palette p ) + public static void drawString( + @Nonnull BufferBuilder renderer, float x, float y, + @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, + @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize + ) { - // Draw the quads - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder renderer = tessellator.getBuffer(); - renderer.begin( GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION_TEX_COLOR ); - for( int i = 0; i < s.length(); i++ ) + if( backgroundColour != null ) { - // Switch colour - int colour = "0123456789abcdef".indexOf( textColour.charAt( i ) ); - if( colour < 0 || (greyScale && !isGreyScale( colour )) ) + drawBackground( renderer, x, y, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize, FONT_HEIGHT ); + } + + for( int i = 0; i < text.length(); i++ ) + { + double[] colour = palette.getColour( getColour( textColour.charAt( i ) ) ); + float r, g, b; + if( greyscale ) { - colour = 0; + r = g = b = toGreyscale( colour ); + } + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; } // Draw char - int index = s.charAt( i ); - if( index < 0 || index > 255 ) - { - index = '?'; - } - drawChar( renderer, x + i * FONT_WIDTH, y, index, colour, p, greyScale ); + int index = text.charAt( i ); + if( index > 255 ) index = '?'; + drawChar( renderer, x + i * FONT_WIDTH, y, index, r, g, b ); } + + } + + public static void drawString( + float x, float y, @Nonnull TextBuffer text, @Nonnull TextBuffer textColour, @Nullable TextBuffer backgroundColour, + @Nonnull Palette palette, boolean greyscale, float leftMarginSize, float rightMarginSize + ) + { + bindFont(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + begin( buffer ); + drawString( buffer, x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize ); tessellator.draw(); } - public void drawString( TextBuffer s, int x, int y, TextBuffer textColour, TextBuffer backgroundColour, double leftMarginSize, double rightMarginSize, boolean greyScale, Palette p ) + public static void drawTerminalWithoutCursor( + @Nonnull BufferBuilder buffer, float x, float y, + @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) { - // Draw background - if( backgroundColour != null ) + Palette palette = terminal.getPalette(); + int height = terminal.getHeight(); + + // Top and bottom margins + drawBackground( + buffer, x, y - topMarginSize, + terminal.getBackgroundColourLine( 0 ), palette, greyscale, + leftMarginSize, rightMarginSize, topMarginSize + ); + + drawBackground( + buffer, x, y + height * FONT_HEIGHT, + terminal.getBackgroundColourLine( height - 1 ), palette, greyscale, + leftMarginSize, rightMarginSize, bottomMarginSize + ); + + // The main text + for( int i = 0; i < height; i++ ) { - // Bind the background texture - m_textureManager.bindTexture( BACKGROUND ); - - // Draw the quads - drawStringBackgroundPart( x, y, backgroundColour, leftMarginSize, rightMarginSize, greyScale, p ); - } - - // Draw text - if( s != null && textColour != null ) - { - // Bind the font texture - bindFont(); - - // Draw the quads - drawStringTextPart( x, y, s, textColour, greyScale, p ); + drawString( + buffer, x, y + FixedWidthFontRenderer.FONT_HEIGHT * i, + terminal.getLine( i ), terminal.getTextColourLine( i ), terminal.getBackgroundColourLine( i ), + palette, greyscale, leftMarginSize, rightMarginSize + ); } } - public int getStringWidth( String s ) + public static void drawCursor( + @Nonnull BufferBuilder buffer, float x, float y, + @Nonnull Terminal terminal, boolean greyscale + ) { - if( s == null ) + Palette palette = terminal.getPalette(); + int width = terminal.getWidth(); + int height = terminal.getHeight(); + + int cursorX = terminal.getCursorX(); + int cursorY = terminal.getCursorY(); + if( terminal.getCursorBlink() && cursorX >= 0 && cursorX < width && cursorY >= 0 && cursorY < height && FrameInfo.getGlobalCursorBlink() ) { - return 0; + double[] colour = palette.getColour( 15 - terminal.getTextColour() ); + float r, g, b; + if( greyscale ) + { + r = g = b = toGreyscale( colour ); + } + else + { + r = (float) colour[0]; + g = (float) colour[1]; + b = (float) colour[2]; + } + + drawChar( buffer, x + cursorX * FONT_WIDTH, y + cursorY * FONT_HEIGHT, '_', r, g, b ); } - return s.length() * FONT_WIDTH; } - public void bindFont() + public static void drawTerminal( + @Nonnull BufferBuilder buffer, float x, float y, + @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) { - m_textureManager.bindTexture( FONT ); + drawTerminalWithoutCursor( buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + drawCursor( buffer, x, y, terminal, greyscale ); + } + + public static void drawTerminal( + float x, float y, @Nonnull Terminal terminal, boolean greyscale, + float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize + ) + { + bindFont(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + begin( buffer ); + drawTerminal( buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize ); + tessellator.draw(); + } + + public static void drawEmptyTerminal( float x, float y, float width, float height ) + { + bindFont(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + begin( buffer ); + + Colour colour = Colour.Black; + drawQuad( buffer, x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); + + tessellator.draw(); + } + + public static void drawBlocker( @Nonnull BufferBuilder buffer, float x, float y, float width, float height ) + { + Colour colour = Colour.Black; + drawQuad( buffer, x, y, width, height, colour.getR(), colour.getG(), colour.getB() ); + } + + public static void drawBlocker( float x, float y, float width, float height ) + { + bindFont(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + begin( buffer ); + drawBlocker( buffer, x, y, width, height ); + tessellator.draw(); + } + + public static void bindFont() + { + Minecraft.getMinecraft().getTextureManager().bindTexture( FONT ); GlStateManager.glTexParameteri( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); + + GlStateManager.enableTexture2D(); + } + + public static void begin( BufferBuilder buffer ) + { + buffer.begin( GL11.GL_TRIANGLES, POSITION_COLOR_TEX ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 87d5e2f80..691f632ea 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -5,25 +5,18 @@ */ package dan200.computercraft.client.gui.widgets; -import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IComputerContainer; -import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.util.ChatAllowedCharacters; import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import java.util.ArrayList; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.BACKGROUND; - public class WidgetTerminal extends Widget { private static final float TERMINATE_TIME = 0.5f; @@ -41,10 +34,10 @@ public class WidgetTerminal extends Widget private boolean m_focus = false; private boolean m_allowFocusLoss = true; - private int m_leftMargin; - private int m_rightMargin; - private int m_topMargin; - private int m_bottomMargin; + private final int leftMargin; + private final int rightMargin; + private final int topMargin; + private final int bottomMargin; private final ArrayList m_keysDown = new ArrayList<>(); @@ -58,10 +51,10 @@ public class WidgetTerminal extends Widget m_computer = computer; - m_leftMargin = leftMargin; - m_rightMargin = rightMargin; - m_topMargin = topMargin; - m_bottomMargin = bottomMargin; + this.leftMargin = leftMargin; + this.rightMargin = rightMargin; + this.topMargin = topMargin; + this.bottomMargin = bottomMargin; } public void setAllowFocusLoss( boolean allowFocusLoss ) @@ -166,8 +159,8 @@ public class WidgetTerminal extends Widget Terminal term = computer.getTerminal(); if( term != null ) { - int charX = (mouseX - (getXPosition() + m_leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH; - int charY = (mouseY - (getYPosition() + m_topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT; + int charX = (mouseX - (getXPosition() + leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH; + int charY = (mouseY - (getYPosition() + topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT; charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); @@ -223,8 +216,8 @@ public class WidgetTerminal extends Widget Terminal term = computer.getTerminal(); if( term != null ) { - int charX = (mouseX - (getXPosition() + m_leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH; - int charY = (mouseY - (getYPosition() + m_topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT; + int charX = (mouseX - (getXPosition() + leftMargin)) / FixedWidthFontRenderer.FONT_WIDTH; + int charY = (mouseY - (getYPosition() + topMargin)) / FixedWidthFontRenderer.FONT_HEIGHT; charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); @@ -339,74 +332,14 @@ public class WidgetTerminal extends Widget Terminal terminal = computer != null ? computer.getTerminal() : null; if( terminal != null ) { - // Draw the terminal - boolean greyscale = !computer.isColour(); - - Palette palette = terminal.getPalette(); - - // Get the data from the terminal first - // Unfortunately we have to keep the lock for the whole of drawing, so the text doesn't change under us. - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - boolean tblink = m_focus && terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink(); - int tw = terminal.getWidth(); - int th = terminal.getHeight(); - int tx = terminal.getCursorX(); - int ty = terminal.getCursorY(); - - int x = startX + m_leftMargin; - int y = startY + m_topMargin; - - // Draw margins - TextBuffer emptyLine = new TextBuffer( ' ', tw ); - if( m_topMargin > 0 ) - { - fontRenderer.drawString( emptyLine, x, startY, terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), m_leftMargin, m_rightMargin, greyscale, palette ); - } - if( m_bottomMargin > 0 ) - { - fontRenderer.drawString( emptyLine, x, startY + 2 * m_bottomMargin + (th - 1) * FixedWidthFontRenderer.FONT_HEIGHT, terminal.getTextColourLine( th - 1 ), terminal.getBackgroundColourLine( th - 1 ), m_leftMargin, m_rightMargin, greyscale, palette ); - } - - // Draw lines - for( int line = 0; line < th; line++ ) - { - TextBuffer text = terminal.getLine( line ); - TextBuffer colour = terminal.getTextColourLine( line ); - TextBuffer backgroundColour = terminal.getBackgroundColourLine( line ); - fontRenderer.drawString( text, x, y, colour, backgroundColour, m_leftMargin, m_rightMargin, greyscale, palette ); - y += FixedWidthFontRenderer.FONT_HEIGHT; - } - - if( tblink && tx >= 0 && ty >= 0 && tx < tw && ty < th ) - { - TextBuffer cursor = new TextBuffer( '_', 1 ); - TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); - - fontRenderer.drawString( - cursor, - x + FixedWidthFontRenderer.FONT_WIDTH * tx, - startY + m_topMargin + FixedWidthFontRenderer.FONT_HEIGHT * ty, - cursorColour, null, - 0, 0, - greyscale, - palette - ); - } + FixedWidthFontRenderer.drawTerminal( + startX + topMargin, startY + bottomMargin, + terminal, !computer.isColour(), topMargin, bottomMargin, leftMargin, rightMargin + ); } else { - // Draw a black background - mc.getTextureManager().bindTexture( BACKGROUND ); - Colour black = Colour.Black; - GlStateManager.color( black.getR(), black.getG(), black.getB(), 1.0f ); - try - { - drawTexturedModalRect( startX, startY, 0, 0, getWidth(), getHeight() ); - } - finally - { - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); - } + FixedWidthFontRenderer.drawEmptyTerminal( startX, startY, getWidth(), getHeight() ); } } } diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 300c65b6a..c01ef3f01 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -6,15 +6,12 @@ package dan200.computercraft.client.render; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; @@ -27,7 +24,8 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.relauncher.Side; import org.lwjgl.opengl.GL11; -import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; import static dan200.computercraft.client.gui.GuiComputer.*; /** @@ -104,21 +102,11 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer if( computer != null && terminal != null ) { - // If we've a computer and terminal then attempt to render it. - renderTerminal( terminal, !computer.isColour(), width, height ); + FixedWidthFontRenderer.drawTerminal( MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); } else { - // Otherwise render a plain background - Minecraft.getMinecraft().getTextureManager().bindTexture( BACKGROUND ); - - Tessellator tessellator = Tessellator.getInstance(); - BufferBuilder buffer = tessellator.getBuffer(); - - Colour black = Colour.Black; - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION ); - renderTexture( buffer, 0, 0, 0, 0, width, height, black.getR(), black.getG(), black.getB() ); - tessellator.draw(); + FixedWidthFontRenderer.drawEmptyTerminal( 0, 0, width, height ); } GlStateManager.enableDepth(); @@ -189,53 +177,6 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer GlStateManager.enableTexture2D(); } - private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height ) - { - synchronized( terminal ) - { - int termWidth = terminal.getWidth(); - int termHeight = terminal.getHeight(); - - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - Palette palette = terminal.getPalette(); - - // Render top/bottom borders - TextBuffer emptyLine = new TextBuffer( ' ', termWidth ); - fontRenderer.drawString( - emptyLine, MARGIN, 0, - terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), MARGIN, MARGIN, greyscale, palette - ); - fontRenderer.drawString( - emptyLine, MARGIN, 2 * MARGIN + (termHeight - 1) * FixedWidthFontRenderer.FONT_HEIGHT, - terminal.getTextColourLine( termHeight - 1 ), terminal.getBackgroundColourLine( termHeight - 1 ), MARGIN, MARGIN, greyscale, palette - ); - - // Render the actual text - for( int line = 0; line < termWidth; line++ ) - { - TextBuffer text = terminal.getLine( line ); - TextBuffer colour = terminal.getTextColourLine( line ); - TextBuffer backgroundColour = terminal.getBackgroundColourLine( line ); - fontRenderer.drawString( - text, MARGIN, MARGIN + line * FONT_HEIGHT, - colour, backgroundColour, MARGIN, MARGIN, greyscale, palette - ); - } - - // And render the cursor; - int tx = terminal.getCursorX(), ty = terminal.getCursorY(); - if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() && - tx >= 0 && ty >= 0 && tx < termWidth && ty < termHeight ) - { - TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); - fontRenderer.drawString( - new TextBuffer( '_', 1 ), MARGIN + FONT_WIDTH * tx, MARGIN + FONT_HEIGHT * ty, - cursorColour, null, 0, 0, greyscale, palette - ); - } - } - } - private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) { renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b ); diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index be07d5039..f068e9b0a 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -63,11 +63,12 @@ public final class PrintoutRenderer public static void drawText( int x, int y, int start, TextBuffer[] text, TextBuffer[] colours ) { - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) { - fontRenderer.drawString( text[start + line], x, y + line * FONT_HEIGHT, colours[start + line], null, 0, 0, false, Palette.DEFAULT ); + FixedWidthFontRenderer.drawString( + x, y + line * FONT_HEIGHT, text[start + line], colours[start + line], null, Palette.DEFAULT, + false, 0, 0 + ); } } @@ -78,11 +79,13 @@ public final class PrintoutRenderer GlStateManager.enableTexture2D(); GlStateManager.tryBlendFuncSeparate( SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA, SourceFactor.ONE, DestFactor.ZERO ); - FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance(); - for( int line = 0; line < LINES_PER_PAGE && line < text.length; line++ ) { - fontRenderer.drawString( new TextBuffer( text[start + line] ), x, y + line * FONT_HEIGHT, new TextBuffer( colours[start + line] ), null, 0, 0, false, Palette.DEFAULT ); + FixedWidthFontRenderer.drawString( + x, y + line * FONT_HEIGHT, + new TextBuffer( text[start + line] ), new TextBuffer( colours[start + line] ), + null, Palette.DEFAULT, false, 0, 0 + ); } } diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 96646ff4c..db7f7b785 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -8,32 +8,33 @@ package dan200.computercraft.client.render; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import org.lwjgl.opengl.GL11; +import javax.annotation.Nonnull; + +import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN; + public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer { + private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1); + @Override - public void render( TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i, float f2 ) + public void render( @Nonnull TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i, float f2 ) { - if( tileEntity != null ) - { - renderMonitorAt( tileEntity, posX, posY, posZ, f, i ); - } + renderMonitorAt( tileEntity, posX, posY, posZ, f, i ); } private static void renderMonitorAt( TileMonitor monitor, double posX, double posY, double posZ, float f, int i ) @@ -69,223 +70,141 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer= 0 && cursorX < width && cursorY >= 0 && cursorY < height ) - { - TextBuffer cursor = new TextBuffer( "_" ); - TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 ); - fontRenderer.drawString( - cursor, - FixedWidthFontRenderer.FONT_WIDTH * cursorX, - FixedWidthFontRenderer.FONT_HEIGHT * cursorY, - cursorColour, null, - 0, 0, - greyscale, - palette - ); - } - } - finally - { - GlStateManager.glEndList(); - } - } - if( FrameInfo.getGlobalCursorBlink() ) - { - GlStateManager.callList( originTerminal.renderDisplayLists[2] ); - GlStateManager.resetColor(); - } - } - finally - { - GlStateManager.popMatrix(); - } - } - else - { - // Draw a big black quad - mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND ); - final Colour colour = Colour.Black; - - final float r = colour.getR(); - final float g = colour.getG(); - final float b = colour.getB(); - - renderer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION_TEX_COLOR ); - renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 0.0, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 0.0, 1.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0D ).tex( 1.0, 0.0 ).color( r, g, b, 1.0f ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).tex( 1.0, 1.0 ).color( r, g, b, 1.0f ).endVertex(); - tessellator.draw(); - } - } - finally - { - GlStateManager.depthMask( true ); - mc.entityRenderer.enableLightmap(); - GlStateManager.enableLighting(); - } - - // Draw the depth blocker - GlStateManager.colorMask( false, false, false, false ); - try - { - mc.getTextureManager().bindTexture( FixedWidthFontRenderer.BACKGROUND ); - renderer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION ); - renderer.pos( -TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - renderer.pos( -TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - renderer.pos( xSize + TileMonitor.RENDER_MARGIN, -ySize - TileMonitor.RENDER_MARGIN, 0.0 ).endVertex(); - tessellator.draw(); - } - finally - { - GlStateManager.colorMask( true, true, true, true ); - } - } - finally - { - GlStateManager.color( 1.0f, 1.0f, 1.0f, 1.0f ); GlStateManager.popMatrix(); } + else + { + FixedWidthFontRenderer.drawEmptyTerminal( + -MARGIN, MARGIN, + (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) + ); + } + + // Tear down render state for monitors. + GlStateManager.depthMask( true ); + mc.entityRenderer.enableLightmap(); + GlStateManager.enableLighting(); + + // Draw the depth blocker + GlStateManager.colorMask( false, false, false, false ); + FixedWidthFontRenderer.drawBlocker( + (float) -TileMonitor.RENDER_MARGIN, (float) TileMonitor.RENDER_MARGIN, + (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) + ); + GlStateManager.colorMask( true, true, true, true ); + + GlStateManager.popMatrix(); + } + + private static void renderTerminal( ClientMonitor monitor, float xMargin, float yMargin ) + { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + + boolean redraw = monitor.pollTerminalChanged(); + + // Setup the buffers if needed. We get the renderer here, to avoid the (unlikely) race condition between + // creating the buffers and rendering. + MonitorRenderer renderer = MonitorRenderer.current(); + if( monitor.createBuffer( renderer ) ) redraw = true; + + FixedWidthFontRenderer.bindFont(); + + switch( renderer ) + { + case VBO: + { + VertexBuffer vbo = monitor.buffer; + if( redraw ) + { + renderTerminalTo( monitor, buffer, xMargin, yMargin ); + buffer.finishDrawing(); + buffer.reset(); + vbo.bufferData( buffer.getByteBuffer() ); + } + + vbo.bindBuffer(); + setupBufferFormat(); + vbo.drawArrays( GL11.GL_TRIANGLES ); + vbo.unbindBuffer(); + + break; + } + + case DISPLAY_LIST: + if( redraw ) + { + GlStateManager.glNewList( monitor.displayList, GL11.GL_COMPILE ); + renderTerminalTo( monitor, buffer, xMargin, yMargin ); + tessellator.draw(); + GlStateManager.glEndList(); + } + + GlStateManager.callList( monitor.displayList ); + break; + } + + // We don't draw the cursor with a buffer, as it's dynamic and so we'll end up refreshing far more than is + // reasonable. + FixedWidthFontRenderer.begin( buffer ); + FixedWidthFontRenderer.drawCursor( buffer, 0, 0, monitor.getTerminal(), !monitor.isColour() ); + tessellator.draw(); + } + + private static void renderTerminalTo( ClientMonitor monitor, BufferBuilder buffer, float xMargin, float yMargin ) + { + FixedWidthFontRenderer.begin( buffer ); + FixedWidthFontRenderer.drawTerminalWithoutCursor( + buffer, 0, 0, + monitor.getTerminal(), !monitor.isColour(), yMargin, yMargin, xMargin, xMargin + ); + } + + public static void setupBufferFormat() + { + int stride = FixedWidthFontRenderer.POSITION_COLOR_TEX.getSize(); + GlStateManager.glVertexPointer( 3, GL11.GL_FLOAT, stride, 0 ); + GlStateManager.glEnableClientState( GL11.GL_VERTEX_ARRAY ); + + GlStateManager.glColorPointer( 4, GL11.GL_UNSIGNED_BYTE, stride, 12 ); + GlStateManager.glEnableClientState( GL11.GL_COLOR_ARRAY ); + + GlStateManager.glTexCoordPointer( 2, GL11.GL_FLOAT, stride, 16 ); + GlStateManager.glEnableClientState( GL11.GL_TEXTURE_COORD_ARRAY ); } } diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 65819e69e..92f2b75c3 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -11,6 +11,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.AddressPredicate; import dan200.computercraft.core.apis.http.websocket.Websocket; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import net.minecraftforge.common.config.ConfigCategory; import net.minecraftforge.common.config.ConfigElement; import net.minecraftforge.common.config.Configuration; @@ -69,6 +70,7 @@ public final class Config private static Property modemRangeDuringStorm; private static Property modemHighAltitudeRangeDuringStorm; private static Property maxNotesPerTick; + private static Property monitorRenderer; private static Property turtlesNeedFuel; private static Property turtleFuelLimit; @@ -264,9 +266,15 @@ public final class Config maxNotesPerTick.setComment( "Maximum amount of notes a speaker can play at once" ); maxNotesPerTick.setMinValue( 1 ); + monitorRenderer = config.get( CATEGORY_PERIPHERAL, "monitor_renderer", ComputerCraft.monitorRenderer.displayName() ); + monitorRenderer.setComment( "The renderer to use for monitors. Generally this should be kept at \"best\" - if " + + "monitors have performance issues, you may wish to experiment with alternative renderers." ); + monitorRenderer.setValidValues( MonitorRenderer.NAMES ); + setOrder( CATEGORY_PERIPHERAL, - commandBlockEnabled, modemRange, modemHighAltitudeRange, modemRangeDuringStorm, modemHighAltitudeRangeDuringStorm, maxNotesPerTick + commandBlockEnabled, modemRange, modemHighAltitudeRange, modemRangeDuringStorm, modemHighAltitudeRangeDuringStorm, maxNotesPerTick, + monitorRenderer ); } @@ -459,6 +467,7 @@ public final class Config ComputerCraft.modem_highAltitudeRange = Math.min( modemHighAltitudeRange.getInt(), MODEM_MAX_RANGE ); ComputerCraft.modem_rangeDuringStorm = Math.min( modemRangeDuringStorm.getInt(), MODEM_MAX_RANGE ); ComputerCraft.modem_highAltitudeRangeDuringStorm = Math.min( modemHighAltitudeRangeDuringStorm.getInt(), MODEM_MAX_RANGE ); + ComputerCraft.monitorRenderer = MonitorRenderer.ofString( monitorRenderer.getString() ); // Turtles ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.getBoolean(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index c3ccc3dae..2bcd45181 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -5,8 +5,10 @@ */ package dan200.computercraft.shared.peripheral.monitor; +import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.shared.common.ClientTerminal; -import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.math.BlockPos; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; @@ -15,7 +17,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; -public class ClientMonitor extends ClientTerminal +public final class ClientMonitor extends ClientTerminal { private static final Set allMonitors = new HashSet<>(); @@ -23,7 +25,9 @@ public class ClientMonitor extends ClientTerminal public long lastRenderFrame = -1; public BlockPos lastRenderPos = null; - public int[] renderDisplayLists = null; + + public VertexBuffer buffer; + public int displayList = 0; public ClientMonitor( boolean colour, TileMonitor origin ) { @@ -36,41 +40,72 @@ public class ClientMonitor extends ClientTerminal return origin; } + /** + * Create the appropriate buffer if needed. + * + * @param renderer The renderer to use. This can be fetched from {@link #renderer()}. + * @return If a buffer was created. This will return {@code false} if we already have an appropriate buffer, + * or this mode does not require one. + */ @SideOnly( Side.CLIENT ) - public void createLists() + public boolean createBuffer( MonitorRenderer renderer ) { - if( renderDisplayLists == null ) + switch( renderer ) { - renderDisplayLists = new int[3]; + case VBO: + if( buffer != null ) return false; - for( int i = 0; i < renderDisplayLists.length; i++ ) - { - renderDisplayLists[i] = GlStateManager.glGenLists( 1 ); - } + deleteBuffers(); + buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX ); + addMonitor(); + return true; + case DISPLAY_LIST: + if( displayList != 0 ) return false; - synchronized( allMonitors ) - { - allMonitors.add( this ); - } + deleteBuffers(); + displayList = GLAllocation.generateDisplayLists( 1 ); + addMonitor(); + return true; + + default: + return false; + } + } + + private void addMonitor() + { + synchronized( allMonitors ) + { + allMonitors.add( this ); + } + } + + private void deleteBuffers() + { + if( buffer != null ) + { + buffer.deleteGlBuffers(); + buffer = null; + } + + if( displayList != 0 ) + { + GLAllocation.deleteDisplayLists( displayList ); + displayList = 0; } } @SideOnly( Side.CLIENT ) public void destroy() { - if( renderDisplayLists != null ) + if( buffer != null || displayList != 0 ) { synchronized( allMonitors ) { allMonitors.remove( this ); } - for( int list : renderDisplayLists ) - { - GlStateManager.glDeleteLists( list, 1 ); - } - - renderDisplayLists = null; + deleteBuffers(); } } @@ -82,14 +117,7 @@ public class ClientMonitor extends ClientTerminal for( Iterator iterator = allMonitors.iterator(); iterator.hasNext(); ) { ClientMonitor monitor = iterator.next(); - if( monitor.renderDisplayLists != null ) - { - for( int list : monitor.renderDisplayLists ) - { - GlStateManager.glDeleteLists( list, 1 ); - } - monitor.renderDisplayLists = null; - } + monitor.deleteBuffers(); iterator.remove(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java new file mode 100644 index 000000000..c60ea91ed --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java @@ -0,0 +1,105 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.monitor; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.render.TileEntityMonitorRenderer; +import net.minecraft.client.renderer.OpenGlHelper; + +import javax.annotation.Nonnull; +import java.util.Locale; + +/** + * The render type to use for monitors. + * + * @see TileEntityMonitorRenderer + * @see ClientMonitor + */ +public enum MonitorRenderer +{ + /** + * Determine the best monitor backend. + */ + BEST, + + /** + * Render using VBOs. This is the default when supported. + * + * @see net.minecraft.client.renderer.vertex.VertexBuffer + */ + VBO, + + /** + * Render using display lists. + * + * @see net.minecraft.client.renderer.GLAllocation#generateDisplayLists(int) + */ + DISPLAY_LIST; + + private static final MonitorRenderer[] VALUES = values(); + public static final String[] NAMES; + + private final String displayName = "gui.computercraft:config.peripheral.monitor_renderer." + name().toLowerCase( Locale.ROOT ); + + static + { + NAMES = new String[VALUES.length]; + for( int i = 0; i < VALUES.length; i++ ) NAMES[i] = VALUES[i].displayName(); + } + + public String displayName() + { + return displayName; + } + + @Nonnull + public static MonitorRenderer ofString( String name ) + { + for( MonitorRenderer backend : VALUES ) + { + if( backend.displayName.equalsIgnoreCase( name ) || backend.name().equalsIgnoreCase( name ) ) + { + return backend; + } + } + + ComputerCraft.log.warn( "Unknown monitor renderer {}. Falling back to default.", name ); + return BEST; + } + + /** + * Get the current renderer to use. + * + * @return The current renderer. Will not return {@link MonitorRenderer#BEST}. + */ + @Nonnull + public static MonitorRenderer current() + { + MonitorRenderer current = ComputerCraft.monitorRenderer; + switch( current ) + { + case BEST: + return best(); + case VBO: + if( !OpenGlHelper.vboSupported ) + { + ComputerCraft.log.warn( "VBOs are not supported on your graphics card. Falling back to default." ); + ComputerCraft.monitorRenderer = BEST; + return best(); + } + + return VBO; + default: + return current; + } + } + + private static MonitorRenderer best() + { + return OpenGlHelper.vboSupported ? VBO : DISPLAY_LIST; + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index 18c8040c2..e177940c2 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -48,13 +48,13 @@ public class Palette { if( i >= 0 && i < colours.length ) { - setColour( i, Colour.values()[i] ); + setColour( i, Colour.VALUES[i] ); } } public void resetColours() { - for( int i = 0; i < Colour.values().length; i++ ) + for( int i = 0; i < Colour.VALUES.length; i++ ) { resetColour( i ); } diff --git a/src/main/resources/assets/computercraft/lang/en_us.lang b/src/main/resources/assets/computercraft/lang/en_us.lang index 99cadd868..254fb0e21 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.lang +++ b/src/main/resources/assets/computercraft/lang/en_us.lang @@ -185,6 +185,10 @@ gui.computercraft:config.peripheral.modem_high_altitude_range=Modem range (high- gui.computercraft:config.peripheral.modem_range_during_storm=Modem range (bad weather) gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=Modem range (high-altitude, bad weather) gui.computercraft:config.peripheral.max_notes_per_tick=Maximum notes that a computer can play at once +gui.computercraft:config.peripheral.monitor_renderer=Monitor renderer +gui.computercraft:config.peripheral.monitor_renderer.best=Best +gui.computercraft:config.peripheral.monitor_renderer.vbo=Vertex Buffers +gui.computercraft:config.peripheral.monitor_renderer.display_list=Display Lists gui.computercraft:config.turtle=Turtles gui.computercraft:config.turtle.need_fuel=Enable fuel diff --git a/src/main/resources/assets/computercraft/textures/gui/term_background.png b/src/main/resources/assets/computercraft/textures/gui/term_background.png deleted file mode 100644 index 694d2b25b96a186fffedf045db42cc4fd488de4b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4kiW$h6xih%orFLI14-?iy0WWg+Z8+Vb&Z8 z1_lQ95>H=O_WL|c{Cs>yN@*z!3=C49E{-7@=ac{Z|8LK%+0fbOVz4SPDnIFfe$!`njxgN@xNAgMA!^ diff --git a/src/main/resources/assets/computercraft/textures/gui/term_font.png b/src/main/resources/assets/computercraft/textures/gui/term_font.png index ef7119bc2525bb67c86b7c11f1fbacc0f3ba2083..7bf23be2e751a8ba4dc8f408e56f0522198e6d2d 100644 GIT binary patch literal 3904 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4rT@hhU_&FAs}9Hkh>GZx^prw85kH?(j9#r z85lP9bN@+XWnf@t2=EDUWnf_V|NlS3C>RZa5g7vMWp9!}xuzt@FZln+1`NU9*;N@B z7&r?&B8wRq_zr;HW(TE$dTTWeaCAT#adW$m8#?wd7PFT_SA+r^)mamYpCz_aa& z4-&UETn=r&UOQzK!=w%Q*NprB9yQZ^m^|YeBll)jEBRY|OAP9n&RyXV-Msbngup)Y z!(YEHer@L++fa6R<9?;IfU^OH(YwVsD@86dSFL*M!M0f4;s4CWw}sQ$kD5g3O7X2$ z3cJerHh^s@!zStb=M)PIB+8GxRZ^Jt^0~Nd-1o>;Ogcuo4in}-HUG1Zfj?cG;a8L! z>jO>JZu^gi{pZH5?|*wlIs$N1BF3?Z8BGb5jV=-(H?#%s?l=GQVm{^R`Og$x#N zmK!*$2x3h`z4+lzO6 z5N^oGpLS*O{F6Us*uDFg^R4~oGtM99cX+N!whL^C-ptKVs~gl%aXYZ$)$x^SZTomF z9@zd7DwDmybKz&&KlYFNId1yRaKFAqe;Y&d#(f+0qj;8|dBtY5fhlCA^%kGfCa(M) zWd|O`Cf{Ej*U!P;HL+c+;eBbI`nSwgu{{~xHWiY8vKAx?xMW!TJ^UiRb?4;A+pb*M zBVi=J_T62rTSXm82J`+Vt}h-cOhW*p;t@U%dtI^u?Lslc7F>k`D9hZIxE_b=3 z@+frCQK3Vbiz5G=ecuqRQgQ5`K-0cyu?#;~J`&M>WPk5mcxdw}MzeF_uPmC|BTVfD z>v^+|_tsvYGI7^gk0UwF=$mTB{H7}B+~6I?cjg@3Qn_QrtasBn9BgvJ z|3A`+IwrJ|OCj$5l!^Yi$1Q{mxedBz9M!g#)^B*X;-1KCqfaZ}O1QfvAD4(WvS4nh zOJ2O}%B{Ys`|?j|tka$ONvz}9I>`wE=L{v>7vDerb<>8`VxNm|-e`edHEx`}MCt5#Pe=xH6&a2}$mKbx23Y05xt)5lRd`fu1T+@3i-}N1> zxPC)?ZtLAk>sl_&tmn{Nw^ZKrrOyM=rPc;{N6vFA#BwByIrwwRy1sJ`W-#8mI{NPH zqf8w}X^qRo4{@w^dFQOzkh-Ml+I+_Jbf+&|Jlq_6>yuWimh?!|cSxwN6d+(Py@>JO}sEbO^n{o~ayhtA94y+1=2*`4F~ zwTXv$-OerP4eva*r$)_sJ7w*=wVvU}MK@0f9dVQlZzcgeLaloH#6+fTW9WUrQN#f*U1<0EftG@ zEEL)&J!N(8^_k(>hBAe_J(z+R-Z&rK^5cN+v0rMkEOxAZsUg!8{2o7lP%r#u_Ce`R z58HRVGsA1&%5RnEvgn=PV#ipMbazF0YvYTvUDk1u%OXzLHXc)CIPzABGo)Tr?8>t9 zHCMjOV{Cc2Su^dpjbZGX<>DQ;U5zZn5~fc2Zu)NGei4QK=qU;HoKCaVBXS!~lV;NqE$5Dojd(x z3&Ve_-3;L5Vk?uyvQWOiSjcJl_4JM047PU@@`YRY9?xmH@bYWq8zzV41(S_Ke?_cK zf3e4>jB!Emj*~OBYS&ydE{RjC-_faaHcfoN{R_)YXU8(U$X>~P;r_&LVk;jrwmgn2 z6OY@ox$5WEne|gI3Ljv(n>2YHPX@of2Ip60-R~ZAc;+#@>)+k7{`WfeFUi+=6#Axj zTz>HFM(N^4nLgGHGFub{f4%YSw4N6FC)t68yVY(X0~^o%EhZ`fY`1J880JdYy?CCu z(AuD$>4Dh%#tUZr8`(t*cU9&pO#dkCLE|I=ssrOfi~vhFof z7PMuyS$w*yclX=E&+4x>@4Fl#Hjm-;Rfk2-&U`)9<1&rw!kwtSm&N91_{`7L+y9eq z$KikVXQ4%(^_n~1KJT@fb*IOf+x}MtFGG*~y2o3L_D8P&^L<&+J*JHpJtU-ipFK>z zbGvb0Kx6yz>$TH9Uw^Ph;nKzJjr%4h&v~72H|C3a!`VRnZI`N5&&?`PGf|r7{g)-i zyT#W^{N?K(Yc`6TE?ZMV?E+u6zG1rJF6gK3@?jSD+&@|8*FR^GQj|II9U95>p{5b=DYLVs!*y~f^ delta 1210 zcmX>gcb9X51Scai0|P_a9xK&}it_agoCO|{#S9F5he4R}c>anM1_lPn64!{5;QX|b z^2DN4hJwV*yb`^<)Di^~Jp(;MGndTuUl|w}*aCb)Tp1V`{{R2K^yd7#3=9m6B|(0{ z3=Yq3q%knC=y|$0hGg7(JHxR1iJM4^_6vu`gzn@fPQ8qtCO$FcGc5WUKE?GR1~S4t z?FNSv&#)XWJjf=^^*Q4I)4!~7>{iuhS8lDAd2^O6*uZB&|Mm5&S6`jfke^q9@E`D6I_s-2+mPzk+ z7_SaV*naE4%h&r#j(PF-h0gAE6RTJo`Z_FGjq}GLlg6Xj_NQKkF1oSBmO&w;agQ&r zw17h}=wVIzFFRIXz6(OG!GwIN`X!u8l06OUyqXmD&-f-P4<@pmgT?qazYF9b60- z&#V<#su0L~^NLgMJFznvwvqxrrRKVAyXf{^hg<8?omb_PLc9bIZ@V++Sy=s-jW52H zJ?Gh;DxuX764G^KgYK=fjrMYkqM3YCR_UV>RT(g_>X75RNyq=nI zdbUmq;xaT_8RWRQkgK+*H^5jcAV^7BT8A-HAUS8%fv`oFdLzUddVAbD^Bzj~*qyeW zt-+BIDDmod9#cnCYwyh)2hFB^Zd~~I`9`CQ1(*D;bSf6END+#3_3K=?o_SKp3|G}v zQHfjTNV=4s6<%2{H(hRX-JH7&4b%SW-wkHC`DWYZ?)I~ax3}n@V9S5D{n6dbTjE(t z%)7cK9@XF#Imz}}@mLJg)V3+fwH-pIZlt8K=HCo&(|C9>XMxd?@T$+UX7}R%_WoYo z{=e=y1H+yB_wUEY#>U#(*z6H0D6_5laD7ssKHr`_SHH)-9nUB z>nj{r-V*gVZ1wARyRPtauVskXRquD5d*0ujPRwt%u9ofQTVV4&AU5vGtK@7=!`mCT zURfWxQRo(PH6v5N&b+j=ZTj!trA_^w=Q-(EkeB9~TE>F%^848`$2W5Mh<@7^k;qh+ zFIN5I{-n9Sk6+!0^4gGm`pPYf`L0Hn@2My({I*TQGtJAI^U^N^WY&YW46x?FbN>{842tHG<5|5p#7ujt&&)AP@ro1L{x^Qy%*pIrOxn{G1SYMy+4YTV}^s)50) zwkAxe>3WtWctGUcQ!X3Npl5$>Y_1QUTYT=|A!BPbNoBoVFBWyfh|rhv@sAF$n16CU R#lXP8;OXk;vd$@?2>@eHEe-$x From 1fc02148576c1040481e4dd6951cfdc5f92d8214 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 21 Apr 2020 11:37:56 +0100 Subject: [PATCH 180/711] Some redesigning of the settings API (#408) - The store is now split into two sections: - A list of possible options, with some metadata about them. - A list of values which have been changed. - settings.define can be used to register a new option. We have migrated all existing options over to use it. This can be used to define a default value, description, and a type the setting must have (such as `string` or `boolean). - settings.{set,unset,clear,load,store} operate using this value list. This means that only values which have been changed are stored to disk. Furthermore, clearing/unsetting will reset to the /default/ value, rather than removing entirely. - The set program will now display descriptions. - settings.{load,save} now default to `.settings` if no path is given. --- .../assets/computercraft/lua/bios.lua | 70 ++++++-- .../computercraft/lua/rom/apis/settings.lua | 165 +++++++++++++----- .../computercraft/lua/rom/programs/set.lua | 26 ++- .../test-rom/spec/apis/settings_spec.lua | 135 +++++++++++++- .../test-rom/spec/programs/set_spec.lua | 56 ++++-- 5 files changed, 378 insertions(+), 74 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 39dd252c3..f1e80cef4 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -881,18 +881,66 @@ if bAPIError then end -- Set default settings -settings.set("shell.allow_startup", true) -settings.set("shell.allow_disk_startup", commands == nil) -settings.set("shell.autocomplete", true) -settings.set("edit.autocomplete", true) -settings.set("edit.default_extension", "lua") -settings.set("paint.default_extension", "nfp") -settings.set("lua.autocomplete", true) -settings.set("list.show_hidden", false) -settings.set("motd.enable", false) -settings.set("motd.path", "/rom/motd.txt:/motd.txt") +settings.define("shell.allow_startup", { + default = true, + description = "Run startup files when the computer turns on.", + type = "boolean", +}) +settings.define("shell.allow_disk_startup", { + default = commands == nil, + description = "Run startup files from disk drives when the computer turns on.", + type = "boolean", +}) + +settings.define("shell.autocomplete", { + default = true, + description = "Autocomplete program and arguments in the shell.", + type = "boolean", +}) +settings.define("edit.autocomplete", { + default = true, + description = "Autocomplete API and function names in the editor.", + type = "boolean", +}) +settings.define("lua.autocomplete", { + default = true, + description = "Autocomplete API and function names in the Lua REPL.", + type = "boolean", +}) + +settings.define("edit.default_extension", { + default = "lua", + description = [[The file extension the editor will use if none is given. Set to "" to disable.]], + type = "string", +}) +settings.define("paint.default_extension", { + default = "nfp", + description = [[The file extension the paint program will use if none is given. Set to "" to disable.]], + type = "string", +}) + +settings.define("list.show_hidden", { + default = false, + description = [[Show hidden files (those starting with "." in the Lua REPL)]], + type = "boolean", +}) + +settings.define("motd.enable", { + default = false, + description = "Display a random message when the computer starts up.", + type = "boolean", +}) +settings.define("motd.path", { + default = "/rom/motd.txt:/motd.txt", + description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]], + type = "string", +}) if term.isColour() then - settings.set("bios.use_multishell", true) + settings.define("bios.use_multishell", { + default = true, + description = [[Allow running multiple programs at once, through the use of the "fg" and "bg" programs.]], + type = "boolean", + }) end if _CC_DEFAULT_SETTINGS then for sPair in string.gmatch(_CC_DEFAULT_SETTINGS, "[^,]+") do diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 40044c1a0..fcfb1d17a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -6,9 +6,86 @@ -- -- @module settings -local expect = dofile("rom/modules/main/cc/expect.lua").expect +local expect = dofile("rom/modules/main/cc/expect.lua") +local type, expect, field = type, expect.expect, expect.field -local tSettings = {} +local details, values = {}, {} + +local function reserialize(value) + if type(value) ~= "table" then return value end + return textutils.unserialize(textutils.serialize(value)) +end + +local function copy(value) + if type(value) ~= "table" then return value end + local result = {} + for k, v in pairs(value) do result[k] = copy(v) end + return result +end + +local valid_types = { "number", "string", "boolean", "table" } +for _, v in ipairs(valid_types) do valid_types[v] = true end + +--- Define a new setting, optional specifying various properties about it. +-- +-- While settings do not have to be added before being used, doing so allows +-- you to provide defaults and additional metadata. +-- +-- @tparam string name The name of this option +-- @tparam[opt] { description? = string, default? = value, type? = string } options +-- Options for this setting. This table accepts the following fields: +-- +-- - `description`: A description which may be printed when running the `set` program. +-- - `default`: A default value, which is returned by @{settings.get} if the +-- setting has not been changed. +-- - `type`: Require values to be of this type. @{set|Setting} the value to another type +-- will error. +function define(name, options) + expect(1, name, "string") + expect(2, options, "table", nil) + + if options then + options = { + description = field(options, "description", "string", "nil"), + default = reserialize(field(options, "default", "number", "string", "boolean", "table", "nil")), + type = field(options, "type", "string", "nil"), + } + + if options.type and not valid_types[options.type] then + error(("Unknown type %q. Expected one of %s."):format(options.type, table.concat(valid_types, ", ")), 2) + end + else + options = {} + end + + details[name] = options +end + +--- Remove a @{define|definition} of a setting. +-- +-- If a setting has been changed, this does not remove its value. Use @{settings.unset} +-- for that. +-- +-- @tparam string name The name of this option +function undefine(name) + expect(1, name, "string") + details[name] = nil +end + +local function set_value(name, value) + local new = reserialize(value) + local old = values[name] + if old == nil then + local opt = details[name] + old = opt and opt.default + end + + values[name] = new + if old ~= new then + -- This should be safe, as os.queueEvent copies values anyway. + os.queueEvent("setting_changed", name, new, old) + end +end --- Set the value of a setting. -- @@ -21,43 +98,43 @@ function set(name, value) expect(1, name, "string") expect(2, value, "number", "string", "boolean", "table") - if type(value) == "table" then - -- Ensure value is serializeable - value = textutils.unserialize(textutils.serialize(value)) - end - tSettings[name] = value -end + local opt = details[name] + if opt and opt.type then expect(2, value, opt.type) end -local copy -function copy(value) - if type(value) == "table" then - local result = {} - for k, v in pairs(value) do - result[k] = copy(v) - end - return result - else - return value - end + set_value(name, value) end --- Get the value of a setting. -- -- @tparam string name The name of the setting to get. -- @param[opt] default The value to use should there be pre-existing value for --- this setting. Defaults to `nil`. --- @return The setting's, or `default` if the setting has not been set. +-- this setting. If not given, it will use the setting's default value if given, +-- or `nil` otherwise. +-- @return The setting's, or the default if the setting has not been changed. function get(name, default) expect(1, name, "string") - local result = tSettings[name] + local result = values[name] if result ~= nil then return copy(result) - else + elseif default ~= nil then return default + else + local opt = details[name] + return opt and copy(opt.default) end end ---- Remove the value of a setting, clearing it back to `nil`. +--- Get details about a specific setting +function getDetails(name) + expect(1, name, "string") + local deets = copy(details[name]) or {} + deets.value = values[name] + deets.changed = deets.value ~= nil + if deets.value == nil then deets.value = deets.default end + return deets +end + +--- Remove the value of a setting, setting it to the default. -- -- @{settings.get} will return the default value until the setting's value is -- @{settings.set|set}, or the computer is rebooted. @@ -67,15 +144,17 @@ end -- @see settings.clear function unset(name) expect(1, name, "string") - tSettings[name] = nil + set_value(name, nil) end ---- Removes the value of all settings. Equivalent to calling @{settings.unset} +--- Resets the value of all settings. Equivalent to calling @{settings.unset} --- on every setting. -- -- @see settings.unset function clear() - tSettings = {} + for name in pairs(values) do + set_value(name, nil) + end end --- Get the names of all currently defined settings. @@ -83,9 +162,12 @@ end -- @treturn { string } An alphabetically sorted list of all currently-defined -- settings. function getNames() - local result = {} - for k in pairs(tSettings) do - result[#result + 1] = k + local result, n = {}, 1 + for k in pairs(details) do + result[n], n = k, n + 1 + end + for k in pairs(values) do + if not details[k] then result[n], n = k, n + 1 end end table.sort(result) return result @@ -96,15 +178,15 @@ end -- Existing settings will be merged with any pre-existing ones. Conflicting -- entries will be overwritten, but any others will be preserved. -- --- @tparam string sPath The file to load from. +-- @tparam[opt] string sPath The file to load from, defaulting to `.settings`. -- @treturn boolean Whether settings were successfully read from this -- file. Reasons for failure may include the file not existing or being -- corrupted. -- -- @see settings.save function load(sPath) - expect(1, sPath, "string") - local file = fs.open(sPath, "r") + expect(1, sPath, "string", "nil") + local file = fs.open(sPath or ".settings", "r") if not file then return false end @@ -118,9 +200,12 @@ function load(sPath) end for k, v in pairs(tFile) do - if type(k) == "string" and - (type(v) == "string" or type(v) == "number" or type(v) == "boolean" or type(v) == "table") then - set(k, v) + local ty_v = type(k) + if type(k) == "string" and (ty_v == "string" or ty_v == "number" or ty_v == "boolean" or ty_v == "table") then + local opt = details[name] + if not opt or not opt.type or ty_v == opt.type then + set_value(k, v) + end end end @@ -132,18 +217,18 @@ end -- This will entirely overwrite the pre-existing file. Settings defined in the -- file, but not currently loaded will be removed. -- --- @tparam string sPath The path to save settings to. +-- @tparam[opt] string sPath The path to save settings to, defaulting to `.settings`. -- @treturn boolean If the settings were successfully saved. -- -- @see settings.load function save(sPath) - expect(1, sPath, "string") - local file = fs.open(sPath, "w") + expect(1, sPath, "string", "nil") + local file = fs.open(".settings", "w") if not file then return false end - file.write(textutils.serialize(tSettings)) + file.write(textutils.serialize(values)) file.close() return true diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua index a826d8ad6..01d4b246e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/set.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/set.lua @@ -1,3 +1,4 @@ +local pp = require "cc.pretty" local tArgs = { ... } if #tArgs == 0 then @@ -12,7 +13,13 @@ if #tArgs == 0 then elseif #tArgs == 1 then -- "set foo" local sName = tArgs[1] - print(textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName))) + local deets = settings.getDetails(sName) + local msg = pp.text(sName, colors.cyan) .. " is " .. pp.pretty(deets.value) + if deets.default ~= nil and deets.value ~= deets.default then + msg = msg .. " (default is " .. pp.pretty(deets.default) .. ")" + end + pp.print(msg) + if deets.description then print(deets.description) end else -- "set foo bar" @@ -31,15 +38,18 @@ else value = sValue end - local oldValue = settings.get(sValue) - if value ~= nil then - settings.set(sName, value) - print(textutils.serialize(sName) .. " set to " .. textutils.serialize(value)) - else + local option = settings.getDetails(sName) + if value == nil then settings.unset(sName) print(textutils.serialize(sName) .. " unset") + elseif option.type and option.type ~= type(value) then + printError(("%s is not a valid %s."):format(textutils.serialize(sValue), option.type)) + else + settings.set(sName, value) + print(textutils.serialize(sName) .. " set to " .. textutils.serialize(value)) end - if value ~= oldValue then - settings.save(".settings") + + if value ~= option.value then + settings.save() end end diff --git a/src/test/resources/test-rom/spec/apis/settings_spec.lua b/src/test/resources/test-rom/spec/apis/settings_spec.lua index b54e24e67..40af033d1 100644 --- a/src/test/resources/test-rom/spec/apis/settings_spec.lua +++ b/src/test/resources/test-rom/spec/apis/settings_spec.lua @@ -1,4 +1,18 @@ describe("The settings library", function() + describe("settings.define", function() + it("ensures valid type names", function() + expect.error(settings.define, "test.defined", { type = "function" }) + :eq('Unknown type "function". Expected one of number, string, boolean, table.') + end) + end) + describe("settings.undefine", function() + it("clears defined settings", function() + settings.define("test.unset", { default = 123 }) + settings.undefine("test.unset") + expect(settings.get("test.unset")):eq(nil) + end) + end) + describe("settings.set", function() it("validates arguments", function() settings.set("test", 1) @@ -13,6 +27,30 @@ describe("The settings library", function() it("prevents storing unserialisable types", function() expect.error(settings.set, "", { print }):eq("Cannot serialize type function") end) + + it("setting changes the value", function() + local random = math.random(1, 0x7FFFFFFF) + settings.set("test", random) + expect(settings.get("test")):eq(random) + end) + + it("checks the type of the value", function() + settings.define("test.defined", { default = 123, description = "A description", type = "number" }) + expect.error(settings.set, "test.defined", "hello") + :eq("bad argument #2 (expected number, got string)") + settings.set("test.defined", 123) + end) + + it("setting fires an event", function() + settings.clear() + + local s = stub(os, "queueEvent") + settings.set("test", 1) + settings.set("test", 2) + + expect(s):called_with("setting_changed", "test", 1, nil) + expect(s):called_with("setting_changed", "test", 2, 1) + end) end) describe("settings.get", function() @@ -20,6 +58,43 @@ describe("The settings library", function() settings.get("test") expect.error(settings.get, nil):eq("bad argument #1 (expected string, got nil)") end) + + it("returns the default", function() + expect(settings.get("test.undefined")):eq(nil) + expect(settings.get("test.undefined", "?")):eq("?") + + settings.define("test.unset", { default = "default" }) + expect(settings.get("test.unset")):eq("default") + expect(settings.get("test.unset", "?")):eq("?") + end) + end) + + describe("settings.getDetails", function() + it("validates arguments", function() + expect.error(settings.getDetails, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("works on undefined and unset values", function() + expect(settings.getDetails("test.undefined")):same { value = nil, changed = false } + end) + + it("works on undefined but set values", function() + settings.set("test", 456) + expect(settings.getDetails("test")):same { value = 456, changed = true } + end) + + it("works on defined but unset values", function() + settings.define("test.unset", { default = 123, description = "A description" }) + expect(settings.getDetails("test.unset")):same + { default = 123, value = 123, changed = false, description = "A description" } + end) + + it("works on defined and set values", function() + settings.define("test.defined", { default = 123, description = "A description", type = "number" }) + settings.set("test.defined", 456) + expect(settings.getDetails("test.defined")):same + { default = 123, value = 456, changed = true, description = "A description", type = "number" } + end) end) describe("settings.unset", function() @@ -27,17 +102,73 @@ describe("The settings library", function() settings.unset("test") expect.error(settings.unset, nil):eq("bad argument #1 (expected string, got nil)") end) + + it("unsetting resets the value", function() + settings.set("test", true) + settings.unset("test") + expect(settings.get("test")):eq(nil) + end) + + it("unsetting does not touch defaults", function() + settings.define("test.defined", { default = 123 }) + settings.set("test.defined", 456) + settings.unset("test.defined") + expect(settings.get("test.defined")):eq(123) + end) + + it("unsetting fires an event", function() + settings.set("test", 1) + + local s = stub(os, "queueEvent") + settings.unset("test") + expect(s):called_with("setting_changed", "test", nil, 1) + end) + end) + + describe("settings.clear", function() + it("clearing resets all values", function() + settings.set("test", true) + settings.clear() + expect(settings.get("test")):eq(nil) + end) + + it("clearing does not touch defaults", function() + settings.define("test.defined", { default = 123 }) + settings.set("test.defined", 456) + settings.clear() + expect(settings.get("test.defined")):eq(123) + end) + + it("clearing fires an event", function() + settings.set("test", 1) + + local s = stub(os, "queueEvent") + settings.clear() + expect(s):called_with("setting_changed", "test", nil, 1) + end) end) describe("settings.load", function() it("validates arguments", function() - expect.error(settings.load, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(settings.load, 1):eq("bad argument #1 (expected string, got number)") + end) + + it("defaults to .settings", function() + local s = stub(fs, "open") + settings.load() + expect(s):called_with(".settings", "r") end) end) describe("settings.save", function() it("validates arguments", function() - expect.error(settings.save, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(settings.save, 1):eq("bad argument #1 (expected string, got number)") + end) + + it("defaults to .settings", function() + local s = stub(fs, "open") + settings.save() + expect(s):called_with(".settings", "w") end) end) end) diff --git a/src/test/resources/test-rom/spec/programs/set_spec.lua b/src/test/resources/test-rom/spec/programs/set_spec.lua index 46cf0b84d..8d74d951e 100644 --- a/src/test/resources/test-rom/spec/programs/set_spec.lua +++ b/src/test/resources/test-rom/spec/programs/set_spec.lua @@ -1,29 +1,59 @@ local capture = require "test_helpers".capture_program describe("The set program", function() + local function setup() + local set = setmetatable({}, { __index = _G }) + loadfile("/rom/apis/settings.lua", set)() + stub(_G, "settings", set) + + settings.set("test", "Hello World!") + settings.define("test.defined", { default = 456, description = "A description", type = "number" }) + end it("displays all settings", function() - settings.clear() - settings.set("Test", "Hello World!") - settings.set("123", 456) + setup() expect(capture(stub, "set")) - :matches { ok = true, output = '"123" is 456\n"Test" is "Hello World!"\n', error = "" } + :matches { ok = true, output = '"test" is "Hello World!"\n"test.defined" is 456\n', error = "" } end) - it("displays a single settings", function() - settings.clear() - settings.set("Test", "Hello World!") - settings.set("123", 456) + it("displays a single setting", function() + setup() - expect(capture(stub, "set Test")) - :matches { ok = true, output = '"Test" is "Hello World!"\n', error = "" } + expect(capture(stub, "set test")) + :matches { ok = true, output = 'test is "Hello World!"\n', error = "" } + end) + + it("displays a single setting with description", function() + setup() + + expect(capture(stub, "set test")) + :matches { ok = true, output = 'test is "Hello World!"\n', error = "" } + end) + + it("displays a changed setting with description", function() + setup() + + settings.set("test.defined", 123) + expect(capture(stub, "set test.defined")) + :matches { ok = true, output = 'test.defined is 123 (default is 456)\nA description\n', error = "" } end) it("set a setting", function() - expect(capture(stub, "set Test Hello")) - :matches { ok = true, output = '"Test" set to "Hello"\n', error = "" } + setup() - expect(settings.get("Test")):eq("Hello") + expect(capture(stub, "set test Hello")) + :matches { ok = true, output = '"test" set to "Hello"\n', error = "" } + + expect(settings.get("test")):eq("Hello") + end) + + it("checks the type of a setting", function() + setup() + + expect(capture(stub, "set test.defined Hello")) + :matches { ok = true, output = "", error = '"Hello" is not a valid number.\n' } + expect(capture(stub, "set test.defined 456")) + :matches { ok = true, output = '"test.defined" set to 456\n', error = "" } end) end) From 3b7b8459304ced12b3a893aa9369b50fd64fd8a1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 21 Apr 2020 12:12:44 +0100 Subject: [PATCH 181/711] Some tiny bits of documentation cleanup I'm really good at this English lark :D:. --- illuaminate.sexp | 17 +++++++++++++++++ .../computercraft/lua/rom/apis/settings.lua | 7 ++++++- .../computercraft/lua/rom/apis/window.lua | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index 38ed350c5..f727a3a8e 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -59,3 +59,20 @@ (at /doc/stub (linters -var:unused-global) (lint (allow-toplevel-global true))) + +;; Ensure any fully documented modules stay fully documented. +(at + (/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua + /src/main/resources/assets/computercraft/lua/rom/apis/colours.lua + /src/main/resources/assets/computercraft/lua/rom/apis/disk.lua + /src/main/resources/assets/computercraft/lua/rom/apis/gps.lua + /src/main/resources/assets/computercraft/lua/rom/apis/help.lua + /src/main/resources/assets/computercraft/lua/rom/apis/keys.lua + /src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua + /src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua + /src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua + /src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua + /src/main/resources/assets/computercraft/lua/rom/apis/settings.lua + /src/main/resources/assets/computercraft/lua/rom/apis/texutils.lua + /src/main/resources/assets/computercraft/lua/rom/apis/vector.lua) + (linters doc:undocumented doc:undocumented-arg)) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index fcfb1d17a..3046f65b1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -124,7 +124,12 @@ function get(name, default) end end ---- Get details about a specific setting +--- Get details about a specific setting. +-- +-- @tparam string name The name of the setting to get. +-- @treturn { description? = string, default? = value, type? = string, value? = value } +-- Information about this setting. This includes all information from @{settings.define}, +-- as well as this setting's value. function getDetails(name) expect(1, name, "string") local deets = copy(details[name]) or {} diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua index 57bd70c54..d93533f03 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/window.lua @@ -445,7 +445,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) -- @treturn string The textual content of this line. -- @treturn string The text colours of this line, suitable for use with @{term.blit}. -- @treturn string The background colours of this line, suitable for use with @{term.blit}. - -- @throws If `y` is a valid line. + -- @throws If `y` is not between 1 and this window's height. function window.getLine(y) if type(y) ~= "number" then expect(1, y, "number") end From 463635a45918b54606732ddc204018b000e17d06 Mon Sep 17 00:00:00 2001 From: Wojbie Date: Tue, 21 Apr 2020 18:28:55 +0200 Subject: [PATCH 182/711] Fix save() sPath param. --- .../resources/assets/computercraft/lua/rom/apis/settings.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 3046f65b1..c1fcb45f6 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -228,7 +228,7 @@ end -- @see settings.load function save(sPath) expect(1, sPath, "string", "nil") - local file = fs.open(".settings", "w") + local file = fs.open(sPath or ".settings", "w") if not file then return false end From f3de97d67fc74876b85f823b69da163b8d37b11b Mon Sep 17 00:00:00 2001 From: JakobDev Date: Wed, 22 Apr 2020 07:30:49 +0200 Subject: [PATCH 183/711] Remove / and \ at the start of shell.setDir() (#410) Uses fs.combine to normalise the file path. This removes leading/trailing slashes, as well as any redundant "../"s within the path. --- .../resources/assets/computercraft/lua/rom/programs/shell.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 8a63138f8..0d4b9f337 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -194,7 +194,7 @@ function shell.setDir(_sDir) if not fs.isDir(_sDir) then error("Not a directory", 2) end - sDir = _sDir + sDir = fs.combine(_sDir, "") end function shell.path() From f106733d716a96ecd445f7a8ea7a447166ea8bbd Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 22 Apr 2020 08:58:21 +0100 Subject: [PATCH 184/711] Redo how http block/allow lists are stored. (#396) This replaces the allow/block lists with a series of rules. Each rule takes the form [[http.rules]] host = "127.0.0.0/8" action = "block" This is pretty much the same as the previous config style, in that hosts may be domains, wildcards or in CIDR notation. However, they may also be mixed, so you could allow a specific IP, and then block all others. --- .../dan200/computercraft/ComputerCraft.java | 21 +- .../core/apis/AddressPredicate.java | 181 ------------------ .../computercraft/core/apis/HTTPAPI.java | 2 +- .../core/apis/http/AddressRule.java | 167 ++++++++++++++++ .../core/apis/http/NetworkUtils.java | 16 +- .../core/apis/http/request/HttpRequest.java | 2 - .../core/apis/http/websocket/Websocket.java | 1 - .../core/computer/ComputerExecutor.java | 2 +- .../dan200/computercraft/shared/Config.java | 75 +++++--- 9 files changed, 234 insertions(+), 233 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/core/apis/AddressPredicate.java create mode 100644 src/main/java/dan200/computercraft/core/apis/http/AddressRule.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 4aacb9842..99ec296b2 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -6,7 +6,7 @@ package dan200.computercraft; import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.core.apis.AddressPredicate; +import dan200.computercraft.core.apis.http.AddressRule; import dan200.computercraft.core.apis.http.websocket.Websocket; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.computer.blocks.BlockComputer; @@ -39,8 +39,13 @@ import org.apache.logging.log4j.Logger; import java.io.IOException; import java.io.InputStream; +import java.util.Collections; import java.util.EnumSet; +import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; @Mod( ComputerCraft.MOD_ID ) public final class ComputerCraft @@ -50,8 +55,8 @@ public final class ComputerCraft public static final int DATAFIXER_VERSION = 0; // Configuration options - public static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" }; - public static final String[] DEFAULT_HTTP_BLACKLIST = new String[] { + public static final String[] DEFAULT_HTTP_ALLOW = new String[] { "*" }; + public static final String[] DEFAULT_HTTP_DENY = new String[] { "127.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", @@ -71,10 +76,12 @@ public final class ComputerCraft public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( 10 ); public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( 5 ); - public static boolean http_enable = true; - public static boolean http_websocket_enable = true; - public static AddressPredicate http_whitelist = new AddressPredicate( DEFAULT_HTTP_WHITELIST ); - public static AddressPredicate http_blacklist = new AddressPredicate( DEFAULT_HTTP_BLACKLIST ); + public static boolean httpEnabled = true; + public static boolean httpWebsocketEnabled = true; + public static List httpRules = Collections.unmodifiableList( Stream.concat( + Stream.of( DEFAULT_HTTP_DENY ).map( x -> AddressRule.parse( x, AddressRule.Action.DENY ) ).filter( Objects::nonNull ), + Stream.of( DEFAULT_HTTP_ALLOW ).map( x -> AddressRule.parse( x, AddressRule.Action.ALLOW ) ).filter( Objects::nonNull ) + ).collect( Collectors.toList() ) ); public static int httpTimeout = 30000; public static int httpMaxRequests = 16; diff --git a/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java b/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java deleted file mode 100644 index 69708fc83..000000000 --- a/src/main/java/dan200/computercraft/core/apis/AddressPredicate.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.core.apis; - -import com.google.common.net.InetAddresses; -import dan200.computercraft.ComputerCraft; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; - -/** - * Used to determine whether a domain or IP address matches a series of patterns. - */ -public class AddressPredicate -{ - private static final class HostRange - { - private final byte[] min; - private final byte[] max; - - private HostRange( byte[] min, byte[] max ) - { - this.min = min; - this.max = max; - } - - public boolean contains( InetAddress address ) - { - byte[] entry = address.getAddress(); - if( entry.length != min.length ) return false; - - for( int i = 0; i < entry.length; i++ ) - { - int value = 0xFF & entry[i]; - if( value < (0xFF & min[i]) || value > (0xFF & max[i]) ) return false; - } - - return true; - } - } - - private final List wildcards; - private final List ranges; - - public AddressPredicate( String... filters ) - { - this( Arrays.asList( filters ) ); - } - - public AddressPredicate( Iterable filters ) - { - List wildcards = this.wildcards = new ArrayList<>(); - List ranges = this.ranges = new ArrayList<>(); - - for( String filter : filters ) - { - int cidr = filter.indexOf( '/' ); - if( cidr >= 0 ) - { - String addressStr = filter.substring( 0, cidr ); - String prefixSizeStr = filter.substring( cidr + 1 ); - - int prefixSize; - try - { - prefixSize = Integer.parseInt( prefixSizeStr ); - } - catch( NumberFormatException e ) - { - ComputerCraft.log.error( - "Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.", - filter, prefixSizeStr - ); - continue; - } - - InetAddress address; - try - { - address = InetAddresses.forString( addressStr ); - } - catch( IllegalArgumentException e ) - { - ComputerCraft.log.error( - "Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.", - filter, prefixSizeStr - ); - continue; - } - - // Mask the bytes of the IP address. - byte[] minBytes = address.getAddress(), maxBytes = address.getAddress(); - int size = prefixSize; - for( int i = 0; i < minBytes.length; i++ ) - { - if( size <= 0 ) - { - minBytes[i] &= 0; - maxBytes[i] |= 0xFF; - } - else if( size < 8 ) - { - minBytes[i] &= 0xFF << (8 - size); - maxBytes[i] |= ~(0xFF << (8 - size)); - } - - size -= 8; - } - - ranges.add( new HostRange( minBytes, maxBytes ) ); - } - else - { - wildcards.add( Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ) ); - } - } - } - - /** - * Determine whether a host name matches a series of patterns. - * - * This is intended to allow early exiting, before one has to look up the IP address. You should use - * {@link #matches(InetAddress)} instead of/in addition to this one. - * - * @param domain The domain to match. - * @return Whether the patterns were matched. - */ - public boolean matches( String domain ) - { - for( Pattern domainPattern : wildcards ) - { - if( domainPattern.matcher( domain ).matches() ) return true; - } - - return false; - } - - private boolean matchesAddress( InetAddress address ) - { - String addressString = address.getHostAddress(); - for( Pattern domainPattern : wildcards ) - { - if( domainPattern.matcher( addressString ).matches() ) return true; - } - - for( HostRange range : ranges ) - { - if( range.contains( address ) ) return true; - } - - return false; - } - - /** - * Determine whether the given address matches a series of patterns. - * - * @param address The address to check. - * @return Whether it matches any of these patterns. - */ - public boolean matches( InetAddress address ) - { - // Match the host name - String host = address.getHostName(); - if( host != null && matches( host ) ) return true; - - // Match the normal address - if( matchesAddress( address ) ) return true; - - // If we're an IPv4 address in disguise then let's check that. - return address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address ) - && matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) ); - - } -} diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 8c29d9237..375135ffd 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -173,7 +173,7 @@ public class HTTPAPI implements ILuaAPI String address = getString( args, 0 ); Map headerTbl = optTable( args, 1, Collections.emptyMap() ); - if( !ComputerCraft.http_websocket_enable ) + if( !ComputerCraft.httpWebsocketEnabled ) { throw new LuaException( "Websocket connections are disabled" ); } diff --git a/src/main/java/dan200/computercraft/core/apis/http/AddressRule.java b/src/main/java/dan200/computercraft/core/apis/http/AddressRule.java new file mode 100644 index 000000000..19ab61f36 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/http/AddressRule.java @@ -0,0 +1,167 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.apis.http; + +import com.google.common.net.InetAddresses; +import dan200.computercraft.ComputerCraft; + +import javax.annotation.Nullable; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.regex.Pattern; + +/** + * A pattern which matches an address, and controls whether it is accessible or not. + */ +public final class AddressRule +{ + private static final class HostRange + { + private final byte[] min; + private final byte[] max; + + private HostRange( byte[] min, byte[] max ) + { + this.min = min; + this.max = max; + } + + public boolean contains( InetAddress address ) + { + byte[] entry = address.getAddress(); + if( entry.length != min.length ) return false; + + for( int i = 0; i < entry.length; i++ ) + { + int value = 0xFF & entry[i]; + if( value < (0xFF & min[i]) || value > (0xFF & max[i]) ) return false; + } + + return true; + } + } + + public enum Action + { + ALLOW, + DENY, + } + + private final HostRange ip; + private final Pattern domainPattern; + private final Action action; + + private AddressRule( HostRange ip, Pattern domainPattern, Action action ) + { + this.ip = ip; + this.domainPattern = domainPattern; + this.action = action; + } + + @Nullable + public static AddressRule parse( String filter, Action action ) + { + int cidr = filter.indexOf( '/' ); + if( cidr >= 0 ) + { + String addressStr = filter.substring( 0, cidr ); + String prefixSizeStr = filter.substring( cidr + 1 ); + + int prefixSize; + try + { + prefixSize = Integer.parseInt( prefixSizeStr ); + } + catch( NumberFormatException e ) + { + ComputerCraft.log.error( + "Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.", + filter, prefixSizeStr + ); + return null; + } + + InetAddress address; + try + { + address = InetAddresses.forString( addressStr ); + } + catch( IllegalArgumentException e ) + { + ComputerCraft.log.error( + "Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.", + filter, prefixSizeStr + ); + return null; + } + + // Mask the bytes of the IP address. + byte[] minBytes = address.getAddress(), maxBytes = address.getAddress(); + int size = prefixSize; + for( int i = 0; i < minBytes.length; i++ ) + { + if( size <= 0 ) + { + minBytes[i] &= 0; + maxBytes[i] |= 0xFF; + } + else if( size < 8 ) + { + minBytes[i] &= 0xFF << (8 - size); + maxBytes[i] |= ~(0xFF << (8 - size)); + } + + size -= 8; + } + + return new AddressRule( new HostRange( minBytes, maxBytes ), null, action ); + } + else + { + Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ); + return new AddressRule( null, pattern, action ); + } + } + + /** + * Determine whether the given address matches a series of patterns. + * + * @param domain The domain to match + * @param address The address to check. + * @return Whether it matches any of these patterns. + */ + public boolean matches( String domain, InetAddress address ) + { + if( domainPattern != null ) + { + if( domainPattern.matcher( domain ).matches() ) return true; + if( domainPattern.matcher( address.getHostName() ).matches() ) return true; + } + + // Match the normal address + if( matchesAddress( address ) ) return true; + + // If we're an IPv4 address in disguise then let's check that. + return address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address ) + && matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) ); + } + + private boolean matchesAddress( InetAddress address ) + { + if( domainPattern != null && domainPattern.matcher( address.getHostAddress() ).matches() ) return true; + return ip != null && ip.contains( address ); + } + + public static Action apply( Iterable rules, String domain, InetAddress address ) + { + for( AddressRule rule : rules ) + { + if( rule.matches( domain, address ) ) return rule.action; + } + + return Action.DENY; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java index aedf7e419..c2a3e6c59 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -97,20 +97,6 @@ public final class NetworkUtils } } - /** - * Checks a host is allowed. - * - * @param host The domain to check against - * @throws HTTPRequestException If the host is not permitted. - */ - public static void checkHost( String host ) throws HTTPRequestException - { - if( !ComputerCraft.http_whitelist.matches( host ) || ComputerCraft.http_blacklist.matches( host ) ) - { - throw new HTTPRequestException( "Domain not permitted" ); - } - } - /** * Create a {@link InetSocketAddress} from the resolved {@code host} and port. * @@ -130,7 +116,7 @@ public final class NetworkUtils if( socketAddress.isUnresolved() ) throw new HTTPRequestException( "Unknown host" ); InetAddress address = socketAddress.getAddress(); - if( !ComputerCraft.http_whitelist.matches( address ) || ComputerCraft.http_blacklist.matches( address ) ) + if( AddressRule.apply( ComputerCraft.httpRules, host, address ) == AddressRule.Action.DENY ) { throw new HTTPRequestException( "Domain not permitted" ); } diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index 2f03a1b7e..b15ce77d5 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -119,8 +119,6 @@ public class HttpRequest extends Resource { throw new HTTPRequestException( "Invalid protocol '" + scheme + "'" ); } - - NetworkUtils.checkHost( url.getHost() ); } public void request( URI uri, HttpMethod method ) diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index 67a15e963..c088f09d2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -106,7 +106,6 @@ public class Websocket extends Resource throw new HTTPRequestException( "Invalid scheme '" + scheme + "'" ); } - NetworkUtils.checkHost( uri.getHost() ); return uri; } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index e33089bae..b3ccd2718 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -171,7 +171,7 @@ final class ComputerExecutor apis.add( new FSAPI( environment ) ); apis.add( new PeripheralAPI( environment ) ); apis.add( new OSAPI( environment ) ); - if( ComputerCraft.http_enable ) apis.add( new HTTPAPI( environment ) ); + if( ComputerCraft.httpEnabled ) apis.add( new HTTPAPI( environment ) ); // Load in the externally registered APIs. for( ILuaAPIFactory factory : ApiFactories.getAll() ) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 864c51949..017725408 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -6,12 +6,13 @@ package dan200.computercraft.shared; import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.UnmodifiableConfig; import com.electronwill.nightconfig.core.file.CommentedFileConfig; import com.google.common.base.CaseFormat; import com.google.common.base.Converter; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.core.apis.AddressPredicate; +import dan200.computercraft.core.apis.http.AddressRule; import dan200.computercraft.core.apis.http.websocket.Websocket; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -19,13 +20,14 @@ import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; -import java.util.Arrays; +import javax.annotation.Nullable; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_BLACKLIST; -import static dan200.computercraft.ComputerCraft.DEFAULT_HTTP_WHITELIST; import static net.minecraftforge.common.ForgeConfigSpec.Builder; import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue; @@ -50,8 +52,7 @@ public final class Config private static ConfigValue httpEnabled; private static ConfigValue httpWebsocketEnabled; - private static ConfigValue> httpWhitelist; - private static ConfigValue> httpBlacklist; + private static ConfigValue> httpRules; private static ConfigValue httpTimeout; private static ConfigValue httpMaxRequests; @@ -151,25 +152,25 @@ public final class Config builder.push( "http" ); httpEnabled = builder - .comment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for more " + - "fine grained control than this)" ) - .define( "enabled", ComputerCraft.http_enable ); + .comment( "Enable the \"http\" API on Computers (see \"rules\" for more fine grained control than this)." ) + .define( "enabled", ComputerCraft.httpEnabled ); httpWebsocketEnabled = builder .comment( "Enable use of http websockets. This requires the \"http_enable\" option to also be true." ) - .define( "websocket_enabled", ComputerCraft.http_websocket_enable ); + .define( "websocket_enabled", ComputerCraft.httpWebsocketEnabled ); - httpWhitelist = builder - .comment( "A list of wildcards for domains or IP ranges that can be accessed through the \"http\" API on Computers.\n" + - "Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to just subdomains of pastebin.com.\n" + - "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) - .defineList( "whitelist", Arrays.asList( DEFAULT_HTTP_WHITELIST ), x -> true ); - - httpBlacklist = builder - .comment( "A list of wildcards for domains or IP ranges that cannot be accessed through the \"http\" API on Computers.\n" + - "If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block access to all subdomains of github.com.\n" + - "You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." ) - .defineList( "blacklist", Arrays.asList( DEFAULT_HTTP_BLACKLIST ), x -> true ); + httpRules = builder + .comment( "A list of rules which control which domains or IPs are allowed through the \"http\" API on computers.\n" + + "Each rule is an item with a 'host' to match against, and an action. " + + "The host may be a domain name (\"pastebin.com\"),\n" + + "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). 'action' maybe 'allow' or 'block'. If no rules" + + "match, the domain will be blocked." ) + .defineList( "rules", + Stream.concat( + Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> makeRule( x, "deny" ) ), + Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> makeRule( x, "allow" ) ) + ).collect( Collectors.toList() ), + x -> x instanceof UnmodifiableConfig && parseRule( (UnmodifiableConfig) x ) != null ); httpTimeout = builder .comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ) @@ -286,10 +287,10 @@ public final class Config ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( maxMainComputerTime.get() ); // HTTP - ComputerCraft.http_enable = httpEnabled.get(); - ComputerCraft.http_websocket_enable = httpWebsocketEnabled.get(); - ComputerCraft.http_whitelist = new AddressPredicate( httpWhitelist.get() ); - ComputerCraft.http_blacklist = new AddressPredicate( httpBlacklist.get() ); + ComputerCraft.httpEnabled = httpEnabled.get(); + ComputerCraft.httpWebsocketEnabled = httpWebsocketEnabled.get(); + ComputerCraft.httpRules = Collections.unmodifiableList( httpRules.get().stream() + .map( Config::parseRule ).filter( Objects::nonNull ).collect( Collectors.toList() ) ); ComputerCraft.httpTimeout = httpTimeout.get(); ComputerCraft.httpMaxRequests = httpMaxRequests.get(); @@ -346,4 +347,28 @@ public final class Config return null; } } + + private static UnmodifiableConfig makeRule( String host, String action ) + { + com.electronwill.nightconfig.core.Config config = com.electronwill.nightconfig.core.Config.inMemory(); + config.add( "host", host ); + config.add( "action", action ); + return config; + } + + @Nullable + private static AddressRule parseRule( UnmodifiableConfig builder ) + { + Object hostObj = builder.get( "host" ); + Object actionObj = builder.get( "action" ); + if( !(hostObj instanceof String) || !(actionObj instanceof String) ) return null; + + String host = (String) hostObj, action = (String) actionObj; + for( AddressRule.Action candiate : AddressRule.Action.values() ) + { + if( candiate.name().equalsIgnoreCase( action ) ) return AddressRule.parse( host, candiate ); + } + + return null; + } } From e5cc345f497a1e7199e8d037fefea89c0df89c32 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Apr 2020 10:00:43 +0100 Subject: [PATCH 185/711] Some cleanup to the Lua programs --- illuaminate.sexp | 47 ++++++++--------- .../dan200/computercraft/ComputerCraft.java | 3 +- .../dan200/computercraft/core/apis/OSAPI.java | 4 +- .../lua/rom/apis/command/commands.lua | 52 +++++++++---------- .../data/computercraft/lua/rom/apis/keys.lua | 6 +-- 5 files changed, 53 insertions(+), 59 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index f727a3a8e..22219f22c 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -2,11 +2,10 @@ (sources /doc/stub/ - /src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/ + /src/main/resources/data/computercraft/lua/bios.lua + /src/main/resources/data/computercraft/lua/rom/ /src/test/resources/test-rom) - (doc (title "CC: Tweaked") (index doc/index.md) @@ -15,13 +14,13 @@ (library-path /doc/stub/ - /src/main/resources/assets/computercraft/lua/rom/apis - /src/main/resources/assets/computercraft/lua/rom/apis/command - /src/main/resources/assets/computercraft/lua/rom/apis/turtle + /src/main/resources/data/computercraft/lua/rom/apis + /src/main/resources/data/computercraft/lua/rom/apis/command + /src/main/resources/data/computercraft/lua/rom/apis/turtle - /src/main/resources/assets/computercraft/lua/rom/modules/main - /src/main/resources/assets/computercraft/lua/rom/modules/command - /src/main/resources/assets/computercraft/lua/rom/modules/turtle)) + /src/main/resources/data/computercraft/lua/rom/modules/main + /src/main/resources/data/computercraft/lua/rom/modules/command + /src/main/resources/data/computercraft/lua/rom/modules/turtle)) (at / (linters @@ -50,8 +49,8 @@ ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. (at - (/src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/apis/) + (/src/main/resources/data/computercraft/lua/bios.lua + /src/main/resources/data/computercraft/lua/rom/apis/) (linters -var:unused-global) (lint (allow-toplevel-global true))) @@ -62,17 +61,17 @@ ;; Ensure any fully documented modules stay fully documented. (at - (/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua - /src/main/resources/assets/computercraft/lua/rom/apis/colours.lua - /src/main/resources/assets/computercraft/lua/rom/apis/disk.lua - /src/main/resources/assets/computercraft/lua/rom/apis/gps.lua - /src/main/resources/assets/computercraft/lua/rom/apis/help.lua - /src/main/resources/assets/computercraft/lua/rom/apis/keys.lua - /src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua - /src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua - /src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua - /src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua - /src/main/resources/assets/computercraft/lua/rom/apis/settings.lua - /src/main/resources/assets/computercraft/lua/rom/apis/texutils.lua - /src/main/resources/assets/computercraft/lua/rom/apis/vector.lua) + (/src/main/resources/data/computercraft/lua/rom/apis/colors.lua + /src/main/resources/data/computercraft/lua/rom/apis/colours.lua + /src/main/resources/data/computercraft/lua/rom/apis/disk.lua + /src/main/resources/data/computercraft/lua/rom/apis/gps.lua + /src/main/resources/data/computercraft/lua/rom/apis/help.lua + /src/main/resources/data/computercraft/lua/rom/apis/keys.lua + /src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua + /src/main/resources/data/computercraft/lua/rom/apis/parallel.lua + /src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua + /src/main/resources/data/computercraft/lua/rom/apis/rednet.lua + /src/main/resources/data/computercraft/lua/rom/apis/settings.lua + /src/main/resources/data/computercraft/lua/rom/apis/texutils.lua + /src/main/resources/data/computercraft/lua/rom/apis/vector.lua) (linters doc:undocumented doc:undocumented-arg)) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 9a4246e5d..b27beb1cd 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -7,7 +7,6 @@ package dan200.computercraft; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.AddressPredicate; -import dan200.computercraft.core.apis.http.websocket.Websocket; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; @@ -22,9 +21,9 @@ import dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull; import dan200.computercraft.shared.peripheral.modem.wired.ItemBlockCable; import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem; import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; +import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.printer.BlockPrinter; import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; -import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 71577a127..6ccd51730 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -95,10 +95,10 @@ public class OSAPI implements ILuaAPI if( time > previousTime || day > previousDay ) { double now = m_day * 24.0 + m_time; - Iterator> it = m_alarms.entrySet().iterator(); + Iterator> it = m_alarms.int2ObjectEntrySet().iterator(); while( it.hasNext() ) { - Map.Entry entry = it.next(); + Int2ObjectMap.Entry entry = it.next(); Alarm alarm = entry.getValue(); double t = alarm.m_day * 24.0 + alarm.m_time; if( now >= t ) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua index e09b9248d..5877c1b8e 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/command/commands.lua @@ -14,7 +14,7 @@ -- @module commands if not commands then - error( "Cannot load command API on normal computer", 2 ) + error("Cannot load command API on normal computer", 2) end --- The builtin commands API, without any generated command helper functions @@ -23,16 +23,16 @@ end -- overwritten by a command. local native = commands.native or commands -local function collapseArgs( bJSONIsNBT, ... ) +local function collapseArgs(bJSONIsNBT, ...) local args = table.pack(...) for i = 1, #args do local arg = args[i] if type(arg) == "boolean" or type(arg) == "number" or type(arg) == "string" then args[i] = tostring(arg) elseif type(arg) == "table" then - args[i] = textutils.serialiseJSON( arg, bJSONIsNBT ) + args[i] = textutils.serialiseJSON(arg, bJSONIsNBT) else - error( "Expected string, number, boolean or table", 3 ) + error("Expected string, number, boolean or table", 3) end end @@ -42,22 +42,22 @@ end -- Put native functions into the environment local env = _ENV env.native = native -for k,v in pairs( native ) do +for k, v in pairs(native) do env[k] = v end -- Create wrapper functions for all the commands local tAsync = {} local tNonNBTJSONCommands = { - [ "tellraw" ] = true, - [ "title" ] = true + ["tellraw"] = true, + ["title"] = true, } local command_mt = {} function command_mt.__call(self, ...) local meta = self[command_mt] - local sCommand = collapseArgs( meta.json, table.concat(meta.name, " "), ... ) - return meta.func( sCommand ) + local sCommand = collapseArgs(meta.json, table.concat(meta.name, " "), ...) + return meta.func(sCommand) end function command_mt.__tostring(self) @@ -65,6 +65,16 @@ function command_mt.__tostring(self) return ("command %q"):format("/" .. table.concat(meta.name, " ")) end +local function mk_command(name, json, func) + return setmetatable({ + [command_mt] = { + name = name, + func = func, + json = json, + }, + }, command_mt) +end + function command_mt.__index(self, key) local meta = self[command_mt] if meta.children then return nil end @@ -74,31 +84,17 @@ function command_mt.__index(self, key) for _, child in ipairs(native.list(table.unpack(name))) do local child_name = { table.unpack(name) } child_name[#child_name + 1] = child - - self[child] = setmetatable({ [command_mt] = { - name = child_name, - func = meta.func, - json = meta.json - } }, command_mt) + self[child] = mk_command(child_name, meta.json, meta.func) end return self[key] end for _, sCommandName in ipairs(native.list()) do - if env[ sCommandName ] == nil then - local bJSONIsNBT = tNonNBTJSONCommands[ sCommandName ] == nil - env[ sCommandName ] = setmetatable({ [command_mt] = { - name = { sCommandName }, - func = native.exec, - json = bJSONIsNBT - } }, command_mt) - - tAsync[ sCommandName ] = setmetatable({ [command_mt] = { - name = { sCommandName }, - func = native.execAsync, - json = bJSONIsNBT - } }, command_mt) + if env[sCommandName] == nil then + local bJSONIsNBT = tNonNBTJSONCommands[sCommandName] == nil + env[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.exec) + tAsync[sCommandName] = mk_command({ sCommandName }, bJSONIsNBT, native.execAsync) end end env.async = tAsync diff --git a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua index d5df768e9..90f877aa5 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua @@ -131,7 +131,7 @@ tKeys[346] = 'rightAlt' -- tKeys[348] = 'menu' local keys = _ENV -for nKey, sKey in pairs( tKeys ) do +for nKey, sKey in pairs(tKeys) do keys[sKey] = nKey end @@ -145,7 +145,7 @@ keys.cimcumflex = keys.circumflex --- @local -- -- @tparam number code The key code to look up. -- @treturn string|nil The name of the key, or `nil` if not a valid key code. -function getName( _nKey ) +function getName(_nKey) expect(1, _nKey, "number") - return tKeys[ _nKey ] + return tKeys[_nKey] end From 4ed4a6409b355648d0fbd00fa50ba728ed8a5332 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Apr 2020 10:07:43 +0100 Subject: [PATCH 186/711] Skip the src/generated file in check-lines --- tools/check-lines.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/check-lines.py b/tools/check-lines.py index d50d4610d..956e87d46 100644 --- a/tools/check-lines.py +++ b/tools/check-lines.py @@ -6,7 +6,8 @@ problems = False exclude = [ "*.png", "**/data/json-parsing/*.json" ] for path in pathlib.Path("src").glob("**/*"): - if path.is_dir() or path.suffix == "" or any(path.match(x) for x in exclude): + # Ideally we'd use generated as a glob, but .match("generated/**/*.json") doesn't work! + if path.is_dir() or path.suffix == "" or any(path.match(x) for x in exclude) or path.parts[1] == "generated": continue with path.open(encoding="utf-8") as file: From ee391ae9eaf1adbe5363c0eab4b7710510e8a997 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Apr 2020 10:17:31 +0100 Subject: [PATCH 187/711] Register a fake renderer for turtle players Fixes #383, probably. --- .../proxy/ComputerCraftProxyClient.java | 5 +++ .../client/render/TurtlePlayerRenderer.java | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index fc913fb81..e463204ba 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -10,6 +10,7 @@ import dan200.computercraft.client.gui.*; import dan200.computercraft.client.render.TileEntityCableRenderer; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; +import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; @@ -20,12 +21,14 @@ import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.client.gui.ScreenManager; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.client.registry.ClientRegistry; +import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; @@ -41,6 +44,8 @@ public final class ComputerCraftProxyClient ClientRegistry.bindTileEntitySpecialRenderer( TileMonitor.class, new TileEntityMonitorRenderer() ); ClientRegistry.bindTileEntitySpecialRenderer( TileCable.class, new TileEntityCableRenderer() ); ClientRegistry.bindTileEntitySpecialRenderer( TileTurtle.class, new TileEntityTurtleRenderer() ); + + RenderingRegistry.registerEntityRenderingHandler( TurtlePlayer.class, TurtlePlayerRenderer::new ); } private static void registerContainers() diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java new file mode 100644 index 000000000..341c9a591 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -0,0 +1,37 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.client.render; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class TurtlePlayerRenderer extends EntityRenderer +{ + public TurtlePlayerRenderer( EntityRendererManager renderManager ) + { + super( renderManager ); + } + + @Override + public void doRender( @Nonnull TurtlePlayer entity, double x, double y, double z, float entityYaw, float partialTicks ) + { + ComputerCraft.log.error( "Rendering TurtlePlayer on the client side, at {}", entity.getPosition() ); + } + + @Nullable + @Override + protected ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity ) + { + return null; + } +} From 759d02a2492924c05d1e75d1ce5fc83ebb493ce9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Apr 2020 11:04:29 +0100 Subject: [PATCH 188/711] Some post-merge cleanup --- build.gradle | 6 +++--- .../client/render/TurtlePlayerRenderer.java | 14 ++++++------- .../dan200/computercraft/core/apis/OSAPI.java | 2 +- .../core/filesystem/MountWrapper.java | 20 ++++++++++--------- .../computercraft/data/LootTableProvider.java | 13 ++++++------ .../peripheral/monitor/ClientMonitor.java | 2 +- .../peripheral/monitor/MonitorRenderer.java | 18 +---------------- 7 files changed, 31 insertions(+), 44 deletions(-) diff --git a/build.gradle b/build.gradle index 8fc56233d..cc7521a21 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ minecraft { } server { - workingDirectory project.file('run') + workingDirectory project.file("run/server-${mc_version}") property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' property 'forge.logging.console.level', 'debug' @@ -99,8 +99,8 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.2:api") - runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.2") + compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3:api") + runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java index 341c9a591..4c00145f9 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -6,14 +6,15 @@ package dan200.computercraft.client.render; -import dan200.computercraft.ComputerCraft; +import com.mojang.blaze3d.matrix.MatrixStack; +import dan200.computercraft.client.gui.GuiComputer; import dan200.computercraft.shared.turtle.core.TurtlePlayer; +import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererManager; import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; -import javax.annotation.Nullable; public class TurtlePlayerRenderer extends EntityRenderer { @@ -22,16 +23,15 @@ public class TurtlePlayerRenderer extends EntityRenderer super( renderManager ); } + @Nonnull @Override - public void doRender( @Nonnull TurtlePlayer entity, double x, double y, double z, float entityYaw, float partialTicks ) + public ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity ) { - ComputerCraft.log.error( "Rendering TurtlePlayer on the client side, at {}", entity.getPosition() ); + return GuiComputer.BACKGROUND_NORMAL; } - @Nullable @Override - protected ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity ) + public void render( @Nonnull TurtlePlayer entityIn, float entityYaw, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer buffer, int packedLightIn ) { - return null; } } diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 6ccd51730..825ad05fa 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -103,7 +103,7 @@ public class OSAPI implements ILuaAPI double t = alarm.m_day * 24.0 + alarm.m_time; if( now >= t ) { - queueLuaEvent( "alarm", new Object[] { entry.getKey() } ); + queueLuaEvent( "alarm", new Object[] { entry.getIntKey() } ); it.remove(); } } diff --git a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java index 5cc4ee958..a83838118 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java @@ -20,11 +20,11 @@ import java.util.OptionalLong; class MountWrapper { - private String label; - private String location; + private final String label; + private final String location; - private IMount mount; - private IWritableMount writableMount; + private final IMount mount; + private final IWritableMount writableMount; MountWrapper( String label, String location, IMount mount ) { @@ -36,7 +36,9 @@ class MountWrapper MountWrapper( String label, String location, IWritableMount mount ) { - this( label, location, (IMount) mount ); + this.label = label; + this.location = location; + this.mount = mount; writableMount = mount; } @@ -154,7 +156,7 @@ class MountWrapper { if( mount.exists( path ) && !mount.isDirectory( path ) ) { - return mount.openChannelForRead( path ); + return mount.openForRead( path ); } else { @@ -232,7 +234,7 @@ class MountWrapper writableMount.makeDirectory( dir ); } } - return writableMount.openChannelForWrite( path ); + return writableMount.openForWrite( path ); } } catch( AccessDeniedException e ) @@ -262,7 +264,7 @@ class MountWrapper writableMount.makeDirectory( dir ); } } - return writableMount.openChannelForWrite( path ); + return writableMount.openForWrite( path ); } else if( mount.isDirectory( path ) ) { @@ -270,7 +272,7 @@ class MountWrapper } else { - return writableMount.openChannelForAppend( path ); + return writableMount.openForAppend( path ); } } catch( AccessDeniedException e ) diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java index 54b47c42f..c0f0c44e0 100644 --- a/src/main/java/dan200/computercraft/data/LootTableProvider.java +++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -14,9 +14,10 @@ import net.minecraft.data.DataGenerator; import net.minecraft.data.DirectoryCache; import net.minecraft.data.IDataProvider; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.LootParameterSets; import net.minecraft.world.storage.loot.LootTable; import net.minecraft.world.storage.loot.LootTableManager; -import net.minecraft.world.storage.loot.ValidationResults; +import net.minecraft.world.storage.loot.ValidationTracker; import javax.annotation.Nonnull; import java.io.IOException; @@ -42,17 +43,17 @@ public abstract class LootTableProvider implements IDataProvider @Override public void act( @Nonnull DirectoryCache cache ) { - - ValidationResults validation = new ValidationResults(); Map tables = new HashMap<>(); + ValidationTracker validation = new ValidationTracker( LootParameterSets.GENERIC, x -> null, tables::get ); + registerLoot( ( id, table ) -> { - if( tables.containsKey( id ) ) validation.addProblem( "Duplicate loot tables for " + id ); + if( tables.containsKey( id ) ) validation.func_227530_a_( "Duplicate loot tables for " + id ); tables.put( id, table ); } ); - tables.forEach( ( key, value ) -> LootTableManager.func_215302_a( validation, key, value, tables::get ) ); + tables.forEach( ( key, value ) -> LootTableManager.func_227508_a_( validation, key, value ) ); - Multimap problems = validation.getProblems(); + Multimap problems = validation.func_227527_a_(); if( !problems.isEmpty() ) { problems.forEach( ( child, problem ) -> diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index a527a5ecb..4db761997 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -54,7 +54,7 @@ public final class ClientMonitor extends ClientTerminal if( buffer != null ) return false; deleteBuffers(); - buffer = new VertexBuffer( FixedWidthFontRenderer.POSITION_COLOR_TEX ); + buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.getVertexFormat() ); addMonitor(); return true; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java index 4f8bb353a..5effa06c0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.peripheral.monitor; -import com.mojang.blaze3d.platform.GLX; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.TileEntityMonitorRenderer; @@ -73,22 +72,7 @@ public enum MonitorRenderer public static MonitorRenderer current() { MonitorRenderer current = ComputerCraft.monitorRenderer; - switch( current ) - { - case BEST: - return best(); - case VBO: - if( !GLX.useVbo() ) - { - ComputerCraft.log.warn( "VBOs are not supported on your graphics card. Falling back to default." ); - ComputerCraft.monitorRenderer = BEST; - return best(); - } - - return VBO; - default: - return current; - } + return current == MonitorRenderer.BEST ? best() : current; } private static MonitorRenderer best() From af40f5ae5cf8c1f9cedc8f825fee17bc6f2232e1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Apr 2020 11:11:02 +0100 Subject: [PATCH 189/711] Add back CraftTweaker integration --- build.gradle | 11 +- .../render_old/TileEntityCableRenderer.java | 141 ------------------ 2 files changed, 2 insertions(+), 150 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java diff --git a/build.gradle b/build.gradle index cc7521a21..ef72382cd 100644 --- a/build.gradle +++ b/build.gradle @@ -100,6 +100,8 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3:api") + compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.15.2:6.0.0.9") + runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' @@ -110,15 +112,6 @@ dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" } -sourceSets { - main { - java { - exclude 'dan200/computercraft/client/render_old' - exclude 'dan200/computercraft/shared/integration/crafttweaker' - } - } -} - // Compile tasks javadoc { diff --git a/src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java b/src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java deleted file mode 100644 index 66120e290..000000000 --- a/src/main/java/dan200/computercraft/client/render_old/TileEntityCableRenderer.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.client.render; - -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.systems.RenderSystem; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; -import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; -import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; -import dan200.computercraft.shared.peripheral.modem.wired.TileCable; -import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.model.IBakedModel; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.renderer.tileentity.TileEntityRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.util.BlockRenderLayer; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.RayTraceResult; -import net.minecraft.world.World; -import net.minecraftforge.client.ForgeHooksClient; -import net.minecraftforge.client.model.data.EmptyModelData; -import org.lwjgl.opengl.GL11; - -import javax.annotation.Nonnull; -import java.util.Random; - -/** - * Render breaking animation only over part of a {@link TileCable}. - */ -public class TileEntityCableRenderer extends TileEntityRenderer -{ - private static final ResourceLocation[] DESTROY_STAGES = new ResourceLocation[10]; - private static final Random random = new Random(); - - static - { - for( int i = 0; i < DESTROY_STAGES.length; i++ ) - { - DESTROY_STAGES[i] = new ResourceLocation( "block/destroy_stage_" + i ); - } - } - - @Override - public void render( @Nonnull TileCable te, double x, double y, double z, float partialTicks, int destroyStage ) - { - if( destroyStage < 0 ) return; - - BlockPos pos = te.getPos(); - - Minecraft mc = Minecraft.getInstance(); - - RayTraceResult hit = mc.objectMouseOver; - if( hit == null || hit.getType() != RayTraceResult.Type.BLOCK || !((BlockRayTraceResult) hit).getPos().equals( pos ) ) - { - return; - } - - World world = te.getWorld(); - BlockState state = world.getBlockState( pos ); - Block block = state.getBlock(); - if( block != ComputerCraft.Blocks.cable ) return; - - state = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) - ? block.getDefaultState().with( BlockCable.MODEM, state.get( BlockCable.MODEM ) ) - : state.with( BlockCable.MODEM, CableModemVariant.None ); - - IBakedModel model = mc.getBlockRendererDispatcher().getModelForState( state ); - - preRenderDamagedBlocks(); - - ForgeHooksClient.setRenderLayer( block.getRenderLayer() ); - - // See BlockRendererDispatcher#renderBlockDamage - TextureAtlasSprite breakingTexture = mc.getTextureMap().getSprite( DESTROY_STAGES[destroyStage] ); - - BufferBuilder buffer = Tessellator.getInstance().getBuffer(); - buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.BLOCK ); - buffer.setTranslation( x - pos.getX(), y - pos.getY(), z - pos.getZ() ); - buffer.noColor(); - - mc.getBlockRendererDispatcher().getBlockModelRenderer().renderModel( - world, - ForgeHooksClient.getDamageModel( model, breakingTexture, state, world, pos, 0 ), - state, pos, buffer, true, random, state.getPositionRandom( pos ), EmptyModelData.INSTANCE - ); - - ForgeHooksClient.setRenderLayer( BlockRenderLayer.SOLID ); - - buffer.setTranslation( 0, 0, 0 ); - Tessellator.getInstance().draw(); - - postRenderDamagedBlocks(); - } - - /** - * Set up the state for rendering block-breaking progress. - * - * @see WorldRenderer#preRenderDamagedBlocks() - */ - private void preRenderDamagedBlocks() - { - RenderSystem.disableLighting(); - - RenderSystem.enableBlend(); - RenderSystem.blendFuncSeparate( GlStateManager.SourceFactor.DST_COLOR, GlStateManager.DestFactor.SRC_COLOR, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO ); - RenderSystem.enableBlend(); - RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 0.5F ); - RenderSystem.polygonOffset( -3.0F, -3.0F ); - RenderSystem.enablePolygonOffset(); - RenderSystem.alphaFunc( 516, 0.1F ); - RenderSystem.enableAlphaTest(); - RenderSystem.pushMatrix(); - } - - /** - * Tear down the state for rendering block-breaking progress. - * - * @see WorldRenderer#postRenderDamagedBlocks() - */ - private void postRenderDamagedBlocks() - { - RenderSystem.disableAlphaTest(); - RenderSystem.polygonOffset( 0.0F, 0.0F ); - RenderSystem.disablePolygonOffset(); - RenderSystem.disablePolygonOffset(); - RenderSystem.depthMask( true ); - RenderSystem.popMatrix(); - } -} From 2f42a4e85b7b905b4d4cc1842044b290eacbcee0 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 22 Apr 2020 14:39:39 +0100 Subject: [PATCH 190/711] Add documentation for shell and multishell Heh, one place we're more complete than cc.cc :p. --- doc/styles.css | 2 +- illuaminate.sexp | 62 +++-- .../assets/computercraft/lua/bios.lua | 5 +- .../computercraft/lua/rom/apis/disk.lua | 2 +- .../computercraft/lua/rom/apis/settings.lua | 4 +- .../rom/modules/main/cc/shell/completion.lua | 9 +- .../lua/rom/programs/advanced/multishell.lua | 76 ++++- .../computercraft/lua/rom/programs/shell.lua | 263 +++++++++++++++--- 8 files changed, 339 insertions(+), 84 deletions(-) diff --git a/doc/styles.css b/doc/styles.css index ef14a7d94..436a8c535 100644 --- a/doc/styles.css +++ b/doc/styles.css @@ -23,7 +23,7 @@ body { "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } -code, pre, .parameter, .type, .definition-name, .reference { +code, pre, .parameter, .type, .definition-name, .reference-code { font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; } diff --git a/illuaminate.sexp b/illuaminate.sexp index f727a3a8e..32acc06de 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -2,8 +2,8 @@ (sources /doc/stub/ - /src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/ + /src/main/resources/*/computercraft/lua/bios.lua + /src/main/resources/*/computercraft/lua/rom/ /src/test/resources/test-rom) @@ -15,13 +15,13 @@ (library-path /doc/stub/ - /src/main/resources/assets/computercraft/lua/rom/apis - /src/main/resources/assets/computercraft/lua/rom/apis/command - /src/main/resources/assets/computercraft/lua/rom/apis/turtle + /src/main/resources/*/computercraft/lua/rom/apis + /src/main/resources/*/computercraft/lua/rom/apis/command + /src/main/resources/*/computercraft/lua/rom/apis/turtle - /src/main/resources/assets/computercraft/lua/rom/modules/main - /src/main/resources/assets/computercraft/lua/rom/modules/command - /src/main/resources/assets/computercraft/lua/rom/modules/turtle)) + /src/main/resources/*/computercraft/lua/rom/modules/main + /src/main/resources/*/computercraft/lua/rom/modules/command + /src/main/resources/*/computercraft/lua/rom/modules/turtle)) (at / (linters @@ -35,9 +35,7 @@ ;; be good to find a compromise in the future, but this works for now. -var:unused-arg - ;; Suppress a couple of documentation comments warnings for now. We'll - ;; hopefully be able to remove them in the future. - -doc:undocumented -doc:undocumented-arg -doc:unresolved-reference + ;; Some APIS (keys, colour and os mainly) are incomplete right now. -var:unresolved-member) (lint (bracket-spaces @@ -50,8 +48,8 @@ ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. (at - (/src/main/resources/assets/computercraft/lua/bios.lua - /src/main/resources/assets/computercraft/lua/rom/apis/) + (/src/main/resources/*/computercraft/lua/bios.lua + /src/main/resources/*/computercraft/lua/rom/apis/) (linters -var:unused-global) (lint (allow-toplevel-global true))) @@ -60,19 +58,27 @@ (linters -var:unused-global) (lint (allow-toplevel-global true))) -;; Ensure any fully documented modules stay fully documented. +;; Suppress warnings for currently undocumented modules. (at - (/src/main/resources/assets/computercraft/lua/rom/apis/colors.lua - /src/main/resources/assets/computercraft/lua/rom/apis/colours.lua - /src/main/resources/assets/computercraft/lua/rom/apis/disk.lua - /src/main/resources/assets/computercraft/lua/rom/apis/gps.lua - /src/main/resources/assets/computercraft/lua/rom/apis/help.lua - /src/main/resources/assets/computercraft/lua/rom/apis/keys.lua - /src/main/resources/assets/computercraft/lua/rom/apis/paintutils.lua - /src/main/resources/assets/computercraft/lua/rom/apis/parallel.lua - /src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua - /src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua - /src/main/resources/assets/computercraft/lua/rom/apis/settings.lua - /src/main/resources/assets/computercraft/lua/rom/apis/texutils.lua - /src/main/resources/assets/computercraft/lua/rom/apis/vector.lua) - (linters doc:undocumented doc:undocumented-arg)) + (/doc/stub/commands.lua + /doc/stub/fs.lua + /doc/stub/http.lua + /doc/stub/os.lua + /doc/stub/redstone.lua + /doc/stub/term.lua + /doc/stub/turtle.lua + /src/main/resources/*/computercraft/lua/rom/apis/command/commands.lua + /src/main/resources/*/computercraft/lua/rom/apis/io.lua + /src/main/resources/*/computercraft/lua/rom/apis/window.lua + /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua) + + (linters -doc:undocumented -doc:undocumented-arg)) + +;; These currently rely on unknown references. +(at + (/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua + /src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua + /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua + /src/main/resources/*/computercraft/lua/rom/programs/advanced/multishell.lua + /src/main/resources/*/computercraft/lua/rom/programs/shell.lua) + (linters -doc:unresolved-reference)) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index f1e80cef4..a2f737416 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -521,14 +521,11 @@ function os.run(_tEnv, _sPath, ...) expect(1, _tEnv, "table") expect(2, _sPath, "string") - local tArgs = table.pack(...) local tEnv = _tEnv setmetatable(tEnv, { __index = _G }) local fnFile, err = loadfile(_sPath, nil, tEnv) if fnFile then - local ok, err = pcall(function() - fnFile(table.unpack(tArgs, 1, tArgs.n)) - end) + local ok, err = pcall(fnFile, ...) if not ok then if err and err ~= "" then printError(err) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua index fcc907121..9e136b22c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/disk.lua @@ -106,7 +106,7 @@ end -- This generally returns the same as @{disk.getLabel} for records. -- -- @tparam string name The name of the disk drive. --- @treturn string|false|nil The track title, `false` if there is not a music +-- @treturn string|false|nil The track title, @{false} if there is not a music -- record in the drive or `nil` if no drive is present. function getAudioTitle(name) if isDrive(name) then diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index c1fcb45f6..f9925d36f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -32,7 +32,7 @@ for _, v in ipairs(valid_types) do valid_types[v] = true end -- you to provide defaults and additional metadata. -- -- @tparam string name The name of this option --- @tparam[opt] { description? = string, default? = value, type? = string } options +-- @tparam[opt] { description? = string, default? = any, type? = string } options -- Options for this setting. This table accepts the following fields: -- -- - `description`: A description which may be printed when running the `set` program. @@ -127,7 +127,7 @@ end --- Get details about a specific setting. -- -- @tparam string name The name of the setting to get. --- @treturn { description? = string, default? = value, type? = string, value? = value } +-- @treturn { description? = string, default? = any, type? = string, value? = any } -- Information about this setting. This includes all information from @{settings.define}, -- as well as this setting's value. function getDetails(name) diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua index d89c72a91..6be54fe2f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -16,7 +16,7 @@ local completion = require "cc.completion" --- Complete the name of a file relative to the current working directory. -- --- @tparam shell shell The shell we're completing in +-- @tparam table shell The shell we're completing in -- @tparam { string... } choices The list of choices to complete from. -- @treturn { string... } A list of suffixes of matching files. local function file(shell, text) @@ -25,7 +25,7 @@ end --- Complete the name of a directory relative to the current working directory. -- --- @tparam shell shell The shell we're completing in +-- @tparam table shell The shell we're completing in -- @tparam { string... } choices The list of choices to complete from. -- @treturn { string... } A list of suffixes of matching directories. local function dir(shell, text) @@ -35,7 +35,7 @@ end --- Complete the name of a file or directory relative to the current working -- directory. -- --- @tparam shell shell The shell we're completing in +-- @tparam table shell The shell we're completing in -- @tparam { string... } choices The list of choices to complete from. -- @tparam { string... } previous The shell arguments before this one. -- @tparam[opt] boolean add_space Whether to add a space after the completed item. @@ -61,9 +61,10 @@ end --- Complete the name of a program. -- --- @tparam shell shell The shell we're completing in +-- @tparam table shell The shell we're completing in -- @tparam { string... } choices The list of choices to complete from. -- @treturn { string... } A list of suffixes of matching programs. +-- @see shell.completeProgram local function program(shell, text) return shell.completeProgram(text) end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua index c675f2dc6..1ff73ab9f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/multishell.lua @@ -1,3 +1,21 @@ +--- Multishell allows multiple programs to be run at the same time. +-- +-- When multiple programs are running, it displays a tab bar at the top of the +-- screen, which allows you to switch between programs. New programs can be +-- launched using the `fg` or `bg` programs, or using the @{shell.openTab} and +-- @{multishell.launch} functions. +-- +-- Each process is identified by its ID, which corresponds to its position in +-- the tab list. As tabs may be opened and closed, this ID is _not_ constant +-- over a program's run. As such, be careful not to use stale IDs. +-- +-- As with @{shell}, @{multishell} is not a "true" API. Instead, it is a +-- standard program, which launches a shell and injects its API into the shell's +-- environment. This API is not available in the global environment, and so is +-- not available to @{os.loadAPI|APIs}. +-- +-- @module[module] multishell + local expect = dofile("rom/modules/main/cc/expect.lua").expect -- Setup process switching @@ -190,12 +208,26 @@ local function setMenuVisible(bVis) end end -local multishell = {} +local multishell = {} --- @export +--- Get the currently visible process. This will be the one selected on +-- the tab bar. +-- +-- Note, this is different to @{getCurrent}, which returns the process which is +-- currently executing. +-- +-- @treturn number The currently visible process's index. +-- @see setFocus function multishell.getFocus() return nCurrentProcess end +--- Change the currently visible process. +-- +-- @tparam number n The process index to switch to. +-- @treturn boolean If the process was changed successfully. This will +-- return @{false} if there is no process with this id. +-- @see getFocus function multishell.setFocus(n) expect(1, n, "number") if n >= 1 and n <= #tProcesses then @@ -206,6 +238,13 @@ function multishell.setFocus(n) return false end +--- Get the title of the given tab. +-- +-- This starts as the name of the program, but may be changed using +-- @{multishell.setTitle}. +-- @tparam number n The process index. +-- @treturn string|nil The current process title, or @{nil} if the +-- process doesn't exist. function multishell.getTitle(n) expect(1, n, "number") if n >= 1 and n <= #tProcesses then @@ -214,19 +253,45 @@ function multishell.getTitle(n) return nil end -function multishell.setTitle(n, sTitle) +--- Set the title of the given process. +-- +-- @tparam number n The process index. +-- @tparam string title The new process title. +-- @see getTitle +-- @usage Change the title of the current process +-- +-- multishell.setTitle(multishell.getCurrent(), "Hello") +function multishell.setTitle(n, title) expect(1, n, "number") - expect(2, sTitle, "string") + expect(2, title, "string") if n >= 1 and n <= #tProcesses then - setProcessTitle(n, sTitle) + setProcessTitle(n, title) redrawMenu() end end +--- Get the index of the currently running process. +-- +-- @treturn number The currently running process. function multishell.getCurrent() return nRunningProcess end +--- Start a new process, with the given environment, program and arguments. +-- +-- The returned process index is not constant over the program's run. It can be +-- safely used immediately after launching (for instance, to update the title or +-- switch to that tab). However, after your program has yielded, it may no +-- longer be correct. +-- +-- @tparam table tProgramEnv The environment to load the path under. +-- @tparam string sProgramPath The path to the program to run. +-- @param ... Additional arguments to pass to the program. +-- @treturn number The index of the created process. +-- @see os.run +-- @usage Run the "hello" program, and set its title to "Hello!" +-- local id = multishell.launch({}, "/rom/programs/fun/hello.lua") +-- multishell.setTitle(id, "Hello!") function multishell.launch(tProgramEnv, sProgramPath, ...) expect(1, tProgramEnv, "table") expect(2, sProgramPath, "string") @@ -238,6 +303,9 @@ function multishell.launch(tProgramEnv, sProgramPath, ...) return nResult end +--- Get the number of processes within this multishell. +-- +-- @treturn number The number of processes. function multishell.getCount() return #tProcesses end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 0d4b9f337..c36cc9abf 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -1,3 +1,15 @@ +--- The shell API provides access to CraftOS's command line interface. +-- +-- It allows you to @{run|start programs}, @{setCompletionFunction|add +-- completion for a program}, and much more. +-- +-- @{shell} is not a "true" API. Instead, it is a standard program, which its +-- API into the programs that it launches. This allows for multiple shells to +-- run at the same time, but means that the API is not available in the global +-- environment, and so is unavailable to other @{os.loadAPI|APIs}. +-- +-- @module[module] shell + local expect = dofile("rom/modules/main/cc/expect.lua").expect local multishell = multishell @@ -15,7 +27,7 @@ local tAliases = parentShell and parentShell.aliases() or {} local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {} local tProgramStack = {} -local shell = {} +local shell = {} --- @export local function createShellEnv(sDir) local tEnv = {} tEnv.shell = shell @@ -172,6 +184,18 @@ local function tokenise(...) end -- Install shell API + +--- Run a program with the supplied arguments. +-- +-- All arguments are concatenated together and then parsed as a command line. As +-- a result, `shell.run("program a b")` is the same as `shell.run("program", +-- "a", "b")`. +-- +-- @tparam string ... The program to run and its arguments. +-- @treturn boolean Whether the program exited successfully. +-- @usage Run `paint my-image` from within your program: +-- +-- shell.run("paint", "my-image") function shell.run(...) local tWords = tokenise(...) local sCommand = tWords[1] @@ -181,38 +205,83 @@ function shell.run(...) return false end +--- Exit the current shell. +-- +-- This does _not_ terminate your program, it simply makes the shell terminate +-- after your program has finished. If this is the toplevel shell, then the +-- computer will be shutdown. function shell.exit() bExit = true end +--- Return the current working directory. This is what is displayed before the +-- `> ` of the shell prompt, and is used by @{shell.resolve} to handle relative +-- paths. +-- +-- @treturn string The current working directory. +-- @see setDir To change the working directory. function shell.dir() return sDir end -function shell.setDir(_sDir) - expect(1, _sDir, "string") - if not fs.isDir(_sDir) then +--- Set the current working directory. +-- +-- @tparam string dir The new working directory. +-- @throws If the path does not exist or is not a directory. +-- @usage Set the working directory to "rom" +-- +-- shell.setDir("rom") +function shell.setDir(dir) + expect(1, dir, "string") + if not fs.isDir(dir) then error("Not a directory", 2) end - sDir = fs.combine(_sDir, "") + sDir = fs.combine(dir, "") end +--- Set the path where programs are located. +-- +-- The path is composed of a list of directory names in a string, each separated +-- by a colon (`:`). On normal turtles will look in the current directory (`.`), +-- `/rom/programs` and `/rom/programs/turtle` folder, making the path +-- `.:/rom/programs:/rom/programs/turtle`. +-- +-- @treturn string The current shell's path. +-- @see setPath To change the current path. function shell.path() return sPath end -function shell.setPath(_sPath) - expect(1, _sPath, "string") - sPath = _sPath +--- Set the @{path|current program path}. +-- +-- Be careful to prefix directories with a `/`. Otherwise they will be searched +-- for from the @{shell.dir|current directory}, rather than the computer's root. +-- +-- @tparam string path The new program path. +function shell.setPath(path) + expect(1, path, "string") + sPath = path end -function shell.resolve(_sPath) - expect(1, _sPath, "string") - local sStartChar = string.sub(_sPath, 1, 1) +--- Resolve a relative path to an absolute path. +-- +-- The @{fs} and @{io} APIs work using absolute paths, and so we must convert +-- any paths relative to the @{dir|current directory} to absolute ones. This +-- does nothing when the path starts with `/`. +-- +-- @tparam string path The path to resolve. +-- @usage Resolve `startup.lua` when in the `rom` folder. +-- +-- shell.setDir("rom") +-- print(shell.resolve("startup.lua")) +-- -- => rom/startup.lua +function shell.resolve(path) + expect(1, path, "string") + local sStartChar = string.sub(path, 1, 1) if sStartChar == "/" or sStartChar == "\\" then - return fs.combine("", _sPath) + return fs.combine("", path) else - return fs.combine(sDir, _sPath) + return fs.combine(sDir, path) end end @@ -226,16 +295,25 @@ local function pathWithExtension(_sPath, _sExt) return _sPath .. "." .. _sExt end -function shell.resolveProgram(_sCommand) - expect(1, _sCommand, "string") +--- Resolve a program, using the @{path|program path} and list of @{aliases|aliases}. +-- +-- @tparam string command The name of the program +-- @treturn string|nil The absolute path to the program, or @{nil} if it could +-- not be found. +-- @usage Locate the `hello` program. +-- +-- shell.resolveProgram("hello") +-- -- => rom/programs/fun/hello.lua +function shell.resolveProgram(command) + expect(1, command, "string") -- Substitute aliases firsts - if tAliases[_sCommand] ~= nil then - _sCommand = tAliases[_sCommand] + if tAliases[command] ~= nil then + command = tAliases[command] end -- If the path is a global path, use it directly - if _sCommand:find("/") or _sCommand:find("\\") then - local sPath = shell.resolve(_sCommand) + if command:find("/") or command:find("\\") then + local sPath = shell.resolve(command) if fs.exists(sPath) and not fs.isDir(sPath) then return sPath else @@ -249,7 +327,7 @@ function shell.resolveProgram(_sCommand) -- Otherwise, look on the path variable for sPath in string.gmatch(sPath, "[^:]+") do - sPath = fs.combine(shell.resolve(sPath), _sCommand) + sPath = fs.combine(shell.resolve(sPath), command) if fs.exists(sPath) and not fs.isDir(sPath) then return sPath else @@ -264,7 +342,15 @@ function shell.resolveProgram(_sCommand) return nil end -function shell.programs(_bIncludeHidden) +--- Return a list of all programs on the @{shell.path|path}. +-- +-- @tparam[opt] boolean include_hidden Include hidden files. Namely, any which +-- start with `.`. +-- @treturn { string } A list of available programs. +-- @usage textutils.tabulate(shell.programs()) +function shell.programs(include_hidden) + expect(1, include_hidden, "boolean", "nil") + local tItems = {} -- Add programs from the path @@ -275,7 +361,7 @@ function shell.programs(_bIncludeHidden) for n = 1, #tList do local sFile = tList[n] if not fs.isDir(fs.combine(sPath, sFile)) and - (_bIncludeHidden or string.sub(sFile, 1, 1) ~= ".") then + (include_hidden or string.sub(sFile, 1, 1) ~= ".") then if #sFile > 4 and sFile:sub(-4) == ".lua" then sFile = sFile:sub(1, -5) end @@ -351,6 +437,21 @@ local function completeProgramArgument(sProgram, nArgument, sPart, tPreviousPart return nil end +--- Complete a shell command line. +-- +-- This accepts an incomplete command, and completes the program name or +-- arguments. For instance, `l` will be completed to `ls`, and `ls ro` will be +-- completed to `ls rom/`. +-- +-- Completion handlers for your program may be registered with +-- @{shell.setCompletionFunction}. +-- +-- @tparam string sLine The input to complete. +-- @treturn { string }|nil The list of possible completions. +-- @see read For more information about completion. +-- @see shell.completeProgram +-- @see shell.setCompletionFunction +-- @see shell.getCompletionInfo function shell.complete(sLine) expect(1, sLine, "string") if #sLine > 0 then @@ -388,23 +489,66 @@ function shell.complete(sLine) return nil end -function shell.completeProgram(sProgram) - expect(1, sProgram, "string") - return completeProgram(sProgram) +--- Complete the name of a program. +-- +-- @tparam string program The name of a program to complete. +-- @treturn { string } A list of possible completions. +-- @see cc.shell.completion.program +function shell.completeProgram(program) + expect(1, program, "string") + return completeProgram(program) end -function shell.setCompletionFunction(sProgram, fnComplete) - expect(1, sProgram, "string") - expect(2, fnComplete, "function") - tCompletionInfo[sProgram] = { - fnComplete = fnComplete, +--- Set the completion function for a program. When the program is entered on +-- the command line, this program will be called to provide auto-complete +-- information. +-- +-- The completion function accepts four arguments: +-- +-- 1. The current shell. As completion functions are inherited, this is not +-- guaranteed to be the shell you registered this function in. +-- 2. The index of the argument currently being completed. +-- 3. The current argument. This may be the empty string. +-- 4. A list of the previous arguments. +-- +-- For instance, when completing `pastebin put rom/st` our pastebin completion +-- function will receive the shell API, an index of 2, `rom/st` as the current +-- argument, and a "previous" table of `{ "put" }`. This function may then wish +-- to return a table containing `artup.lua`, indicating the entire command +-- should be completed to `pastebin put rom/startup.lua`. +-- +-- You completion entries may also be followed by a space, if you wish to +-- indicate another argument is expected. +-- +-- @tparam string program The path to the program. This should be an absolute path +-- _without_ the leading `/`. +-- @tparam function(shell: table, index: number, argument: string, previous: { string }):({ string }|nil) complete +-- The completion function. +-- @see cc.shell.completion Various utilities to help with writing completion functions. +-- @see shell.complete +-- @see read For more information about completion. +function shell.setCompletionFunction(program, complete) + expect(1, program, "string") + expect(2, complete, "function") + tCompletionInfo[program] = { + fnComplete = complete, } end +--- Get a table containing all completion functions. +-- +-- This should only be needed when building custom shells. Use +-- @{setCompletionFunction} to add a completion function. +-- +-- @treturn { [string] = { fnComplete = function } } A table mapping the +-- absolute path of programs, to their completion functions. function shell.getCompletionInfo() return tCompletionInfo end +--- Returns the path to the currently running program. +-- +-- @treturn string The absolute path to the running program. function shell.getRunningProgram() if #tProgramStack > 0 then return tProgramStack[#tProgramStack] @@ -412,17 +556,38 @@ function shell.getRunningProgram() return nil end -function shell.setAlias(_sCommand, _sProgram) - expect(1, _sCommand, "string") - expect(2, _sProgram, "string") - tAliases[_sCommand] = _sProgram +--- Add an alias for a program. +-- +-- @tparam string command The name of the alias to add. +-- @tparam string program The name or path to the program. +-- @usage Alias `vim` to the `edit` program +-- +-- shell.setAlias("vim", "edit") +function shell.setAlias(command, program) + expect(1, command, "string") + expect(2, program, "string") + tAliases[command] = program end -function shell.clearAlias(_sCommand) - expect(1, _sCommand, "string") - tAliases[_sCommand] = nil +--- Remove an alias. +-- +-- @tparam string command The alias name to remove. +function shell.clearAlias(command) + expect(1, command, "string") + tAliases[command] = nil end +--- Get the current aliases for this shell. +-- +-- Aliases are used to allow multiple commands to refer to a single program. For +-- instance, the `list` program is aliased `dir` or `ls`. Running `ls`, `dir` or +-- `list` in the shell will all run the `list` program. +-- +-- @treturn { [string] = string } A table, where the keys are the names of +-- aliases, and the values are the path to the program. +-- @see shell.setAlias +-- @see shell.resolveProgram This uses aliases when resolving a program name to +-- an absolute path. function shell.aliases() -- Copy aliases local tCopy = {} @@ -433,6 +598,20 @@ function shell.aliases() end if multishell then + --- Open a new @{multishell} tab running a command. + -- + -- This behaves similarly to @{shell.run}, but instead returns the process + -- index. + -- + -- This function is only available if the @{multishell} API is. + -- + -- @tparam string ... The command line to run. + -- @see shell.run + -- @see multishell.launch + -- @usage Launch the Lua interpreter and switch to it. + -- + -- local id = shell.openTab("lua") + -- shell.switchTab(id) function shell.openTab(...) local tWords = tokenise(...) local sCommand = tWords[1] @@ -448,9 +627,13 @@ if multishell then end end - function shell.switchTab(nID) - expect(1, nID, "number") - multishell.setFocus(nID) + --- Switch to the @{multishell} tab with the given index. + -- + -- @tparam number id The tab to switch to. + -- @see multishell.setFocus + function shell.switchTab(id) + expect(1, id, "number") + multishell.setFocus(id) end end From 7f57a977a1c6134d5570ce36492fc7c738abc9c5 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 22 Apr 2020 14:48:42 +0100 Subject: [PATCH 191/711] Make the CF link https on tweaked.cc It doesn't play nice on GH, but we need it on our actual website. --- doc/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/index.md b/doc/index.md index c22acd230..9aca61855 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,4 +1,4 @@ -# ![CC: Tweaked](logo.png) [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") +# ![CC: Tweaked](logo.png) [![Download CC: Tweaked on CurseForge](https://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") CC: Tweaked is a fork of [ComputerCraft], adding programmable computers, turtles and more to Minecraft. From da419b24e701229eee3afa06315969c5d2a4f972 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 22 Apr 2020 17:44:13 +0100 Subject: [PATCH 192/711] Enable motd on non-pocket and command computers - I'm excluding pocket computers, as they have such a tiny screen I'm not sure the screen estate is worth it. Pocket computers /generally/ aren't people's starter machine, so I think this is fine. - Prune the motd list, and try to make them a little shorter. I think this list is more of the interesting ones. We can modify this list in the future, as we get more feedback.[^1] - Also fix paint/edit not adding an extension when they should. This was caused by the settings rewrite, as the explicitly provided default shadowed the one provided by bios.lua. [^1]: ~5 months ago I asked for some feedback about enabling motds by default. I only got something constructive back today >_>. --- .../assets/computercraft/lua/bios.lua | 2 +- .../assets/computercraft/lua/rom/motd.txt | 36 +++++-------------- .../computercraft/lua/rom/programs/edit.lua | 2 +- .../lua/rom/programs/fun/advanced/paint.lua | 2 +- 4 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index a2f737416..687c9c798 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -923,7 +923,7 @@ settings.define("list.show_hidden", { }) settings.define("motd.enable", { - default = false, + default = pocket == nil, description = "Display a random message when the computer starts up.", type = "boolean", }) diff --git a/src/main/resources/assets/computercraft/lua/rom/motd.txt b/src/main/resources/assets/computercraft/lua/rom/motd.txt index 87f3f0503..8c8f16945 100644 --- a/src/main/resources/assets/computercraft/lua/rom/motd.txt +++ b/src/main/resources/assets/computercraft/lua/rom/motd.txt @@ -1,43 +1,23 @@ -View the source code at https://github.com/SquidDev-CC/CC-Tweaked +Please report bugs at https://github.com/SquidDev-CC/CC-Tweaked. Thanks! View the documentation at https://wiki.computercraft.cc -Visit the forum at https://forums.computercraft.cc +Show off your programs or ask for help at our forum: https://forums.computercraft.cc You can disable these messages by running "set motd.enable false". -You can create directories with "mkdir". -Want to see hidden files? Run "set list.show_hidden true". -Run "list" or "ls" to see all files in a directory. -You can delete files and directories with "delete" or "rm". Use "pastebin put" to upload a program to pastebin. -Use "pastebin get" to download a program from pastebin. -Use "pastebin run" to run a program from pastebin. Use the "edit" program to create and edit your programs. -You can copy files with "copy" or "cp". -You can use "wget run " to run a program from the internet. You can use "wget" to download a file from the internet. On an advanced computer you can use "fg" or "bg" to run multiple programs at the same time. -Use "type" to see if a path is a file or a directory. -Get a list of all programs with "programs". Use an advanced computer to use colours and the mouse. With a speaker you can play sounds. -Use "motd" to print the Message of the Day. -You can disable the startup from a computer with "set shell.allow_startup false". -You can disable the startup from a disk with "set shell.allow_disk_startup false". Programs that are placed in the "startup" folder in the root of a computer are started on boot. Use a modem to connect with other computers. With the "gps" program you can get the position of a computer. Use "monitor" to run a program on a attached monitor. -View all attached peripherals with "peripherals". -Use "time" to see the in-game time. -You can set the label of a computer with "label set". -A computer needs a label to keep its files if it is destroyed. -You can disable auto completion in the shell with "set shell.autocomplete false". -You can disable auto completion in edit with "set edit.autocomplete false". +Don't forget to label your computer with "label set". Feeling creative? Use a printer to print a book! -Files beginning with a "." character are hidden from "list" by default. +Files beginning with a "." are hidden from "list" by default. Running "set" lists the current values of all settings. -Some programs are only available on advanced computers, turtles, pocket computers, or command computers. -The "equip" and "unequip" programs let you add or remove supported upgrades from a turtle or pocket computer without crafting. -You can change the color of a disk by crafting it with dye. -Right-clicking a turtle with a dye changes its color. +Some programs are only available on advanced computers, turtles, pocket computers or command computers. +The "equip" programs let you add upgrades to a turtle without crafting. +You can change the color of a disk by crafting or right clicking it with dye. You can print on a printed page again to get multiple colors. -Holding the Control and T keys terminates the running program. -Holding Control and S or R shuts down or reboots the computer you are using. +Holding the Ctrl and T keys terminates the running program. diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index a6ea4d8d0..9e57effd1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -15,7 +15,7 @@ end -- Create .lua files by default if not fs.exists(sPath) and not string.find(sPath, "%.") then - local sExtension = settings.get("edit.default_extension", "") + local sExtension = settings.get("edit.default_extension") if sExtension ~= "" and type(sExtension) == "string" then sPath = sPath .. "." .. sExtension end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index fbe228091..08ac53116 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -46,7 +46,7 @@ end -- Create .nfp files by default if not fs.exists(sPath) and not string.find(sPath, "%.") then - local sExtension = settings.get("paint.default_extension", "") + local sExtension = settings.get("paint.default_extension") if sExtension ~= "" and type(sExtension) == "string" then sPath = sPath .. "." .. sExtension end From 9748679484d45f72a739c045b2afaac10fb6b160 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Thu, 23 Apr 2020 10:33:35 +0200 Subject: [PATCH 193/711] Add mouse support for the menu in edit and paint (#419) --- .../computercraft/lua/rom/programs/edit.lua | 28 +++++- .../lua/rom/programs/fun/advanced/paint.lua | 89 ++++++++++++------- 2 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua index 9e57effd1..007f37a24 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/edit.lua @@ -61,7 +61,12 @@ if peripheral.find("printer") then end table.insert(tMenuItems, "Exit") -local sStatus = "Press Ctrl to access menu" +local sStatus +if term.isColour() then + sStatus = "Press Ctrl or click here to access menu" +else + sStatus = "Press Ctrl to access menu" +end if #sStatus > w - 5 then sStatus = "Press Ctrl for menu" end @@ -725,16 +730,35 @@ while bRunning do end elseif sEvent == "mouse_click" then + local cx, cy = param2, param3 if not bMenu then if param == 1 then -- Left click - local cx, cy = param2, param3 if cy < h then local newY = math.min(math.max(scrollY + cy, 1), #tLines) local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1) setCursor(newX, newY) + else + bMenu = true + redrawMenu() end end + else + if cy == h then + local nMenuPosEnd = 1 + local nMenuPosStart = 1 + for n, sMenuItem in ipairs(tMenuItems) do + nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1 + if cx > nMenuPosStart and cx < nMenuPosEnd then + doMenuItem(n) + end + nMenuPosEnd = nMenuPosEnd + 1 + nMenuPosStart = nMenuPosEnd + end + else + bMenu = false + redrawMenu() + end end elseif sEvent == "mouse_scroll" then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua index 08ac53116..b7c44526a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -19,7 +19,7 @@ local canvas = {} local mChoices = { "Save", "Exit" } -- The message displayed in the footer bar -local fMessage = "Press Ctrl to access menu" +local fMessage = "Press Ctrl or click here to access menu" ------------------------- -- Initialisation -- @@ -252,6 +252,29 @@ local function drawCanvas() end end +local menu_choices = { + Save = function() + if bReadOnly then + fMessage = "Access denied" + return false + end + local success, err = save(sPath) + if success then + fMessage = "Saved to " .. sPath + else + if err then + fMessage = "Error saving to " .. err + else + fMessage = "Error saving to " .. sPath + end + end + return false + end, + Exit = function() + return true + end, +} + --[[ Draws menu options and handles input from within the menu. returns: true if the program is to be exited; false otherwise @@ -261,6 +284,7 @@ local function accessMenu() local selection = 1 term.setBackgroundColour(colours.black) + while true do -- Draw the menu term.setCursorPos(1, h) @@ -269,27 +293,28 @@ local function accessMenu() for k, v in pairs(mChoices) do if selection == k then term.setTextColour(colours.yellow) - local ox = term.getCursorPos() - term.write("[" .. string.rep(" ", #v) .. "]") - term.setCursorPos(ox + 1, h) + term.write("[") term.setTextColour(colours.white) term.write(v) - term.setCursorPos(term.getCursorPos() + 1, h) + term.setTextColour(colours.yellow) + term.write("]") + term.setTextColour(colours.white) else term.write(" " .. v .. " ") end end -- Handle input in the menu - local id, key = os.pullEvent("key") + local id, param1, param2, param3 = os.pullEvent() if id == "key" then - -- S and E are shortcuts - if key == keys.s then - selection = 1 - key = keys.enter - elseif key == keys.e then - selection = 2 - key = keys.enter + local key = param1 + + -- Handle menu shortcuts. + for _, menu_item in ipairs(mChoices) do + local k = keys[menu_item:sub(1, 1):lower()] + if k and k == key then + return menu_choices[menu_item]() + end end if key == keys.right then @@ -308,29 +333,25 @@ local function accessMenu() elseif key == keys.enter then -- Select an option - if mChoices[selection] == "Save" then - if bReadOnly then - fMessage = "Access denied" - return false - end - local success, err = save(sPath) - if success then - fMessage = "Saved to " .. sPath - else - if err then - fMessage = "Error saving to " .. err - else - fMessage = "Error saving to " .. sPath - end - end - return false - elseif mChoices[selection] == "Exit" then - return true - end + return menu_choices[mChoices[selection]]() elseif key == keys.leftCtrl or keys == keys.rightCtrl then -- Cancel the menu return false end + elseif id == "mouse_click" then + local cx, cy = param2, param3 + if cy ~= h then return false end -- Exit the menu + + local nMenuPosEnd = 1 + local nMenuPosStart = 1 + for _, sMenuItem in ipairs(mChoices) do + nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1 + if cx > nMenuPosStart and cx < nMenuPosEnd then + return menu_choices[sMenuItem]() + end + nMenuPosEnd = nMenuPosEnd + 1 + nMenuPosStart = nMenuPosEnd + end end end end @@ -378,6 +399,10 @@ local function handleEvents() canvas[p3][p2] = paintColour drawCanvasPixel(p2, p3) + elseif p3 == h and id == "mouse_click" then + -- Open menu + programActive = not accessMenu() + drawInterface() end elseif id == "key" then if p1 == keys.leftCtrl or p1 == keys.rightCtrl then From ae7ef66dfa19a752f3a3265b14a9996f776f9ddb Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 23 Apr 2020 09:56:56 +0100 Subject: [PATCH 194/711] Bump version Oh no. I don't want to have to beta test this :D:. --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 30 +++++++++++++++++++ .../computercraft/lua/rom/help/whatsnew.txt | 30 +++++++++++++++++-- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0f6aa539a..d61ef4e0f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.86.2 +mod_version=1.87.0 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index ae073d005..36a482fb4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,33 @@ +# New features in CC: Tweaked 1.87.0 + +* Add documentation to many Lua functions. This is published online at https://tweaked.cc/. +* Replace to pretty-printer in the Lua REPL. It now supports displaying functions and recursive tables. This printer is may be used within your own code through the `cc.pretty` module. +* Add `fs.getCapacity`. A complement to `fs.getFreeSpace`, this returns the capacity of the supplied drive. +* Add `fs.getAttributes`. This provides file size and type, as well as creation and modification time. +* Update Cobalt version. This backports several features from Lua 5.2 and 5.3: + - The `__len` metamethod may now be used by tables. + - Add `\z`, hexadecimal (`\x00`) and unicode (`\u0000`) string escape codes. + - Add `utf8` lib. + - Mirror Lua's behaviour of tail calls more closely. Native functions are no longer tail called, and tail calls are displayed in the stack trace. + - `table.unpack` now uses `__len` and `__index` metamethods. + - Parser errors now include the token where the error occured. +* Add `textutils.unserializeJSON`. This can be used to decode standard JSON and stringified-NBT. +* Switch the monitor renderer to use VBOs, providing a _significant_ performance boost in some cases. You can switch back to the display list renderer via the config. +* The `settings` API now allows "defining" settings. This allows settings to specify a default value and description. +* Enable the motd on non-pocket computers. +* Allow using the menu with the mouse in edit and paint (JakobDev). +* Add Danish and Korean translations (ChristianLW, mindy15963) +* Fire `mouse_up` events in the monitor program. +* Allow specifying a timeout to `websocket.receive`. +* Increase the maximimum limit for websocket messages. +* Optimise capacity checking of computer/disk folders. + +And several bug fixes: +* Fix turtle texture being incorrectly oriented (magiczocker10). +* Prevent copying folders into themselves. +* Fix race condition within ID assignment. +* Normalise file paths within shell.setDir (JakobDev) + # New features in CC: Tweaked 1.86.2 * Fix peripheral.getMethods returning an empty table diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 0ded4f8d3..29e395d9f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,5 +1,31 @@ -New features in CC: Tweaked 1.86.2 +New features in CC: Tweaked 1.87.0 -* Fix peripheral.getMethods returning an empty table +* Add documentation to many Lua functions. This is published online at https://tweaked.cc/. +* Replace to pretty-printer in the Lua REPL. It now supports displaying functions and recursive tables. This printer is may be used within your own code through the `cc.pretty` module. +* Add `fs.getCapacity`. A complement to `fs.getFreeSpace`, this returns the capacity of the supplied drive. +* Add `fs.getAttributes`. This provides file size and type, as well as creation and modification time. +* Update Cobalt version. This backports several features from Lua 5.2 and 5.3: + - The `__len` metamethod may now be used by tables. + - Add `\z`, hexadecimal (`\x00`) and unicode (`\u0000`) string escape codes. + - Add `utf8` lib. + - Mirror Lua's behaviour of tail calls more closely. Native functions are no longer tail called, and tail calls are displayed in the stack trace. + - `table.unpack` now uses `__len` and `__index` metamethods. + - Parser errors now include the token where the error occured. +* Add `textutils.unserializeJSON`. This can be used to decode standard JSON and stringified-NBT. +* Switch the monitor renderer to use VBOs, providing a _significant_ performance boost in some cases. You can switch back to the display list renderer via the config. +* The `settings` API now allows "defining" settings. This allows settings to specify a default value and description. +* Enable the motd on non-pocket computers. +* Allow using the menu with the mouse in edit and paint (JakobDev). +* Add Danish and Korean translations (ChristianLW, mindy15963) +* Fire `mouse_up` events in the monitor program. +* Allow specifying a timeout to `websocket.receive`. +* Increase the maximimum limit for websocket messages. +* Optimise capacity checking of computer/disk folders. + +And several bug fixes: +* Fix turtle texture being incorrectly oriented (magiczocker10). +* Prevent copying folders into themselves. +* Fix race condition within ID assignment. +* Normalise file paths within shell.setDir (JakobDev) Type "help changelog" to see the full version history. From 48cb032ddf444c04c86e6137b056fba7872826d9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 23 Apr 2020 10:54:12 +0100 Subject: [PATCH 195/711] Also publish on releases This'll probably break. Let's see :) --- .github/workflows/make-doc.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index 1d5e4605d..f1b728ad6 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -4,6 +4,8 @@ on: push: branches: [ master ] tags: + release: + types: [ published ] jobs: make_doc: From 08a0342618d37f2c042f2944b6616aca8acbc95d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 24 Apr 2020 16:41:46 +0100 Subject: [PATCH 196/711] Fix block drop data being generated in the incorrect place Fixes half of #421 --- build.gradle | 4 ++-- .../loot_tables/{ => blocks}/computer_advanced.json | 1 + .../loot_tables/{ => blocks}/computer_normal.json | 1 + .../computercraft/loot_tables/{ => blocks}/disk_drive.json | 1 + .../loot_tables/{ => blocks}/monitor_advanced.json | 1 + .../loot_tables/{ => blocks}/monitor_normal.json | 1 + .../computercraft/loot_tables/{ => blocks}/printer.json | 1 + .../computercraft/loot_tables/{ => blocks}/speaker.json | 1 + .../loot_tables/{ => blocks}/turtle_advanced.json | 1 + .../loot_tables/{ => blocks}/turtle_normal.json | 1 + .../loot_tables/{ => blocks}/wired_modem_full.json | 1 + .../loot_tables/{ => blocks}/wireless_modem_advanced.json | 1 + .../loot_tables/{ => blocks}/wireless_modem_normal.json | 1 + src/main/java/dan200/computercraft/data/LootTables.java | 6 ++++-- 14 files changed, 18 insertions(+), 4 deletions(-) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/computer_advanced.json (95%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/computer_normal.json (95%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/disk_drive.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/monitor_advanced.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/monitor_normal.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/printer.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/speaker.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/turtle_advanced.json (95%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/turtle_normal.json (95%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/wired_modem_full.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/wireless_modem_advanced.json (91%) rename src/generated/resources/data/computercraft/loot_tables/{ => blocks}/wireless_modem_normal.json (91%) diff --git a/build.gradle b/build.gradle index 51b822545..159eedfbd 100644 --- a/build.gradle +++ b/build.gradle @@ -48,7 +48,7 @@ minecraft { server { workingDirectory project.file('run') - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP' property 'forge.logging.console.level', 'debug' mods { @@ -60,7 +60,7 @@ minecraft { data { workingDirectory project.file('run') - property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP' + property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP' property 'forge.logging.console.level', 'debug' args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') diff --git a/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json similarity index 95% rename from src/generated/resources/data/computercraft/loot_tables/computer_advanced.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json index 09dac48f6..74fb9c725 100644 --- a/src/generated/resources/data/computercraft/loot_tables/computer_advanced.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/computer_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json similarity index 95% rename from src/generated/resources/data/computercraft/loot_tables/computer_normal.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json index 09dac48f6..74fb9c725 100644 --- a/src/generated/resources/data/computercraft/loot_tables/computer_normal.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/disk_drive.json b/src/generated/resources/data/computercraft/loot_tables/blocks/disk_drive.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/disk_drive.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/disk_drive.json index 675f3cf78..4bd0f0ea2 100644 --- a/src/generated/resources/data/computercraft/loot_tables/disk_drive.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/disk_drive.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json index e5c1b82b1..21e4fc349 100644 --- a/src/generated/resources/data/computercraft/loot_tables/monitor_advanced.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_advanced.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_normal.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/monitor_normal.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/monitor_normal.json index f27f7adcf..3e4d5df59 100644 --- a/src/generated/resources/data/computercraft/loot_tables/monitor_normal.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/monitor_normal.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/printer.json b/src/generated/resources/data/computercraft/loot_tables/blocks/printer.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/printer.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/printer.json index c632c9d67..e401a994b 100644 --- a/src/generated/resources/data/computercraft/loot_tables/printer.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/printer.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/speaker.json b/src/generated/resources/data/computercraft/loot_tables/blocks/speaker.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/speaker.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/speaker.json index 5b6d03f9a..90e5773e3 100644 --- a/src/generated/resources/data/computercraft/loot_tables/speaker.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/speaker.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json similarity index 95% rename from src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json index 09dac48f6..74fb9c725 100644 --- a/src/generated/resources/data/computercraft/loot_tables/turtle_advanced.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json similarity index 95% rename from src/generated/resources/data/computercraft/loot_tables/turtle_normal.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json index 09dac48f6..74fb9c725 100644 --- a/src/generated/resources/data/computercraft/loot_tables/turtle_normal.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json b/src/generated/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json index 02bd68624..cb2b02189 100644 --- a/src/generated/resources/data/computercraft/loot_tables/wired_modem_full.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/wired_modem_full.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json index 4f46d4b0f..03e30c572 100644 --- a/src/generated/resources/data/computercraft/loot_tables/wireless_modem_advanced.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_advanced.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json similarity index 91% rename from src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json rename to src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json index a9fdb21e7..30c49f858 100644 --- a/src/generated/resources/data/computercraft/loot_tables/wireless_modem_normal.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/wireless_modem_normal.json @@ -1,4 +1,5 @@ { + "type": "minecraft:block", "pools": [ { "name": "main", diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index f40295ccc..02db8551e 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -45,8 +45,9 @@ public class LootTables extends LootTableProvider private static void basicDrop( BiConsumer add, Block block ) { - add.accept( block.getRegistryName(), LootTable + add.accept( block.getLootTable(), LootTable .builder() + .setParameterSet( LootParameterSets.BLOCK ) .addLootPool( LootPool.builder() .name( "main" ) .rolls( ConstantRange.of( 1 ) ) @@ -57,8 +58,9 @@ public class LootTables extends LootTableProvider private static void computerDrop( BiConsumer add, Block block ) { - add.accept( block.getRegistryName(), LootTable + add.accept( block.getLootTable(), LootTable .builder() + .setParameterSet( LootParameterSets.BLOCK ) .addLootPool( LootPool.builder() .name( "main" ) .rolls( ConstantRange.of( 1 ) ) From b7c61f9c6d0f10cace21ce8dd09737a2150648b5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 24 Apr 2020 18:34:01 +0100 Subject: [PATCH 197/711] Bump version --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 4 +++ .../computercraft/lua/rom/help/whatsnew.txt | 31 ++----------------- 3 files changed, 7 insertions(+), 30 deletions(-) diff --git a/gradle.properties b/gradle.properties index 40a2c595f..ea46a1f11 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.87.0 +mod_version=1.87.1 # Minecraft properties (update mods.toml when changing) mc_version=1.14.4 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 0549257ed..c2bb4f4d6 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.87.1 + +* Fix blocks not dropping items in survival. + # New features in CC: Tweaked 1.87.0 * Add documentation to many Lua functions. This is published online at https://tweaked.cc/. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 5d23812ed..02ec15e80 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,32 +1,5 @@ -New features in CC: Tweaked 1.87.0 +New features in CC: Tweaked 1.87.1 -* Add documentation to many Lua functions. This is published online at https://tweaked.cc/. -* Replace to pretty-printer in the Lua REPL. It now supports displaying functions and recursive tables. This printer is may be used within your own code through the `cc.pretty` module. -* Add `fs.getCapacity`. A complement to `fs.getFreeSpace`, this returns the capacity of the supplied drive. -* Add `fs.getAttributes`. This provides file size and type, as well as creation and modification time. -* Update Cobalt version. This backports several features from Lua 5.2 and 5.3: - - The `__len` metamethod may now be used by tables. - - Add `\z`, hexadecimal (`\x00`) and unicode (`\u0000`) string escape codes. - - Add `utf8` lib. - - Mirror Lua's behaviour of tail calls more closely. Native functions are no longer tail called, and tail calls are displayed in the stack trace. - - `table.unpack` now uses `__len` and `__index` metamethods. - - Parser errors now include the token where the error occured. -* Add `textutils.unserializeJSON`. This can be used to decode standard JSON and stringified-NBT. -* Switch the monitor renderer to use VBOs, providing a _significant_ performance boost in some cases. You can switch back to the display list renderer via the config. -* The `settings` API now allows "defining" settings. This allows settings to specify a default value and description. -* Enable the motd on non-pocket computers. -* Allow using the menu with the mouse in edit and paint (JakobDev). -* Add Danish and Korean translations (ChristianLW, mindy15963) -* Fire `mouse_up` events in the monitor program. -* Allow specifying a timeout to `websocket.receive`. -* Increase the maximimum limit for websocket messages. -* Optimise capacity checking of computer/disk folders. - -And several bug fixes: -* Fix turtle texture being incorrectly oriented (magiczocker10). -* Prevent copying folders into themselves. -* Normalise file paths within shell.setDir (JakobDev) -* Fix turtles treating waterlogged blocks as water. -* Register an entity renderer for the turtle's fake player. +* Fix blocks not dropping items in survival. Type "help changelog" to see the full version history. From 8fac68386e30c9065184c6c0799d3d3e18a8f5ff Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 28 Apr 2020 09:42:34 +0100 Subject: [PATCH 198/711] Fix usages of global variables - Lint references to unknown fields of modules, excluding the keys and colours modules. This caught several silly errors in our stub files, but nothing else. - Lint on using unknown globals. This highlighted a couple of really silly mistakes. Fixes #427. - Add documentation for fs.attributes, fs.getCapacity and pocket, as they were not defined before. Co-authored-by: JackMacWindows --- doc/stub/fs.lua | 30 +++++++++++++++++++ doc/stub/os.lua | 7 +++++ doc/stub/pocket.lua | 28 +++++++++++++++++ doc/stub/redstone.lua | 2 +- doc/stub/term.lua | 8 ++--- illuaminate.sexp | 24 ++++++++++++--- .../computercraft/lua/rom/apis/rednet.lua | 6 +++- .../computercraft/lua/rom/apis/settings.lua | 2 +- .../lua/rom/apis/turtle/turtle.lua | 7 ++++- .../lua/rom/modules/main/cc/pretty.lua | 2 +- .../computercraft/lua/rom/programs/shell.lua | 2 +- .../lua/rom/programs/turtle/dance.lua | 2 +- 12 files changed, 105 insertions(+), 15 deletions(-) create mode 100644 doc/stub/pocket.lua diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua index 73d578e01..a9e76a352 100644 --- a/doc/stub/fs.lua +++ b/doc/stub/fs.lua @@ -19,6 +19,36 @@ function getFreeSpace(path) end function find(pattern) end function getDir(path) end +--- Get the capacity of the drive at the given path. +-- +-- This may be used in conjunction with @{getFreeSpace} to determine what +-- percentage of this drive has been used. +-- +-- @tparam string path The path of the drive to get. +-- @treturn number This drive's capacity. This will be 0 for "read-only" drives, +-- such as the ROM or treasure disks. +function getCapacity(path) end + +--- Get attributes about a specific file or folder. +-- +-- The returned attributes table contains information about the size of the +-- file, whether it is a directory, and when it was created and last modified. +-- +-- The creation and modification times are given as the number of milliseconds +-- since the UNIX epoch. This may be given to @{os.date} in order to convert it +-- to more usable form. +-- +-- @tparam string path The path to get attributes for. +-- @treturn { size = number, isDir = boolean, created = number, modified = number } +-- The resulting attributes. +-- @throws If the path does not exist. +-- @see getSize If you only care about the file's size. +-- @see isDir If you only care whether a path is a directory or not. +function attributes(path) end + +-- Defined in bios.lua +function complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) end + --- A file handle which can be read from. -- -- @type ReadHandle diff --git a/doc/stub/os.lua b/doc/stub/os.lua index 163d2c2b0..2703b4d42 100644 --- a/doc/stub/os.lua +++ b/doc/stub/os.lua @@ -15,3 +15,10 @@ function cancelTimer(id) end function cancelAlarm(id) end function epoch(timezone) end function date(format, time) end + +-- Defined in bios.lua +function loadAPI(path) end +function pullEvent(filter) end +function pullEventRaw(filter) end +function version() end +function run(env, path, ...) end diff --git a/doc/stub/pocket.lua b/doc/stub/pocket.lua new file mode 100644 index 000000000..c37da798f --- /dev/null +++ b/doc/stub/pocket.lua @@ -0,0 +1,28 @@ +--[[- +Control the current pocket computer, adding or removing upgrades. + +This API is only available on pocket computers. As such, you may use its +presence to determine what kind of computer you are using: + +```lua +if pocket then + print("On a pocket computer") +else + print("On something else") +end +``` +]] + +--- Search the player's inventory for another upgrade, replacing the existing +-- one with that item if found. +-- +-- This inventory search starts from the player's currently selected slot, +-- allowing you to prioritise upgrades. +-- +-- @throws If an upgrade cannot be found. +function equipBack() end + +--- Remove the pocket computer's current upgrade. +-- +-- @throws If this pocket computer does not currently have an upgrade. +function unequipBack() end diff --git a/doc/stub/redstone.lua b/doc/stub/redstone.lua index cf10a45ca..217d41766 100644 --- a/doc/stub/redstone.lua +++ b/doc/stub/redstone.lua @@ -11,4 +11,4 @@ setAnalogueOutput = setAnalogOutput function getAnalogOutput(sid) end getAnalogueOutput = getAnalogOutput function getAnalogInput(side) end -getAnalogueInput = getAnaloguInput +getAnalogueInput = getAnalogInput diff --git a/doc/stub/term.lua b/doc/stub/term.lua index 2111949b6..fb30c5c36 100644 --- a/doc/stub/term.lua +++ b/doc/stub/term.lua @@ -15,14 +15,14 @@ isColor = isColour function getTextColour() end getTextColor = getTextColor function getBackgroundColour() end -getBackgroundColour = getBackgroundColour +getBackgroundColor = getBackgroundColour function blit(text, text_colours, background_colours) end function setPaletteColour(colour, ...) end -setPaletteColour = setPaletteColour +setPaletteColor = setPaletteColour function getPaletteColour(colour, ...) end -getPaletteColour = getPaletteColour +getPaletteColor = getPaletteColour function nativePaletteColour(colour) end -nativePaletteColour = nativePaletteColour +nativePaletteColor = nativePaletteColour --- @type Redirect local Redirect = {} diff --git a/illuaminate.sexp b/illuaminate.sexp index 32acc06de..b1bf17f31 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -33,17 +33,27 @@ ;; It's useful to name arguments for documentation, so we allow this. It'd ;; be good to find a compromise in the future, but this works for now. - -var:unused-arg + -var:unused-arg) - ;; Some APIS (keys, colour and os mainly) are incomplete right now. - -var:unresolved-member) (lint (bracket-spaces (call no-space) (function-args no-space) (parens no-space) (table space) - (index no-space)))) + (index no-space)) + + ;; colours imports from colors, and we don't handle that right now. + ;; keys is entirely dynamic, so we skip it. + (dynamic-modules colours keys) + + (globals + :max + _CC_DEFAULT_SETTINGS + _CC_DISABLE_LUA51_FEATURES + ;; Ideally we'd pick these up from bios.lua, but illuaminate currently + ;; isn't smart enough. + sleep write printError read rs))) ;; We disable the unused global linter in bios.lua and the APIs. In the future ;; hopefully we'll get illuaminate to handle this. @@ -82,3 +92,9 @@ /src/main/resources/*/computercraft/lua/rom/programs/advanced/multishell.lua /src/main/resources/*/computercraft/lua/rom/programs/shell.lua) (linters -doc:unresolved-reference)) + +(at /src/test/resources/test-rom + (lint + (globals + :max sleep write + cct_test describe expect howlci fail it pending stub))) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index ab68db4b6..358c62bd5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -334,7 +334,11 @@ end local bRunning = false ---- @local +--- Listen for modem messages and converts them into rednet messages, which may +-- then be @{receive|received}. +-- +-- This is automatically started in the background on computer startup, and +-- should not be called manually. function run() if bRunning then error("rednet is already running", 2) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index f9925d36f..92d211a24 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -207,7 +207,7 @@ function load(sPath) for k, v in pairs(tFile) do local ty_v = type(k) if type(k) == "string" and (ty_v == "string" or ty_v == "number" or ty_v == "boolean" or ty_v == "table") then - local opt = details[name] + local opt = details[k] if not opt or not opt.type or ty_v == opt.type then set_value(k, v) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua index 32852f718..c9d57bf12 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/turtle/turtle.lua @@ -5,7 +5,12 @@ if not turtle then error("Cannot load turtle API on computer", 2) end -native = turtle.native or turtle --- @local + +--- The builtin turtle API, without any generated helper functions. +-- +-- Generally you should not need to use this table - it only exists for +-- backwards compatibility reasons. +native = turtle.native or turtle local function addCraftMethod(object) if peripheral.getType("left") == "workbench" then diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua index 95b0c76fa..65718f949 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -384,7 +384,7 @@ local function pretty_impl(obj, tracking) end tracking[obj] = nil - return group(concat(obrace, nest(2, concat(table.unpack(doc, 1, n))), space_line, cbrace)) + return group(concat(obrace, nest(2, concat(table.unpack(doc, 1, doc.n))), space_line, cbrace)) end end diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index c36cc9abf..474d3ecfd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -46,7 +46,7 @@ local function createShellEnv(sDir) package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" if turtle then package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" - elseif command then + elseif commands then package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" end package.config = "/\n;\n?\n!\n-" diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua index 9d539fde4..8efe68930 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua @@ -94,7 +94,7 @@ print("Press any key to stop the groove") parallel.waitForAny( function() - while not bEnd do + while true do local _, key = os.pullEvent("key") if key ~= keys.escape then return From 447c3ab12585cf52968fa7a032171d83b23a4d54 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 28 Apr 2020 09:51:06 +0100 Subject: [PATCH 199/711] Clean up dance.lua Not sure what keys.escape was doing there. That's very old. --- .../computercraft/lua/rom/programs/turtle/dance.lua | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua index 8efe68930..20b14f12e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/turtle/dance.lua @@ -93,18 +93,10 @@ end print("Press any key to stop the groove") parallel.waitForAny( + function() os.pullEvent("key") end, function() while true do - local _, key = os.pullEvent("key") - if key ~= keys.escape then - return - end - end - end, - function() - while true do - local fnMove = tMoves[math.random(1, #tMoves)] - fnMove() + tMoves[math.random(1, #tMoves)]() end end ) From f52b8fa2de7a568da98597bb111f7c9225557007 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 29 Apr 2020 16:23:18 +0100 Subject: [PATCH 200/711] Bump mappings version --- gradle.properties | 2 +- .../java/dan200/computercraft/data/LootTableProvider.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index a4a22ade3..4089f1259 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,4 @@ mod_version=1.87.1 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 forge_version=31.1.41 -mappings_version=20200410-1.15.1 +mappings_version=20200429-1.15.1 diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java index c0f0c44e0..e24d07206 100644 --- a/src/main/java/dan200/computercraft/data/LootTableProvider.java +++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -47,13 +47,13 @@ public abstract class LootTableProvider implements IDataProvider ValidationTracker validation = new ValidationTracker( LootParameterSets.GENERIC, x -> null, tables::get ); registerLoot( ( id, table ) -> { - if( tables.containsKey( id ) ) validation.func_227530_a_( "Duplicate loot tables for " + id ); + if( tables.containsKey( id ) ) validation.addProblem( "Duplicate loot tables for " + id ); tables.put( id, table ); } ); tables.forEach( ( key, value ) -> LootTableManager.func_227508_a_( validation, key, value ) ); - Multimap problems = validation.func_227527_a_(); + Multimap problems = validation.getProblems(); if( !problems.isEmpty() ) { problems.forEach( ( child, problem ) -> From 5eec24676f726e836657203bd4254fbe8d99928d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 29 Apr 2020 17:37:02 +0100 Subject: [PATCH 201/711] Prevent computers scanning peripherals twice --- .../computercraft/shared/computer/blocks/TileComputerBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 9f4aad451..8324b0ed7 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -277,7 +277,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( offset.equals( neighbour ) ) { updateSideInput( computer, dir, offset ); - break; + return; } } From 697e9449cfb4e67d04496b84e5e8f9de9bda4ee0 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 30 Apr 2020 10:59:55 +0100 Subject: [PATCH 202/711] Delete existing treasure disks --- .../GopherAtl/battleship/battleship.lua | 875 ------ .../treasure/GravityScore/LuaIDE/luaide.lua | 2212 --------------- .../lua/treasure/JTK/maze3d/maze2d.lua | 327 --- .../lua/treasure/JTK/maze3d/maze3d.lua | 614 ---- .../lua/treasure/Lyqyd/nsh/framebuffer.lua | 159 -- .../lua/treasure/Lyqyd/nsh/get.lua | 26 - .../lua/treasure/Lyqyd/nsh/nsh.lua | 721 ----- .../lua/treasure/Lyqyd/nsh/put.lua | 35 - .../TheOriginalBIT/tictactoe/tictactoe.lua | 444 --- .../dan200/alongtimeago/alongtimeago.lua | 47 - .../deprecated/GopherAtl/talk/talk.lua | 1 - .../fredthead/protector/protector.lua | 1311 --------- .../nitrogenfingers/goldrunner/goldrunner.lua | 1314 --------- .../goldrunner/levels/01_welcome | 18 - .../goldrunner/levels/02_coalmine | 18 - .../goldrunner/levels/03_seeker | 18 - .../goldrunner/levels/04_fortress | 18 - .../goldrunner/levels/05_caged | 18 - .../goldrunner/levels/06_flowers | 18 - .../goldrunner/levels/07_pyramid | 18 - .../goldrunner/levels/08_cavein | 18 - .../goldrunner/levels/09_skyislands | 18 - .../goldrunner/levels/10_convert | 16 - .../nitrogenfingers/npaintpro/3dprint.lua | 119 - .../nitrogenfingers/npaintpro/gameutils.lua | 615 ---- .../nitrogenfingers/npaintpro/npaintpro.lua | 2517 ----------------- .../treasure/vilsol/gameoflife/gameoflife.lua | 178 -- 27 files changed, 11693 deletions(-) delete mode 100644 src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/framebuffer.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/01_welcome delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/02_coalmine delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/03_seeker delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/04_fortress delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/05_caged delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/06_flowers delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/07_pyramid delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/08_cavein delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/09_skyislands delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/10_convert delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua delete mode 100644 src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua diff --git a/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua b/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua deleted file mode 100644 index 8d48eaaf5..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/GopherAtl/battleship/battleship.lua +++ /dev/null @@ -1,875 +0,0 @@ ---[[ -battleship, - -by GopherAtl, 2013 - -Do whatever you want, just don't judge me by -what a mess this code is. ---]] -local args={...} -local action=args[1] -local opponentID=nil -local openedSide=nil -local opponent=nil -local myName="" -local opponentReady=false -local myTurn -local targetX,targetY -local shipsLeft=5 -local oppShipsLeft=5 - -local originalTerm = term.current() - ---bounding box of the target grid -local targetGridBounds={ - minX=16, maxX=25, - minY=4, maxY=13 - } - - -local function doColor(text,background) - term.setTextColor(text) - term.setBackgroundColor(background) -end - -local function doColor_mono(text,background) - if text==colors.blue or text==colors.red or text==colors.black or text==colors.lime or background==colors.lightGray then - term.setTextColor(colors.black) - term.setBackgroundColor(colors.white) - else - term.setTextColor(colors.white) - term.setBackgroundColor(colors.black) - end -end - -local function doScreenColor() - if term.isColor() then - doColor(colors.white,colors.lightGray) - else - doColor(colors.black,colors.white) - end -end - -local function toGridRef(x,y) - return string.sub("ABCDEFGHIJ",x,x)..string.sub("1234567890",y,y) -end - - -if not term.isColor() then - doColor=doColor_mono -end - -local function quit() - if openedSide then - rednet.close(openedSide) - end - term.redirect( originalTerm ) - term.setCursorPos(term.getSize()) - print() - error() -end - -local foundModem=false ---find modem -for k,v in pairs(redstone.getSides()) do - if peripheral.getType(v)=="modem" then - foundModem=true - if not rednet.isOpen(v) then - rednet.open(v) - openedSide=v - end - break - end -end - -if not foundModem then - print("You must have a modem to play!") - return -end - -if action==nil or (action~="join" and action~="host") then - print("Invalid parameters. Usage:\n> battleship host\nHosts a game, waits for another computer to join\n> battleship join\nLooks for another game to join") - quit() -end - ---get player name -while true do - doColor(colors.cyan,colors.black) - write("player name: ") - doColor(colors.gray,colors.black) - myName=read() - if myName=="" then - doColor(colors.red,colors.black) - print("You have to give a name!") - elseif #myName>11 then - doColor(colors.red,colors.black) - print("Max name is 11 characters!") - else - break - end -end - -if action=="join" then - print("Attempting to join a game...\n(press q to cancel)") - while true do - local retryTimer=os.startTimer(1); - rednet.broadcast("bs join "..myName); - - while true do - local event,p1,p2,p3=os.pullEvent(); - if event=="rednet_message" then - opponent=string.match(p2,"bs accept %s*(.+)%s*") - if opponent then - opponentID=p1 - break - end - elseif event=="timer" and p1==retryTimer then - break - elseif event=="char" and (p1=="q" or p1=="Q") then - print("Couldn't find an opponent; quitting") - quit() - end - end - local joined=false - - if opponentID then - print("Joining game!") - rednet.send(opponentID,"bs start") - break - end - end -elseif action=="host" then - print("Waiting for challenger...\n(Press q to cancel)") - while true do - while true do - local event,p1,p2=os.pullEvent() - if event=="rednet_message" then - opponent=string.match(p2,"bs join %s*(.+)%s*") if opponent then - print("found player, inviting..") - opponentID=p1 - break - end - elseif event=="char" and (p1=="q" or p1=="Q") then - print("Couldn't find opponent, quitting") - quit() - end - end - - if opponentID then - rednet.send(opponentID,"bs accept "..myName) - local timeout=os.startTimer(1) - while true do - local event,p1,p2=os.pullEvent() - if event=="rednet_message" and p2=="bs start" then - print("player joined!") - break - elseif event=="timer" and p1==timeout then - print("player joined another game. Waiting for another...") - opponentID=nil - break - end - end - - if opponentID then - break - end - end - end -end - -local ships={ - {pos=nil,dir="h",size=5,name="carrier",hits=0}, - {pos=nil,dir="h",size=4,name="battleship",hits=0}, - {pos=nil,dir="h",size=3,name="cruiser",hits=0}, - {pos=nil,dir="h",size=3,name="submarine",hits=0}, - {pos=nil,dir="h",size=2,name="destroyer",hits=0}, -} - -local myShotTable={ {1,1,true},{5,5,false} } -local oppShotTable={ } - -local myGrid,oppGrid={title=myName},{title=opponent} - ---setup grids -for i=1,10 do - myGrid[i]={} - oppGrid[i]={} - for j=1,10 do - myGrid[i][j]={hit=false,ship=false} - oppGrid[i][j]={hit=false,ship=false} - end -end - -local function drawShipsToGrid(ships,grid) - for i=1,#ships do - local x,y=table.unpack(ships[i].pos) - local stepX=ships[i].dir=="h" and 1 or 0 - local stepY=stepX==1 and 0 or 1 - for j=1,ships[i].size do - grid[x][y].ship=i - x,y=x+stepX,y+stepY - end - end -end - -local function drawShotToGrid(shot,grid) - grid[shot[1]][shot[2]].shot=true - grid[shot[1]][shot[2]].hit=shot[3] -end - -local function makeShot(x,y,grid) - local tile=grid[x][y] - if tile.shot==true then - return nil --already shot here! - end - - local shot={x,y,tile.ship} - drawShotToGrid(shot,grid) - if tile.ship then - ships[tile.ship].hits=ships[tile.ship].hits+1 - if ships[tile.ship].hits==ships[tile.ship].size then - os.queueEvent("shipsunk",tile.ship) - end - end - return shot -end - - -local function drawTile(scrX,scrY,tile) - term.setCursorPos(scrX,scrY) - - if tile.ship then - if tile.shot then - doColor(colors.red,colors.gray) - term.write("@") - else - doColor(colors.white,colors.gray) - term.write("O") - end - else - if tile.hit then - doColor(colors.red,colors.gray) - term.write("x") - elseif tile.shot then - doColor(colors.white,colors.lightBlue) - term.write(".") - else - doColor(colors.white,colors.lightBlue) - term.write(" ") - end - end -end - -local function drawGrid(scrX,scrY,grid) - doColor(colors.white,colors.black) - term.setCursorPos(scrX,scrY+1) - term.write(" ") - doColor(colors.white,colors.gray) - term.setCursorPos(scrX,scrY) - local pad=11-#grid.title - term.write(string.rep(" ",math.ceil(pad/2))..grid.title..string.rep(" ",math.floor(pad/2))) - - for gx=1,10 do - term.setTextColor(colors.white) - term.setBackgroundColor(colors.black) - term.setCursorPos(scrX+gx,scrY+1) - term.write(gx==10 and "0" or string.char(string.byte("0")+gx)) - - term.setCursorPos(scrX,scrY+gx+1) - term.write(string.char(string.byte("A")+gx-1)) - for gy=1,10 do - drawTile(scrX+gx,scrY+gy+1,grid[gx][gy]) - end - end - doColor(colors.white,colors.black) -end - -function moveTargetIndicator(newX,newY) - --if x has changed... - if targetX and targetY then - drawTile(targetX+targetGridBounds.minX-1,targetY+targetGridBounds.minY-1,oppGrid[targetX][targetY]) - end - doColor(colors.yellow,colors.lightGray) - if newX~=targetX then - --space over old - if targetX then - term.setCursorPos(targetGridBounds.minX+targetX-1,targetGridBounds.maxY+1) - term.write(" ") - term.setCursorPos(targetGridBounds.minX+targetX-1,targetGridBounds.minY-3) - term.write(" ") - end - --draw new - term.setCursorPos(targetGridBounds.minX+newX-1,targetGridBounds.maxY+1) - term.write("^") - term.setCursorPos(targetGridBounds.minX+newX-1,targetGridBounds.minY-3) - term.write("v") - - targetX=newX - end - if newY~=targetY then - --space over old - if targetY then - term.setCursorPos(targetGridBounds.maxX+1,targetGridBounds.minY+targetY-1) - term.write(" ") - term.setCursorPos(targetGridBounds.minX-2,targetGridBounds.minY+targetY-1) - term.write(" ") - end - --draw new - term.setCursorPos(targetGridBounds.maxX+1,targetGridBounds.minY+newY-1) - term.write("<") - term.setCursorPos(targetGridBounds.minX-2,targetGridBounds.minY+newY-1) - term.write(">") - - targetY=newY - end - term.setCursorPos(15,15) - term.write("Target : "..toGridRef(targetX,targetY)) - --if the target tile is a valid target, draw a "+" - if not oppGrid[targetX][targetY].shot then - term.setCursorPos(targetX+targetGridBounds.minX-1,targetY+targetGridBounds.minY-1) - doColor(colors.yellow,colors.lightBlue) - term.write("+") - end -end - -local log={} - -local termWidth,termHeight=term.getSize() - -local logHeight=termHeight-3 -local logWidth=termWidth-28 - -for i=1,logHeight do - log[i]="" -end - -local function printLog() - doColor(colors.white,colors.black) - for i=1,logHeight do - term.setCursorPos(28,1+i) - local name,line=string.match(log[i],"(<[^>]+> )(.*)") - if name then - doColor(colors.lightBlue,colors.black) - write(name) - doColor(colors.white,colors.black) - write(line..string.rep(" ",logWidth-#log[i])) - else - write(log[i]..string.rep(" ",logWidth-#log[i])) - end - end -end - - - ---shipX/Y are the position of ship on grid; gridX/Y are the offset of the top-left of grid -local function drawShip(size,align,x,y,char) - local stepX=align=="h" and 1 or 0 - local stepY=stepX==1 and 0 or 1 - for j=1,size do - term.setCursorPos(x,y) - term.write(char) - x,y=x+stepX,y+stepY - end -end - -local function setStatusLine(lineNum,text) - doScreenColor() - local pad=math.floor((termWidth-#text)/2) - term.setCursorPos(1,16+lineNum) - term.write((" "):rep(pad)..text..(" "):rep(termWidth-#text-pad)) -end - - -doScreenColor() -term.clear() - -drawGrid(2,2,myGrid) - -setStatusLine(1,"Started game with "..opponent.." at computer #"..(opponentID or "nil")) - -local function getShipBounds(ship) - return { - minX=ship.pos[1], - minY=ship.pos[2], - maxX=ship.pos[1]+(ship.dir=="h" and ship.size-1 or 0), - maxY=ship.pos[2]+(ship.dir=="v" and ship.size-1 or 0) - } -end - -local function getPointBounds(x,y) - return { - minX=x, - minY=y, - maxX=x, - maxY=y, - } -end - -local function boundsIntersect(boundsA,boundsB) - return not ( - boundsA.minX>boundsB.maxX or - boundsA.maxXboundsB.maxY or - boundsA.maxY="a" and p1<="j" then - --row selected - moveTargetIndicator(targetX,string.byte(p1)-string.byte("a")+1) - elseif p1>="0" and p1<="9" then - local t=string.byte(p1)-string.byte("0") - if t==0 then t=10 end - moveTargetIndicator(t,targetY) - end - elseif e=="key" then - if p1==keys.enter or p1==keys.space and targetX and targetY then - local shot=makeShot(targetX,targetY,oppGrid) - if shot then - rednet.send(opponentID,"bs shot "..targetX.." "..targetY) - break - end - elseif p1==keys.up then - moveTargetIndicator(targetX,math.max(targetY-1,1)) - elseif p1==keys.down then - moveTargetIndicator(targetX,math.min(targetY+1,10)) - elseif p1==keys.left then - moveTargetIndicator(math.max(targetX-1,1),targetY) - elseif p1==keys.right then - moveTargetIndicator(math.min(targetX+1,10),targetY) - end - end - end - --shot sent, wait for my turn to resolve (top coroutine will switch turns and draw the hit to the grid) - setStatusLine(2,"Waiting for opponent...") - while myTurn do - os.pullEvent() - end - end -end - -local gameRoutine=coroutine.create(runGame) ---if advanced terminal, default focus to chat, can play with mouse -local inChat=term.isColor() -local savedCursorPos={7,19} - ---redirect just to block scroll -local redir={} -for k,v in pairs(originalTerm) do - if k~="scroll" then - redir[k]=v - else - redir[k]=function() end - end -end -originalTerm = term.redirect(redir) - ---run the game routine once -coroutine.resume(gameRoutine) ---hide cursor -term.setCursorBlink(false) - -while true do - local e,p1,p2,p3,p4,p5=os.pullEventRaw() - if e=="terminate" then - quit() - elseif e=="shipsunk" then - setStatusLine(1,opponent.." sank your "..ships[p1].name.."!") - rednet.send(opponentID,"bs sink") - shipsLeft=shipsLeft-1 - if shipsLeft==1 then - setStatusLine(3,"You only have 1 ship left!") - elseif shipsLeft>1 then - setStatusLine(3,"You have "..shipsLeft.." ships left!") - else - rednet.send(opponentID,"bs win") - setStatusLine(3,"You lost the game!") - break - end - elseif e=="rednet_message" then - local cmd,args=string.match(p2,"^bs (%S+)%s?(.*)") - if cmd=="ready" then - opponentReady=true - os.queueEvent("kickcoroutine") - elseif cmd=="cointoss" then - myTurn=args=="true" - if myTurn then - setStatusLine(2,"Your turn, take your shot!") - else - setStatusLine(2,"Opponent's turn, waiting...") - end - os.queueEvent("kickcoroutine") - elseif cmd=="shot" then - if myTurn then - setStatusLine(3,"What the?! Got a shot but not their turn! Ignoring") - else - local tx, ty=string.match(args,"(%d+) (%d+)") - tx,ty=tonumber(tx),tonumber(ty) - local tile=myGrid[tx][ty] - local shot=makeShot(tx,ty,myGrid) - rednet.send(opponentID,"bs result "..(shot[3] and "hit" or "miss")) - drawTile(2+tx,3+ty,tile) - myTurn=true - os.queueEvent("kickcoroutine") - displayGameHelp() - setStatusLine(1,opponent.." fired at "..toGridRef(tx,ty).." and "..(shot[3] and "hit" or "missed")) - setStatusLine(2,"Your turn, take your shot!") - end - elseif cmd=="sink" then - setStatusLine(1,"You sank one of "..opponent.."'s ships!") - oppShipsLeft=oppShipsLeft-1 - if oppShipsLeft==0 then - setStatusLine(2,opponent.." has no ships left!") - elseif oppShipsLeft==1 then - setStatusLine(2,"Sink 1 more to win!") - else - setStatusLine(2,"They have "..oppShipsLeft.." ships left.") - end - elseif cmd=="result" then - if not myTurn then - setStatusLine(3,"What the?! Got a shot result but not my turn! Ignoring") - else - local tile=oppGrid[targetX][targetY] - tile.hit=args=="hit" - drawTile(targetX+15,targetY+3,tile) - myTurn=false - doColor(tile.hit and colors.red or colors.white,colors.lightGray) - term.setCursorPos(17,16) - term.write(tile.hit and "HIT!" or "MISS") - setStatusLine(2,"Waiting for opponent...") - os.queueEvent("kickcoroutine") - end - - elseif cmd=="win" then - --we won! - setStatusLine(3,"You won the game! Congratulations!") - break - end - --everything else goes to gameRoutine - else - --all other events go to this routine - local succ,err=coroutine.resume(gameRoutine,e,p1,p2,p3,p4,p5) - if not succ then - print("game coroutine crashed with the following error: "..err) - quit() - end - - if coroutine.status(gameRoutine)=="dead" then - --game over - break - end - end - -end - -term.setCursorPos(1,19) -term.clearLine() -term.write(" Press any key to continue...") -os.pullEvent("key") ---if a char event was queued following the key event, this will eat it -os.sleep(0) - -term.setTextColor(colors.white) -term.setBackgroundColor(colors.black) -term.clear() -quit() --- diff --git a/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua b/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua deleted file mode 100644 index 7ec78c299..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua +++ /dev/null @@ -1,2212 +0,0 @@ - --- --- Lua IDE --- Made by GravityScore --- - - --- -------- Variables - --- Version -local version = "1.0" -local args = {...} - --- Editing -local w, h = term.getSize() -local tabWidth = 2 - -local autosaveInterval = 20 -local allowEditorEvent = true -local keyboardShortcutTimeout = 0.4 - --- Clipboard -local clipboard = nil - --- Theme -local theme = {} - --- Language -local languages = {} -local curLanguage = {} - --- Events -local event_distract = "luaide_distractionEvent" - --- Locations ---local updateURL = "https://raw.github.com/GravityScore/LuaIDE/master/luaide.lua" -local ideLocation = "/" .. shell.getRunningProgram() -local themeLocation = "/.LuaIDE-Theme" - -local function isAdvanced() return term.isColor and term.isColor() end - - --- -------- Utilities - -local function modRead(properties) - local w, h = term.getSize() - local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil, - liveUpdates = nil, exitOnKey = nil} - if not properties then properties = {} end - for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end - if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end - if not properties.visibleLength then properties.visibleLength = w end - - local sx, sy = term.getCursorPos() - local line = "" - local pos = 0 - local historyPos = nil - - local function redraw(repl) - local scroll = 0 - if properties.visibleLength and sx + pos > properties.visibleLength + 1 then - scroll = (sx + pos) - (properties.visibleLength + 1) - end - - term.setCursorPos(sx, sy) - local a = repl or properties.replaceChar - if a then term.write(string.rep(a, line:len() - scroll)) - else term.write(line:sub(scroll + 1, -1)) end - term.setCursorPos(sx + pos - scroll, sy) - end - - local function sendLiveUpdates(event, ...) - if type(properties.liveUpdates) == "function" then - local ox, oy = term.getCursorPos() - local a, data = properties.liveUpdates(line, event, ...) - if a == true and data == nil then - term.setCursorBlink(false) - return line - elseif a == true and data ~= nil then - term.setCursorBlink(false) - return data - end - term.setCursorPos(ox, oy) - end - end - - term.setCursorBlink(true) - while true do - local e, but, x, y, p4, p5 = os.pullEvent() - - if e == "char" then - local s = false - if properties.textLength and line:len() < properties.textLength then s = true - elseif not properties.textLength then s = true end - - local canType = true - if not properties.grantPrint and properties.refusePrint then - local canTypeKeys = {} - if type(properties.refusePrint) == "table" then - for _, v in pairs(properties.refusePrint) do - table.insert(canTypeKeys, tostring(v):sub(1, 1)) - end - elseif type(properties.refusePrint) == "string" then - for char in properties.refusePrint:gmatch(".") do - table.insert(canTypeKeys, char) - end - end - for _, v in pairs(canTypeKeys) do if but == v then canType = false end end - elseif properties.grantPrint then - canType = false - local canTypeKeys = {} - if type(properties.grantPrint) == "table" then - for _, v in pairs(properties.grantPrint) do - table.insert(canTypeKeys, tostring(v):sub(1, 1)) - end - elseif type(properties.grantPrint) == "string" then - for char in properties.grantPrint:gmatch(".") do - table.insert(canTypeKeys, char) - end - end - for _, v in pairs(canTypeKeys) do if but == v then canType = true end end - end - - if s and canType then - line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1) - pos = pos + 1 - redraw() - end - elseif e == "key" then - if but == keys.enter then break - elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end - elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end - elseif (but == keys.up or but == keys.down) and properties.history then - redraw(" ") - if but == keys.up then - if historyPos == nil and #properties.history > 0 then - historyPos = #properties.history - elseif historyPos > 1 then - historyPos = historyPos - 1 - end - elseif but == keys.down then - if historyPos == #properties.history then historyPos = nil - elseif historyPos ~= nil then historyPos = historyPos + 1 end - end - - if properties.history and historyPos then - line = properties.history[historyPos] - pos = line:len() - else - line = "" - pos = 0 - end - - redraw() - local a = sendLiveUpdates("history") - if a then return a end - elseif but == keys.backspace and pos > 0 then - redraw(" ") - line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1) - pos = pos - 1 - redraw() - local a = sendLiveUpdates("delete") - if a then return a end - elseif but == keys.home then - pos = 0 - redraw() - elseif but == keys.delete and pos < line:len() then - redraw(" ") - line = line:sub(1, pos) .. line:sub(pos + 2, -1) - redraw() - local a = sendLiveUpdates("delete") - if a then return a end - elseif but == keys["end"] then - pos = line:len() - redraw() - elseif properties.exitOnKey then - if but == properties.exitOnKey or (properties.exitOnKey == "control" and - (but == 29 or but == 157)) then - term.setCursorBlink(false) - return nil - end - end - end - local a = sendLiveUpdates(e, but, x, y, p4, p5) - if a then return a end - end - - term.setCursorBlink(false) - if line ~= nil then line = line:gsub("^%s*(.-)%s*$", "%1") end - return line -end - - --- -------- Themes - -local defaultTheme = { - background = "gray", - backgroundHighlight = "lightGray", - prompt = "cyan", - promptHighlight = "lightBlue", - err = "red", - errHighlight = "pink", - - editorBackground = "gray", - editorLineHightlight = "lightBlue", - editorLineNumbers = "gray", - editorLineNumbersHighlight = "lightGray", - editorError = "pink", - editorErrorHighlight = "red", - - textColor = "white", - conditional = "yellow", - constant = "orange", - ["function"] = "magenta", - string = "red", - comment = "lime" -} - -local normalTheme = { - background = "black", - backgroundHighlight = "black", - prompt = "black", - promptHighlight = "black", - err = "black", - errHighlight = "black", - - editorBackground = "black", - editorLineHightlight = "black", - editorLineNumbers = "black", - editorLineNumbersHighlight = "white", - editorError = "black", - editorErrorHighlight = "black", - - textColor = "white", - conditional = "white", - constant = "white", - ["function"] = "white", - string = "white", - comment = "white" -} - ---[[ -local availableThemes = { - {"Water (Default)", "https://raw.github.com/GravityScore/LuaIDE/master/themes/default.txt"}, - {"Fire", "https://raw.github.com/GravityScore/LuaIDE/master/themes/fire.txt"}, - {"Sublime Text 2", "https://raw.github.com/GravityScore/LuaIDE/master/themes/st2.txt"}, - {"Midnight", "https://raw.github.com/GravityScore/LuaIDE/master/themes/midnight.txt"}, - {"TheOriginalBIT", "https://raw.github.com/GravityScore/LuaIDE/master/themes/bit.txt"}, - {"Superaxander", "https://raw.github.com/GravityScore/LuaIDE/master/themes/superaxander.txt"}, - {"Forest", "https://raw.github.com/GravityScore/LuaIDE/master/themes/forest.txt"}, - {"Night", "https://raw.github.com/GravityScore/LuaIDE/master/themes/night.txt"}, - {"Original", "https://raw.github.com/GravityScore/LuaIDE/master/themes/original.txt"}, -} -]]-- - -local function loadTheme(path) - local f = io.open(path) - local l = f:read("*l") - local config = {} - while l ~= nil do - local k, v = string.match(l, "^(%a+)=(%a+)") - if k and v then config[k] = v end - l = f:read("*l") - end - f:close() - return config -end - --- Load Theme -if isAdvanced() then theme = defaultTheme -else theme = normalTheme end - - --- -------- Drawing - -local function centerPrint(text, ny) - if type(text) == "table" then for _, v in pairs(text) do centerPrint(v) end - else - local x, y = term.getCursorPos() - local w, h = term.getSize() - term.setCursorPos(w/2 - text:len()/2 + (#text % 2 == 0 and 1 or 0), ny or y) - print(text) - end -end - -local function title(t) - term.setTextColor(colors[theme.textColor]) - term.setBackgroundColor(colors[theme.background]) - term.clear() - - term.setBackgroundColor(colors[theme.backgroundHighlight]) - for i = 2, 4 do term.setCursorPos(1, i) term.clearLine() end - term.setCursorPos(3, 3) - term.write(t) -end - -local function centerRead(wid, begt) - local function liveUpdate(line, e, but, x, y, p4, p5) - if isAdvanced() and e == "mouse_click" and x >= w/2 - wid/2 and x <= w/2 - wid/2 + 10 - and y >= 13 and y <= 15 then - return true, "" - end - end - - if not begt then begt = "" end - term.setTextColor(colors[theme.textColor]) - term.setBackgroundColor(colors[theme.promptHighlight]) - for i = 8, 10 do - term.setCursorPos(w/2 - wid/2, i) - term.write(string.rep(" ", wid)) - end - - if isAdvanced() then - term.setBackgroundColor(colors[theme.errHighlight]) - for i = 13, 15 do - term.setCursorPos(w/2 - wid/2 + 1, i) - term.write(string.rep(" ", 10)) - end - term.setCursorPos(w/2 - wid/2 + 2, 14) - term.write("> Cancel") - end - - term.setBackgroundColor(colors[theme.promptHighlight]) - term.setCursorPos(w/2 - wid/2 + 1, 9) - term.write("> " .. begt) - return modRead({visibleLength = w/2 + wid/2, liveUpdates = liveUpdate}) -end - - --- -------- Prompt - -local function prompt(list, dir, isGrid) - local function draw(sel) - for i, v in ipairs(list) do - if i == sel then term.setBackgroundColor(v.highlight or colors[theme.promptHighlight]) - else term.setBackgroundColor(v.bg or colors[theme.prompt]) end - term.setTextColor(v.tc or colors[theme.textColor]) - for i = -1, 1 do - term.setCursorPos(v[2], v[3] + i) - term.write(string.rep(" ", v[1]:len() + 4)) - end - - term.setCursorPos(v[2], v[3]) - if i == sel then - term.setBackgroundColor(v.highlight or colors[theme.promptHighlight]) - term.write(" > ") - else term.write(" - ") end - term.write(v[1] .. " ") - end - end - - local key1 = dir == "horizontal" and 203 or 200 - local key2 = dir == "horizontal" and 205 or 208 - local sel = 1 - draw(sel) - - while true do - local e, but, x, y = os.pullEvent() - if e == "key" and but == 28 then - return list[sel][1] - elseif e == "key" and but == key1 and sel > 1 then - sel = sel - 1 - draw(sel) - elseif e == "key" and but == key2 and ((err == true and sel < #list - 1) or (sel < #list)) then - sel = sel + 1 - draw(sel) - elseif isGrid and e == "key" and but == 203 and sel > 2 and #list == 4 then - sel = sel - 2 - draw(sel) - elseif isGrid and e == "key" and but == 205 and sel < 3 and #list == 4 then - sel = sel + 2 - draw(sel) - elseif e == "mouse_click" then - for i, v in ipairs(list) do - if x >= v[2] - 1 and x <= v[2] + v[1]:len() + 3 and y >= v[3] - 1 and y <= v[3] + 1 then - return list[i][1] - end - end - end - end -end - -local function scrollingPrompt(list) - local function draw(items, sel, loc) - for i, v in ipairs(items) do - local bg = colors[theme.prompt] - local bghigh = colors[theme.promptHighlight] - if v:find("Back") or v:find("Return") then - bg = colors[theme.err] - bghigh = colors[theme.errHighlight] - end - - if i == sel then term.setBackgroundColor(bghigh) - else term.setBackgroundColor(bg) end - term.setTextColor(colors[theme.textColor]) - for x = -1, 1 do - term.setCursorPos(3, (i * 4) + x + 4) - term.write(string.rep(" ", w - 13)) - end - - term.setCursorPos(3, i * 4 + 4) - if i == sel then - term.setBackgroundColor(bghigh) - term.write(" > ") - else term.write(" - ") end - term.write(v .. " ") - end - end - - local function updateDisplayList(items, loc, len) - local ret = {} - for i = 1, len do - local item = items[i + loc - 1] - if item then table.insert(ret, item) end - end - return ret - end - - -- Variables - local sel = 1 - local loc = 1 - local len = 3 - local disList = updateDisplayList(list, loc, len) - draw(disList, sel, loc) - - -- Loop - while true do - local e, key, x, y = os.pullEvent() - - if e == "mouse_click" then - for i, v in ipairs(disList) do - if x >= 3 and x <= w - 11 and y >= i * 4 + 3 and y <= i * 4 + 5 then return v end - end - elseif e == "key" and key == 200 then - if sel > 1 then - sel = sel - 1 - draw(disList, sel, loc) - elseif loc > 1 then - loc = loc - 1 - disList = updateDisplayList(list, loc, len) - draw(disList, sel, loc) - end - elseif e == "key" and key == 208 then - if sel < len then - sel = sel + 1 - draw(disList, sel, loc) - elseif loc + len - 1 < #list then - loc = loc + 1 - disList = updateDisplayList(list, loc, len) - draw(disList, sel, loc) - end - elseif e == "mouse_scroll" then - os.queueEvent("key", key == -1 and 200 or 208) - elseif e == "key" and key == 28 then - return disList[sel] - end - end -end - -function monitorKeyboardShortcuts() - local ta, tb = nil, nil - local allowChar = false - local shiftPressed = false - while true do - local event, char = os.pullEvent() - if event == "key" and (char == 42 or char == 52) then - shiftPressed = true - tb = os.startTimer(keyboardShortcutTimeout) - elseif event == "key" and (char == 29 or char == 157 or char == 219 or char == 220) then - allowEditorEvent = false - allowChar = true - ta = os.startTimer(keyboardShortcutTimeout) - elseif event == "key" and allowChar then - local name = nil - for k, v in pairs(keys) do - if v == char then - if shiftPressed then os.queueEvent("shortcut", "ctrl shift", k:lower()) - else os.queueEvent("shortcut", "ctrl", k:lower()) end - sleep(0.005) - allowEditorEvent = true - end - end - if shiftPressed then os.queueEvent("shortcut", "ctrl shift", char) - else os.queueEvent("shortcut", "ctrl", char) end - elseif event == "timer" and char == ta then - allowEditorEvent = true - allowChar = false - elseif event == "timer" and char == tb then - shiftPressed = false - end - end -end - - --- -------- Saving and Loading - ---[[local function download(url, path) - for i = 1, 3 do - local response = http.get(url) - if response then - local data = response.readAll() - response.close() - if path then - local f = io.open(path, "w") - f:write(data) - f:close() - end - return true - end - end - - return false -end]] - -local function saveFile(path, lines) - local dir = path:sub(1, path:len() - fs.getName(path):len()) - if not fs.exists(dir) then fs.makeDir(dir) end - if not fs.isDir(path) and not fs.isReadOnly(path) then - local a = "" - for _, v in pairs(lines) do a = a .. v .. "\n" end - - local f = io.open(path, "w") - f:write(a) - f:close() - return true - else return false end -end - -local function loadFile(path) - if not fs.exists(path) then - local dir = path:sub(1, path:len() - fs.getName(path):len()) - if not fs.exists(dir) then fs.makeDir(dir) end - local f = io.open(path, "w") - f:write("") - f:close() - end - - local l = {} - if fs.exists(path) and not fs.isDir(path) then - local f = io.open(path, "r") - if f then - local a = f:read("*l") - while a do - table.insert(l, a) - a = f:read("*l") - end - f:close() - end - else return nil end - - if #l < 1 then table.insert(l, "") end - return l -end - - --- -------- Languages - -languages.lua = {} -languages.brainfuck = {} -languages.none = {} - --- Lua - -languages.lua.helpTips = { - "A function you tried to call doesn't exist.", - "You made a typo.", - "The index of an array is nil.", - "The wrong variable type was passed.", - "A function/variable doesn't exist.", - "You missed an 'end'.", - "You missed a 'then'.", - "You declared a variable incorrectly.", - "One of your variables is mysteriously nil." -} - -languages.lua.defaultHelpTips = { - 2, 5 -} - -languages.lua.errors = { - ["Attempt to call nil."] = {1, 2}, - ["Attempt to index nil."] = {3, 2}, - [".+ expected, got .+"] = {4, 2, 9}, - ["'end' expected"] = {6, 2}, - ["'then' expected"] = {7, 2}, - ["'=' expected"] = {8, 2} -} - -languages.lua.keywords = { - ["and"] = "conditional", - ["break"] = "conditional", - ["do"] = "conditional", - ["else"] = "conditional", - ["elseif"] = "conditional", - ["end"] = "conditional", - ["for"] = "conditional", - ["function"] = "conditional", - ["if"] = "conditional", - ["in"] = "conditional", - ["local"] = "conditional", - ["not"] = "conditional", - ["or"] = "conditional", - ["repeat"] = "conditional", - ["return"] = "conditional", - ["then"] = "conditional", - ["until"] = "conditional", - ["while"] = "conditional", - - ["true"] = "constant", - ["false"] = "constant", - ["nil"] = "constant", - - ["print"] = "function", - ["write"] = "function", - ["sleep"] = "function", - ["pairs"] = "function", - ["ipairs"] = "function", - ["load"] = "function", - ["loadfile"] = "function", - ["rawset"] = "function", - ["rawget"] = "function", -} - -languages.lua.parseError = function(e) - local ret = {filename = "unknown", line = -1, display = "Unknown!", err = ""} - if e and e ~= "" then - ret.err = e - if e:find(":") then - ret.filename = e:sub(1, e:find(":") - 1):gsub("^%s*(.-)%s*$", "%1") - -- The "" is needed to circumvent a CC bug - e = (e:sub(e:find(":") + 1) .. ""):gsub("^%s*(.-)%s*$", "%1") - if e:find(":") then - ret.line = e:sub(1, e:find(":") - 1) - e = e:sub(e:find(":") + 2):gsub("^%s*(.-)%s*$", "%1") .. "" - end - end - ret.display = e:sub(1, 1):upper() .. e:sub(2, -1) .. "." - end - - return ret -end - -languages.lua.getCompilerErrors = function(code) - code = "local function ee65da6af1cb6f63fee9a081246f2fd92b36ef2(...)\n\n" .. code .. "\n\nend" - local fn, err = load(code) - if not err then - local _, e = pcall(fn) - if e then err = e end - end - - if err then - local a = err:find("]", 1, true) - if a then err = "string" .. err:sub(a + 1, -1) end - local ret = languages.lua.parseError(err) - if tonumber(ret.line) then ret.line = tonumber(ret.line) end - return ret - else return languages.lua.parseError(nil) end -end - -languages.lua.run = function(path, ar) - local fn, err = loadfile(path, _ENV) - if not err then - _, err = pcall(function() fn(table.unpack(ar)) end) - end - return err -end - - --- Brainfuck - -languages.brainfuck.helpTips = { - "Well idk...", - "Isn't this the whole point of the language?", - "Ya know... Not being able to debug it?", - "You made a typo." -} - -languages.brainfuck.defaultHelpTips = { - 1, 2, 3 -} - -languages.brainfuck.errors = { - ["No matching '['"] = {1, 2, 3, 4} -} - -languages.brainfuck.keywords = {} - -languages.brainfuck.parseError = function(e) - local ret = {filename = "unknown", line = -1, display = "Unknown!", err = ""} - if e and e ~= "" then - ret.err = e - ret.line = e:sub(1, e:find(":") - 1) - e = e:sub(e:find(":") + 2):gsub("^%s*(.-)%s*$", "%1") .. "" - ret.display = e:sub(1, 1):upper() .. e:sub(2, -1) .. "." - end - - return ret -end - -languages.brainfuck.mapLoops = function(code) - -- Map loops - local loopLocations = {} - local loc = 1 - local line = 1 - for let in string.gmatch(code, ".") do - if let == "[" then - loopLocations[loc] = true - elseif let == "]" then - local found = false - for i = loc, 1, -1 do - if loopLocations[i] == true then - loopLocations[i] = loc - found = true - end - end - - if not found then - return line .. ": No matching '['" - end - end - - if let == "\n" then line = line + 1 end - loc = loc + 1 - end - return loopLocations -end - -languages.brainfuck.getCompilerErrors = function(code) - local a = languages.brainfuck.mapLoops(code) - if type(a) == "string" then return languages.brainfuck.parseError(a) - else return languages.brainfuck.parseError(nil) end -end - -languages.brainfuck.run = function(path) - -- Read from file - local f = io.open(path, "r") - local content = f:read("*a") - f:close() - - -- Define environment - local dataCells = {} - local dataPointer = 1 - local instructionPointer = 1 - - -- Map loops - local loopLocations = languages.brainfuck.mapLoops(content) - if type(loopLocations) == "string" then return loopLocations end - - -- Execute code - while true do - local let = content:sub(instructionPointer, instructionPointer) - - if let == ">" then - dataPointer = dataPointer + 1 - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - elseif let == "<" then - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - dataPointer = dataPointer - 1 - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - elseif let == "+" then - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - dataCells[tostring(dataPointer)] = dataCells[tostring(dataPointer)] + 1 - elseif let == "-" then - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - dataCells[tostring(dataPointer)] = dataCells[tostring(dataPointer)] - 1 - elseif let == "." then - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - if term.getCursorPos() >= w then print("") end - write(string.char(math.max(1, dataCells[tostring(dataPointer)]))) - elseif let == "," then - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - term.setCursorBlink(true) - local e, but = os.pullEvent("char") - term.setCursorBlink(false) - dataCells[tostring(dataPointer)] = string.byte(but) - if term.getCursorPos() >= w then print("") end - write(but) - elseif let == "/" then - if not dataCells[tostring(dataPointer)] then dataCells[tostring(dataPointer)] = 0 end - if term.getCursorPos() >= w then print("") end - write(dataCells[tostring(dataPointer)]) - elseif let == "[" then - if dataCells[tostring(dataPointer)] == 0 then - for k, v in pairs(loopLocations) do - if k == instructionPointer then instructionPointer = v end - end - end - elseif let == "]" then - for k, v in pairs(loopLocations) do - if v == instructionPointer then instructionPointer = k - 1 end - end - end - - instructionPointer = instructionPointer + 1 - if instructionPointer > content:len() then print("") break end - end -end - --- None - -languages.none.helpTips = {} -languages.none.defaultHelpTips = {} -languages.none.errors = {} -languages.none.keywords = {} - -languages.none.parseError = function(err) - return {filename = "", line = -1, display = "", err = ""} -end - -languages.none.getCompilerErrors = function(code) - return languages.none.parseError(nil) -end - -languages.none.run = function(path) end - - --- Load language -curLanguage = languages.lua - - --- -------- Run GUI - -local function viewErrorHelp(e) - title("LuaIDE - Error Help") - - local tips = nil - for k, v in pairs(curLanguage.errors) do - if e.display:find(k) then tips = v break end - end - - term.setBackgroundColor(colors[theme.err]) - for i = 6, 8 do - term.setCursorPos(5, i) - term.write(string.rep(" ", 35)) - end - - term.setBackgroundColor(colors[theme.prompt]) - for i = 10, 18 do - term.setCursorPos(5, i) - term.write(string.rep(" ", 46)) - end - - if tips then - term.setBackgroundColor(colors[theme.err]) - term.setCursorPos(6, 7) - term.write("Error Help") - - term.setBackgroundColor(colors[theme.prompt]) - for i, v in ipairs(tips) do - term.setCursorPos(7, i + 10) - term.write("- " .. curLanguage.helpTips[v]) - end - else - term.setBackgroundColor(colors[theme.err]) - term.setCursorPos(6, 7) - term.write("No Error Tips Available!") - - term.setBackgroundColor(colors[theme.prompt]) - term.setCursorPos(6, 11) - term.write("There are no error tips available, but") - term.setCursorPos(6, 12) - term.write("you could see if it was any of these:") - - for i, v in ipairs(curLanguage.defaultHelpTips) do - term.setCursorPos(7, i + 12) - term.write("- " .. curLanguage.helpTips[v]) - end - end - - prompt({{"Back", w - 8, 7}}, "horizontal") -end - -local function run(path, lines, useArgs) - local ar = {} - if useArgs then - title("LuaIDE - Run " .. fs.getName(path)) - local s = centerRead(w - 13, fs.getName(path) .. " ") - for m in string.gmatch(s, "[^ \t]+") do ar[#ar + 1] = m:gsub("^%s*(.-)%s*$", "%1") end - end - - saveFile(path, lines) - term.setCursorBlink(false) - term.setBackgroundColor(colors.black) - term.setTextColor(colors.white) - term.clear() - term.setCursorPos(1, 1) - local err = curLanguage.run(path, ar) - - term.setBackgroundColor(colors.black) - print("\n") - if err then - if isAdvanced() then term.setTextColor(colors.red) end - centerPrint("The program has crashed!") - end - term.setTextColor(colors.white) - centerPrint("Press any key to return to LuaIDE...") - while true do - local e = os.pullEvent() - if e == "key" then break end - end - - -- To prevent key from showing up in editor - os.queueEvent(event_distract) - os.pullEvent() - - if err then - if curLanguage == languages.lua and err:find("]") then - err = fs.getName(path) .. err:sub(err:find("]", 1, true) + 1, -1) - end - - while true do - title("LuaIDE - Error!") - - term.setBackgroundColor(colors[theme.err]) - for i = 6, 8 do - term.setCursorPos(3, i) - term.write(string.rep(" ", w - 5)) - end - term.setCursorPos(4, 7) - term.write("The program has crashed!") - - term.setBackgroundColor(colors[theme.prompt]) - for i = 10, 14 do - term.setCursorPos(3, i) - term.write(string.rep(" ", w - 5)) - end - - local formattedErr = curLanguage.parseError(err) - term.setCursorPos(4, 11) - term.write("Line: " .. formattedErr.line) - term.setCursorPos(4, 12) - term.write("Error:") - term.setCursorPos(5, 13) - - local a = formattedErr.display - local b = nil - if a:len() > w - 8 then - for i = a:len(), 1, -1 do - if a:sub(i, i) == " " then - b = a:sub(i + 1, -1) - a = a:sub(1, i) - break - end - end - end - - term.write(a) - if b then - term.setCursorPos(5, 14) - term.write(b) - end - - local opt = prompt({{"Error Help", w/2 - 15, 17}, {"Go To Line", w/2 + 2, 17}}, - "horizontal") - if opt == "Error Help" then - viewErrorHelp(formattedErr) - elseif opt == "Go To Line" then - -- To prevent key from showing up in editor - os.queueEvent(event_distract) - os.pullEvent() - - return "go to", tonumber(formattedErr.line) - end - end - end -end - - --- -------- Functions - -local function goto() - term.setBackgroundColor(colors[theme.backgroundHighlight]) - term.setCursorPos(2, 1) - term.clearLine() - term.write("Line: ") - local line = modRead({visibleLength = w - 2}) - - local num = tonumber(line) - if num and num > 0 then return num - else - term.setCursorPos(2, 1) - term.clearLine() - term.write("Not a line number!") - sleep(1.6) - return nil - end -end - -local function setsyntax() - local opts = { - "[Lua] Brainfuck None ", - " Lua [Brainfuck] None ", - " Lua Brainfuck [None]" - } - local sel = 1 - - term.setCursorBlink(false) - term.setBackgroundColor(colors[theme.backgroundHighlight]) - term.setCursorPos(2, 1) - term.clearLine() - term.write(opts[sel]) - while true do - local e, but, x, y = os.pullEvent("key") - if but == 203 then - sel = math.max(1, sel - 1) - term.setCursorPos(2, 1) - term.clearLine() - term.write(opts[sel]) - elseif but == 205 then - sel = math.min(#opts, sel + 1) - term.setCursorPos(2, 1) - term.clearLine() - term.write(opts[sel]) - elseif but == 28 then - if sel == 1 then curLanguage = languages.lua - elseif sel == 2 then curLanguage = languages.brainfuck - elseif sel == 3 then curLanguage = languages.none end - term.setCursorBlink(true) - return - end - end -end - - --- -------- Re-Indenting - -local tabWidth = 2 - -local comments = {} -local strings = {} - -local increment = { - "if%s+.+%s+then%s*$", - "for%s+.+%s+do%s*$", - "while%s+.+%s+do%s*$", - "repeat%s*$", - "function%s+[a-zA-Z_0-9]\(.*\)%s*$" -} - -local decrement = { - "end", - "until%s+.+" -} - -local special = { - "else%s*$", - "elseif%s+.+%s+then%s*$" -} - -local function check(func) - for _, v in pairs(func) do - local cLineStart = v["lineStart"] - local cLineEnd = v["lineEnd"] - local cCharStart = v["charStart"] - local cCharEnd = v["charEnd"] - - if line >= cLineStart and line <= cLineEnd then - if line == cLineStart then return cCharStart < charNumb - elseif line == cLineEnd then return cCharEnd > charNumb - else return true end - end - end -end - -local function isIn(line, loc) - if check(comments) then return true end - if check(strings) then return true end - return false -end - -local function setComment(ls, le, cs, ce) - comments[#comments + 1] = {} - comments[#comments].lineStart = ls - comments[#comments].lineEnd = le - comments[#comments].charStart = cs - comments[#comments].charEnd = ce -end - -local function setString(ls, le, cs, ce) - strings[#strings + 1] = {} - strings[#strings].lineStart = ls - strings[#strings].lineEnd = le - strings[#strings].charStart = cs - strings[#strings].charEnd = ce -end - -local function map(contents) - local inCom = false - local inStr = false - - for i = 1, #contents do - if content[i]:find("%-%-%[%[") and not inStr and not inCom then - local cStart = content[i]:find("%-%-%[%[") - setComment(i, nil, cStart, nil) - inCom = true - elseif content[i]:find("%-%-%[=%[") and not inStr and not inCom then - local cStart = content[i]:find("%-%-%[=%[") - setComment(i, nil, cStart, nil) - inCom = true - elseif content[i]:find("%[%[") and not inStr and not inCom then - local cStart = content[i]:find("%[%[") - setString(i, nil, cStart, nil) - inStr = true - elseif content[i]:find("%[=%[") and not inStr and not inCom then - local cStart = content[i]:find("%[=%[") - setString(i, nil, cStart, nil) - inStr = true - end - - if content[i]:find("%]%]") and inStr and not inCom then - local cStart, cEnd = content[i]:find("%]%]") - strings[#strings].lineEnd = i - strings[#strings].charEnd = cEnd - inStr = false - elseif content[i]:find("%]=%]") and inStr and not inCom then - local cStart, cEnd = content[i]:find("%]=%]") - strings[#strings].lineEnd = i - strings[#strings].charEnd = cEnd - inStr = false - end - - if content[i]:find("%]%]") and not inStr and inCom then - local cStart, cEnd = content[i]:find("%]%]") - comments[#comments].lineEnd = i - comments[#comments].charEnd = cEnd - inCom = false - elseif content[i]:find("%]=%]") and not inStr and inCom then - local cStart, cEnd = content[i]:find("%]=%]") - comments[#comments].lineEnd = i - comments[#comments].charEnd = cEnd - inCom = false - end - - if content[i]:find("%-%-") and not inStr and not inCom then - local cStart = content[i]:find("%-%-") - setComment(i, i, cStart, -1) - elseif content[i]:find("'") and not inStr and not inCom then - local cStart, cEnd = content[i]:find("'") - local nextChar = content[i]:sub(cEnd + 1, string.len(content[i])) - local _, cEnd = nextChar:find("'") - setString(i, i, cStart, cEnd) - elseif content[i]:find('"') and not inStr and not inCom then - local cStart, cEnd = content[i]:find('"') - local nextChar = content[i]:sub(cEnd + 1, string.len(content[i])) - local _, cEnd = nextChar:find('"') - setString(i, i, cStart, cEnd) - end - end -end - -local function reindent(contents) - local err = nil - if curLanguage ~= languages.lua then - err = "Cannot indent languages other than Lua!" - elseif curLanguage.getCompilerErrors(table.concat(contents, "\n")).line ~= -1 then - err = "Cannot indent a program with errors!" - end - - if err then - term.setCursorBlink(false) - term.setCursorPos(2, 1) - term.setBackgroundColor(colors[theme.backgroundHighlight]) - term.clearLine() - term.write(err) - sleep(1.6) - return contents - end - - local new = {} - local level = 0 - for k, v in pairs(contents) do - local incrLevel = false - local foundIncr = false - for _, incr in pairs(increment) do - if v:find(incr) and not isIn(k, v:find(incr)) then - incrLevel = true - end - if v:find(incr:sub(1, -2)) and not isIn(k, v:find(incr)) then - foundIncr = true - end - end - - local decrLevel = false - if not incrLevel then - for _, decr in pairs(decrement) do - if v:find(decr) and not isIn(k, v:find(decr)) and not foundIncr then - level = math.max(0, level - 1) - decrLevel = true - end - end - end - - if not decrLevel then - for _, sp in pairs(special) do - if v:find(sp) and not isIn(k, v:find(sp)) then - incrLevel = true - level = math.max(0, level - 1) - end - end - end - - new[k] = string.rep(" ", level * tabWidth) .. v - if incrLevel then level = level + 1 end - end - - return new -end - - --- -------- Menu - -local menu = { - [1] = {"File", --- "About", --- "Settings", --- "", - "New File ^+N", - "Open File ^+O", - "Save File ^+S", - "Close ^+W", - "Print ^+P", - "Quit ^+Q" - }, [2] = {"Edit", - "Cut Line ^+X", - "Copy Line ^+C", - "Paste Line ^+V", - "Delete Line", - "Clear Line" - }, [3] = {"Functions", - "Go To Line ^+G", - "Re-Indent ^+I", - "Set Syntax ^+E", - "Start of Line ^+<", - "End of Line ^+>" - }, [4] = {"Run", - "Run Program ^+R", - "Run w/ Args ^+Shift+R" - } -} - -local shortcuts = { - -- File - ["ctrl n"] = "New File ^+N", - ["ctrl o"] = "Open File ^+O", - ["ctrl s"] = "Save File ^+S", - ["ctrl w"] = "Close ^+W", - ["ctrl p"] = "Print ^+P", - ["ctrl q"] = "Quit ^+Q", - - -- Edit - ["ctrl x"] = "Cut Line ^+X", - ["ctrl c"] = "Copy Line ^+C", - ["ctrl v"] = "Paste Line ^+V", - - -- Functions - ["ctrl g"] = "Go To Line ^+G", - ["ctrl i"] = "Re-Indent ^+I", - ["ctrl e"] = "Set Syntax ^+E", - ["ctrl 203"] = "Start of Line ^+<", - ["ctrl 205"] = "End of Line ^+>", - - -- Run - ["ctrl r"] = "Run Program ^+R", - ["ctrl shift r"] = "Run w/ Args ^+Shift+R" -} - -local menuFunctions = { - -- File --- ["About"] = function() end, --- ["Settings"] = function() end, - ["New File ^+N"] = function(path, lines) saveFile(path, lines) return "new" end, - ["Open File ^+O"] = function(path, lines) saveFile(path, lines) return "open" end, - ["Save File ^+S"] = function(path, lines) saveFile(path, lines) end, - ["Close ^+W"] = function(path, lines) saveFile(path, lines) return "menu" end, - ["Print ^+P"] = function(path, lines) saveFile(path, lines) return nil end, - ["Quit ^+Q"] = function(path, lines) saveFile(path, lines) return "exit" end, - - -- Edit - ["Cut Line ^+X"] = function(path, lines, y) - clipboard = lines[y] table.remove(lines, y) return nil, lines end, - ["Copy Line ^+C"] = function(path, lines, y) clipboard = lines[y] end, - ["Paste Line ^+V"] = function(path, lines, y) - if clipboard then table.insert(lines, y, clipboard) end return nil, lines end, - ["Delete Line"] = function(path, lines, y) table.remove(lines, y) return nil, lines end, - ["Clear Line"] = function(path, lines, y) lines[y] = "" return nil, lines, "cursor" end, - - -- Functions - ["Go To Line ^+G"] = function() return nil, "go to", goto() end, - ["Re-Indent ^+I"] = function(path, lines) - local a = reindent(lines) saveFile(path, lines) return nil, a - end, - ["Set Syntax ^+E"] = function(path, lines) - setsyntax() - if curLanguage == languages.brainfuck and lines[1] ~= "-- Syntax: Brainfuck" then - table.insert(lines, 1, "-- Syntax: Brainfuck") - return nil, lines - end - end, - ["Start of Line ^+<"] = function() os.queueEvent("key", 199) end, - ["End of Line ^+>"] = function() os.queueEvent("key", 207) end, - - -- Run - ["Run Program ^+R"] = function(path, lines) - saveFile(path, lines) - return nil, run(path, lines, false) - end, - ["Run w/ Args ^+Shift+R"] = function(path, lines) - saveFile(path, lines) - return nil, run(path, lines, true) - end, -} - -local function drawMenu(open) - term.setCursorPos(1, 1) - term.setTextColor(colors[theme.textColor]) - term.setBackgroundColor(colors[theme.backgroundHighlight]) - term.clearLine() - local curX = 0 - for _, v in pairs(menu) do - term.setCursorPos(3 + curX, 1) - term.write(v[1]) - curX = curX + v[1]:len() + 3 - end - - if open then - local it = {} - local x = 1 - for _, v in pairs(menu) do - if open == v[1] then - it = v - break - end - x = x + v[1]:len() + 3 - end - x = x + 1 - - local items = {} - for i = 2, #it do - table.insert(items, it[i]) - end - - local len = 1 - for _, v in pairs(items) do if v:len() + 2 > len then len = v:len() + 2 end end - - for i, v in ipairs(items) do - term.setCursorPos(x, i + 1) - term.write(string.rep(" ", len)) - term.setCursorPos(x + 1, i + 1) - term.write(v) - end - term.setCursorPos(x, #items + 2) - term.write(string.rep(" ", len)) - return items, len - end -end - -local function triggerMenu(cx, cy) - -- Determine clicked menu - local curX = 0 - local open = nil - for _, v in pairs(menu) do - if cx >= curX + 3 and cx <= curX + v[1]:len() + 2 then - open = v[1] - break - end - curX = curX + v[1]:len() + 3 - end - local menux = curX + 2 - if not open then return false end - - -- Flash menu item - term.setCursorBlink(false) - term.setCursorPos(menux, 1) - term.setBackgroundColor(colors[theme.background]) - term.write(string.rep(" ", open:len() + 2)) - term.setCursorPos(menux + 1, 1) - term.write(open) - sleep(0.1) - local items, len = drawMenu(open) - - local ret = true - - -- Pull events on menu - local ox, oy = term.getCursorPos() - while type(ret) ~= "string" do - local e, but, x, y = os.pullEvent() - if e == "mouse_click" then - -- If clicked outside menu - if x < menux - 1 or x > menux + len - 1 then break - elseif y > #items + 2 then break - elseif y == 1 then break end - - for i, v in ipairs(items) do - if y == i + 1 and x >= menux and x <= menux + len - 2 then - -- Flash when clicked - term.setCursorPos(menux, y) - term.setBackgroundColor(colors[theme.background]) - term.write(string.rep(" ", len)) - term.setCursorPos(menux + 1, y) - term.write(v) - sleep(0.1) - drawMenu(open) - - -- Return item - ret = v - break - end - end - end - end - - term.setCursorPos(ox, oy) - term.setCursorBlink(true) - return ret -end - - --- -------- Editing - -local standardsCompletions = { - "if%s+.+%s+then%s*$", - "for%s+.+%s+do%s*$", - "while%s+.+%s+do%s*$", - "repeat%s*$", - "function%s+[a-zA-Z_0-9]?\(.*\)%s*$", - "=%s*function%s*\(.*\)%s*$", - "else%s*$", - "elseif%s+.+%s+then%s*$" -} - -local liveCompletions = { - ["("] = ")", - ["{"] = "}", - ["["] = "]", - ["\""] = "\"", - ["'"] = "'", -} - -local x, y = 0, 0 -local edw, edh = 0, h - 1 -local offx, offy = 0, 1 -local scrollx, scrolly = 0, 0 -local lines = {} -local liveErr = curLanguage.parseError(nil) -local displayCode = true -local lastEventClock = os.clock() - -local function attemptToHighlight(line, regex, col) - local match = string.match(line, regex) - if match then - if type(col) == "number" then term.setTextColor(col) - elseif type(col) == "function" then term.setTextColor(col(match)) end - term.write(match) - term.setTextColor(colors[theme.textColor]) - return line:sub(match:len() + 1, -1) - end - return nil -end - -local function writeHighlighted(line) - if curLanguage == languages.lua then - while line:len() > 0 do - line = attemptToHighlight(line, "^%-%-%[%[.-%]%]", colors[theme.comment]) or - attemptToHighlight(line, "^%-%-.*", colors[theme.comment]) or - attemptToHighlight(line, "^\".*[^\\]\"", colors[theme.string]) or - attemptToHighlight(line, "^\'.*[^\\]\'", colors[theme.string]) or - attemptToHighlight(line, "^%[%[.-%]%]", colors[theme.string]) or - attemptToHighlight(line, "^[%w_]+", function(match) - if curLanguage.keywords[match] then - return colors[theme[curLanguage.keywords[match]]] - end - return colors[theme.textColor] - end) or - attemptToHighlight(line, "^[^%w_]", colors[theme.textColor]) - end - else term.write(line) end -end - -local function draw() - -- Menu - term.setTextColor(colors[theme.textColor]) - term.setBackgroundColor(colors[theme.editorBackground]) - term.clear() - drawMenu() - - -- Line numbers - offx, offy = tostring(#lines):len() + 1, 1 - edw, edh = w - offx, h - 1 - - -- Draw text - for i = 1, edh do - local a = lines[scrolly + i] - if a then - local ln = string.rep(" ", offx - 1 - tostring(scrolly + i):len()) .. tostring(scrolly + i) - local l = a:sub(scrollx + 1, edw + scrollx + 1) - ln = ln .. ":" - - if liveErr.line == scrolly + i then ln = string.rep(" ", offx - 2) .. "!:" end - - term.setCursorPos(1, i + offy) - term.setBackgroundColor(colors[theme.editorBackground]) - if scrolly + i == y then - if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then - term.setBackgroundColor(colors[theme.editorErrorHighlight]) - else term.setBackgroundColor(colors[theme.editorLineHightlight]) end - term.clearLine() - elseif scrolly + i == liveErr.line then - term.setBackgroundColor(colors[theme.editorError]) - term.clearLine() - end - - term.setCursorPos(1 - scrollx + offx, i + offy) - if scrolly + i == y then - if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then - term.setBackgroundColor(colors[theme.editorErrorHighlight]) - else term.setBackgroundColor(colors[theme.editorLineHightlight]) end - elseif scrolly + i == liveErr.line then term.setBackgroundColor(colors[theme.editorError]) - else term.setBackgroundColor(colors[theme.editorBackground]) end - if scrolly + i == liveErr.line then - if displayCode then term.write(a) - else term.write(liveErr.display) end - else writeHighlighted(a) end - - term.setCursorPos(1, i + offy) - if scrolly + i == y then - if scrolly + i == liveErr.line and os.clock() - lastEventClock > 3 then - term.setBackgroundColor(colors[theme.editorError]) - else term.setBackgroundColor(colors[theme.editorLineNumbersHighlight]) end - elseif scrolly + i == liveErr.line then - term.setBackgroundColor(colors[theme.editorErrorHighlight]) - else term.setBackgroundColor(colors[theme.editorLineNumbers]) end - term.write(ln) - end - end - term.setCursorPos(x - scrollx + offx, y - scrolly + offy) -end - -local function drawLine(...) - local ls = {...} - offx = tostring(#lines):len() + 1 - for _, ly in pairs(ls) do - local a = lines[ly] - if a then - local ln = string.rep(" ", offx - 1 - tostring(ly):len()) .. tostring(ly) - local l = a:sub(scrollx + 1, edw + scrollx + 1) - ln = ln .. ":" - - if liveErr.line == ly then ln = string.rep(" ", offx - 2) .. "!:" end - - term.setCursorPos(1, (ly - scrolly) + offy) - term.setBackgroundColor(colors[theme.editorBackground]) - if ly == y then - if ly == liveErr.line and os.clock() - lastEventClock > 3 then - term.setBackgroundColor(colors[theme.editorErrorHighlight]) - else term.setBackgroundColor(colors[theme.editorLineHightlight]) end - elseif ly == liveErr.line then - term.setBackgroundColor(colors[theme.editorError]) - end - term.clearLine() - - term.setCursorPos(1 - scrollx + offx, (ly - scrolly) + offy) - if ly == y then - if ly == liveErr.line and os.clock() - lastEventClock > 3 then - term.setBackgroundColor(colors[theme.editorErrorHighlight]) - else term.setBackgroundColor(colors[theme.editorLineHightlight]) end - elseif ly == liveErr.line then term.setBackgroundColor(colors[theme.editorError]) - else term.setBackgroundColor(colors[theme.editorBackground]) end - if ly == liveErr.line then - if displayCode then term.write(a) - else term.write(liveErr.display) end - else writeHighlighted(a) end - - term.setCursorPos(1, (ly - scrolly) + offy) - if ly == y then - if ly == liveErr.line and os.clock() - lastEventClock > 3 then - term.setBackgroundColor(colors[theme.editorError]) - else term.setBackgroundColor(colors[theme.editorLineNumbersHighlight]) end - elseif ly == liveErr.line then - term.setBackgroundColor(colors[theme.editorErrorHighlight]) - else term.setBackgroundColor(colors[theme.editorLineNumbers]) end - term.write(ln) - end - end - term.setCursorPos(x - scrollx + offx, y - scrolly + offy) -end - -local function cursorLoc(x, y, force) - local sx, sy = x - scrollx, y - scrolly - local redraw = false - if sx < 1 then - scrollx = x - 1 - sx = 1 - redraw = true - elseif sx > edw then - scrollx = x - edw - sx = edw - redraw = true - end if sy < 1 then - scrolly = y - 1 - sy = 1 - redraw = true - elseif sy > edh then - scrolly = y - edh - sy = edh - redraw = true - end if redraw or force then draw() end - term.setCursorPos(sx + offx, sy + offy) -end - -local function executeMenuItem(a, path) - if type(a) == "string" and menuFunctions[a] then - local opt, nl, gtln = menuFunctions[a](path, lines, y) - if type(opt) == "string" then term.setCursorBlink(false) return opt end - if type(nl) == "table" then - if #lines < 1 then table.insert(lines, "") end - y = math.min(y, #lines) - x = math.min(x, lines[y]:len() + 1) - lines = nl - elseif type(nl) == "string" then - if nl == "go to" and gtln then - x, y = 1, math.min(#lines, gtln) - cursorLoc(x, y) - end - end - end - term.setCursorBlink(true) - draw() - term.setCursorPos(x - scrollx + offx, y - scrolly + offy) -end - -local function edit(path) - -- Variables - x, y = 1, 1 - offx, offy = 0, 1 - scrollx, scrolly = 0, 0 - lines = loadFile(path) - if not lines then return "menu" end - - -- Enable brainfuck - if lines[1] == "-- Syntax: Brainfuck" then - curLanguage = languages.brainfuck - end - - -- Clocks - local autosaveClock = os.clock() - local scrollClock = os.clock() -- To prevent redraw flicker - local liveErrorClock = os.clock() - local hasScrolled = false - - -- Draw - draw() - term.setCursorPos(x + offx, y + offy) - term.setCursorBlink(true) - - -- Main loop - local tid = os.startTimer(3) - while true do - local e, key, cx, cy = os.pullEvent() - if e == "key" and allowEditorEvent then - if key == 200 and y > 1 then - -- Up - x, y = math.min(x, lines[y - 1]:len() + 1), y - 1 - drawLine(y, y + 1) - cursorLoc(x, y) - elseif key == 208 and y < #lines then - -- Down - x, y = math.min(x, lines[y + 1]:len() + 1), y + 1 - drawLine(y, y - 1) - cursorLoc(x, y) - elseif key == 203 and x > 1 then - -- Left - x = x - 1 - local force = false - if y - scrolly + offy < offy + 1 then force = true end - cursorLoc(x, y, force) - elseif key == 205 and x < lines[y]:len() + 1 then - -- Right - x = x + 1 - local force = false - if y - scrolly + offy < offy + 1 then force = true end - cursorLoc(x, y, force) - elseif (key == 28 or key == 156) and (displayCode and true or y + scrolly - 1 == - liveErr.line) then - -- Enter - local f = nil - for _, v in pairs(standardsCompletions) do - if lines[y]:find(v) then f = v end - end - - local _, spaces = lines[y]:find("^[ ]+") - if not spaces then spaces = 0 end - if f then - table.insert(lines, y + 1, string.rep(" ", spaces + 2)) - if not f:find("else", 1, true) and not f:find("elseif", 1, true) then - table.insert(lines, y + 2, string.rep(" ", spaces) .. - (f:find("repeat", 1, true) and "until " or f:find("{", 1, true) and "}" or - "end")) - end - x, y = spaces + 3, y + 1 - cursorLoc(x, y, true) - else - local oldLine = lines[y] - - lines[y] = lines[y]:sub(1, x - 1) - table.insert(lines, y + 1, string.rep(" ", spaces) .. oldLine:sub(x, -1)) - - x, y = spaces + 1, y + 1 - cursorLoc(x, y, true) - end - elseif key == 14 and (displayCode and true or y + scrolly - 1 == liveErr.line) then - -- Backspace - if x > 1 then - local f = false - for k, v in pairs(liveCompletions) do - if lines[y]:sub(x - 1, x - 1) == k then f = true end - end - - lines[y] = lines[y]:sub(1, x - 2) .. lines[y]:sub(x + (f and 1 or 0), -1) - drawLine(y) - x = x - 1 - cursorLoc(x, y) - elseif y > 1 then - local prevLen = lines[y - 1]:len() + 1 - lines[y - 1] = lines[y - 1] .. lines[y] - table.remove(lines, y) - x, y = prevLen, y - 1 - cursorLoc(x, y, true) - end - elseif key == 199 then - -- Home - x = 1 - local force = false - if y - scrolly + offy < offy + 1 then force = true end - cursorLoc(x, y, force) - elseif key == 207 then - -- End - x = lines[y]:len() + 1 - local force = false - if y - scrolly + offy < offy + 1 then force = true end - cursorLoc(x, y, force) - elseif key == 211 and (displayCode and true or y + scrolly - 1 == liveErr.line) then - -- Forward Delete - if x < lines[y]:len() + 1 then - lines[y] = lines[y]:sub(1, x - 1) .. lines[y]:sub(x + 1) - local force = false - if y - scrolly + offy < offy + 1 then force = true end - drawLine(y) - cursorLoc(x, y, force) - elseif y < #lines then - lines[y] = lines[y] .. lines[y + 1] - table.remove(lines, y + 1) - draw() - cursorLoc(x, y) - end - elseif key == 15 and (displayCode and true or y + scrolly - 1 == liveErr.line) then - -- Tab - lines[y] = string.rep(" ", tabWidth) .. lines[y] - x = x + 2 - local force = false - if y - scrolly + offy < offy + 1 then force = true end - drawLine(y) - cursorLoc(x, y, force) - elseif key == 201 then - -- Page up - y = math.min(math.max(y - edh, 1), #lines) - x = math.min(lines[y]:len() + 1, x) - cursorLoc(x, y, true) - elseif key == 209 then - -- Page down - y = math.min(math.max(y + edh, 1), #lines) - x = math.min(lines[y]:len() + 1, x) - cursorLoc(x, y, true) - end - elseif e == "char" and allowEditorEvent and (displayCode and true or - y + scrolly - 1 == liveErr.line) then - local shouldIgnore = false - for k, v in pairs(liveCompletions) do - if key == v and lines[y]:find(k, 1, true) and lines[y]:sub(x, x) == v then - shouldIgnore = true - end - end - - local addOne = false - if not shouldIgnore then - for k, v in pairs(liveCompletions) do - if key == k and lines[y]:sub(x, x) ~= k then key = key .. v addOne = true end - end - lines[y] = lines[y]:sub(1, x - 1) .. key .. lines[y]:sub(x, -1) - end - - x = x + (addOne and 1 or key:len()) - local force = false - if y - scrolly + offy < offy + 1 then force = true end - drawLine(y) - cursorLoc(x, y, force) - elseif e == "mouse_click" and key == 1 then - if cy > 1 then - if cx <= offx and cy - offy == liveErr.line - scrolly then - displayCode = not displayCode - drawLine(liveErr.line) - else - local oldy = y - y = math.min(math.max(scrolly + cy - offy, 1), #lines) - x = math.min(math.max(scrollx + cx - offx, 1), lines[y]:len() + 1) - if oldy ~= y then drawLine(oldy, y) end - cursorLoc(x, y) - end - else - local a = triggerMenu(cx, cy) - if a then - local opt = executeMenuItem(a, path) - if opt then return opt end - end - end - elseif e == "shortcut" then - local a = shortcuts[key .. " " .. cx] - if a then - local parent = nil - local curx = 0 - for i, mv in ipairs(menu) do - for _, iv in pairs(mv) do - if iv == a then - parent = menu[i][1] - break - end - end - if parent then break end - curx = curx + mv[1]:len() + 3 - end - local menux = curx + 2 - - -- Flash menu item - term.setCursorBlink(false) - term.setCursorPos(menux, 1) - term.setBackgroundColor(colors[theme.background]) - term.write(string.rep(" ", parent:len() + 2)) - term.setCursorPos(menux + 1, 1) - term.write(parent) - sleep(0.1) - drawMenu() - - -- Execute item - local opt = executeMenuItem(a, path) - if opt then return opt end - end - elseif e == "mouse_scroll" then - if key == -1 and scrolly > 0 then - scrolly = scrolly - 1 - if os.clock() - scrollClock > 0.0005 then - draw() - term.setCursorPos(x - scrollx + offx, y - scrolly + offy) - end - scrollClock = os.clock() - hasScrolled = true - elseif key == 1 and scrolly < #lines - edh then - scrolly = scrolly + 1 - if os.clock() - scrollClock > 0.0005 then - draw() - term.setCursorPos(x - scrollx + offx, y - scrolly + offy) - end - scrollClock = os.clock() - hasScrolled = true - end - elseif e == "timer" and key == tid then - drawLine(y) - tid = os.startTimer(3) - end - - -- Draw - if hasScrolled and os.clock() - scrollClock > 0.1 then - draw() - term.setCursorPos(x - scrollx + offx, y - scrolly + offy) - hasScrolled = false - end - - -- Autosave - if os.clock() - autosaveClock > autosaveInterval then - saveFile(path, lines) - autosaveClock = os.clock() - end - - -- Errors - if os.clock() - liveErrorClock > 1 then - local prevLiveErr = liveErr - liveErr = curLanguage.parseError(nil) - local code = "" - for _, v in pairs(lines) do code = code .. v .. "\n" end - - liveErr = curLanguage.getCompilerErrors(code) - liveErr.line = math.min(liveErr.line - 2, #lines) - if liveErr ~= prevLiveErr then draw() end - liveErrorClock = os.clock() - end - end - - return "menu" -end - - --- -------- Open File - -local function newFile() - local wid = w - 13 - - -- Get name - title("Lua IDE - New File") - local name = centerRead(wid, "/") - if not name or name == "" then return "menu" end - name = "/" .. name - - -- Clear - title("Lua IDE - New File") - term.setTextColor(colors[theme.textColor]) - term.setBackgroundColor(colors[theme.promptHighlight]) - for i = 8, 10 do - term.setCursorPos(w/2 - wid/2, i) - term.write(string.rep(" ", wid)) - end - term.setCursorPos(1, 9) - if fs.isDir(name) then - centerPrint("Cannot Edit a Directory!") - sleep(1.6) - return "menu" - elseif fs.exists(name) then - centerPrint("File Already Exists!") - local opt = prompt({{"Open", w/2 - 9, 14}, {"Cancel", w/2 + 2, 14}}, "horizontal") - if opt == "Open" then return "edit", name - elseif opt == "Cancel" then return "menu" end - else return "edit", name end -end - -local function openFile() - local wid = w - 13 - - -- Get name - title("Lua IDE - Open File") - local name = centerRead(wid, "/") - if not name or name == "" then return "menu" end - name = "/" .. name - - -- Clear - title("Lua IDE - New File") - term.setTextColor(colors[theme.textColor]) - term.setBackgroundColor(colors[theme.promptHighlight]) - for i = 8, 10 do - term.setCursorPos(w/2 - wid/2, i) - term.write(string.rep(" ", wid)) - end - term.setCursorPos(1, 9) - if fs.isDir(name) then - centerPrint("Cannot Open a Directory!") - sleep(1.6) - return "menu" - elseif not fs.exists(name) then - centerPrint("File Doesn't Exist!") - local opt = prompt({{"Create", w/2 - 11, 14}, {"Cancel", w/2 + 2, 14}}, "horizontal") - if opt == "Create" then return "edit", name - elseif opt == "Cancel" then return "menu" end - else return "edit", name end -end - - --- -------- Settings - -local function update() ---[[ - local function draw(status) - title("LuaIDE - Update") - term.setBackgroundColor(colors[theme.prompt]) - term.setTextColor(colors[theme.textColor]) - for i = 8, 10 do - term.setCursorPos(w/2 - (status:len() + 4), i) - write(string.rep(" ", status:len() + 4)) - end - term.setCursorPos(w/2 - (status:len() + 4), 9) - term.write(" - " .. status .. " ") - - term.setBackgroundColor(colors[theme.errHighlight]) - for i = 8, 10 do - term.setCursorPos(w/2 + 2, i) - term.write(string.rep(" ", 10)) - end - term.setCursorPos(w/2 + 2, 9) - term.write(" > Cancel ") - end - - if not http then - draw("HTTP API Disabled!") - sleep(1.6) - return "settings" - end - - draw("Updating...") - local tID = os.startTimer(10) - http.request(updateURL) - while true do - local e, but, x, y = os.pullEvent() - if (e == "key" and but == 28) or - (e == "mouse_click" and x >= w/2 + 2 and x <= w/2 + 12 and y == 9) then - draw("Cancelled") - sleep(1.6) - break - elseif e == "http_success" and but == updateURL then - local new = x.readAll() - local curf = io.open(ideLocation, "r") - local cur = curf:read("*a") - curf:close() - - if cur ~= new then - draw("Update Found") - sleep(1.6) - local f = io.open(ideLocation, "w") - f:write(new) - f:close() - - draw("Click to Exit") - while true do - local e = os.pullEvent() - if e == "mouse_click" or (not isAdvanced() and e == "key") then break end - end - return "exit" - else - draw("No Updates Found!") - sleep(1.6) - break - end - elseif e == "http_failure" or (e == "timer" and but == tID) then - draw("Update Failed!") - sleep(1.6) - break - end - end -]]-- - - return "settings" -end - -local function changeTheme() - title("LuaIDE - Theme") - term.setCursorPos(1, 7) - centerPrint("Themes are not available on the") - centerPrint("treasure disk version of LuaIDE!") - centerPrint("Download the full program from the") - centerPrint("ComputerCraft Forums!") - ---[[ - if isAdvanced() then - local disThemes = {"Back"} - for _, v in pairs(availableThemes) do table.insert(disThemes, v[1]) end - local t = scrollingPrompt(disThemes) - local url = nil - for _, v in pairs(availableThemes) do if v[1] == t then url = v[2] end end - - if not url then return "settings" end - if t == "Dawn (Default)" then - term.setBackgroundColor(colors[theme.backgroundHighlight]) - term.setCursorPos(3, 3) - term.clearLine() - term.write("LuaIDE - Loaded Theme!") - sleep(1.6) - - fs.delete(themeLocation) - theme = defaultTheme - return "menu" - end - - term.setBackgroundColor(colors[theme.backgroundHighlight]) - term.setCursorPos(3, 3) - term.clearLine() - term.write("LuaIDE - Downloading...") - - fs.delete("/.LuaIDE_temp_theme_file") - download(url, "/.LuaIDE_temp_theme_file") - local a = loadTheme("/.LuaIDE_temp_theme_file") - - term.setCursorPos(3, 3) - term.clearLine() - if a then - term.write("LuaIDE - Loaded Theme!") - fs.delete(themeLocation) - fs.move("/.LuaIDE_temp_theme_file", themeLocation) - theme = a - sleep(1.6) - return "menu" - end - - term.write("LuaIDE - Could Not Load Theme!") - fs.delete("/.LuaIDE_temp_theme_file") - sleep(1.6) - return "settings" - else - term.setCursorPos(1, 8) - centerPrint("Themes are not available on") - centerPrint("normal computers!") - end -]]-- -end - -local function settings() - title("LuaIDE - Settings") - - local opt = prompt({{"Change Theme", w/2 - 17, 8}, {"Return to Menu", w/2 - 19, 13}, - --[[{"Check for Updates", w/2 + 2, 8},]] {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err], - highlight = colors[theme.errHighlight]}}, "vertical", true) - if opt == "Change Theme" then return changeTheme() --- elseif opt == "Check for Updates" then return update() - elseif opt == "Return to Menu" then return "menu" - elseif opt == "Exit IDE" then return "exit" end -end - - --- -------- Menu - -local function menu() - title("Welcome to LuaIDE " .. version) - - local opt = prompt({{"New File", w/2 - 13, 8}, {"Open File", w/2 - 14, 13}, - {"Settings", w/2 + 2, 8}, {"Exit IDE", w/2 + 2, 13, bg = colors[theme.err], - highlight = colors[theme.errHighlight]}}, "vertical", true) - if opt == "New File" then return "new" - elseif opt == "Open File" then return "open" - elseif opt == "Settings" then return "settings" - elseif opt == "Exit IDE" then return "exit" end -end - - --- -------- Main - -local function main(arguments) - local opt, data = "menu", nil - - -- Check arguments - if type(arguments) == "table" and #arguments > 0 then - local f = "/" .. shell.resolve(arguments[1]) - if fs.isDir(f) then print("Cannot edit a directory.") end - opt, data = "edit", f - end - - -- Main run loop - while true do - -- Menu - if opt == "menu" then opt = menu() end - - -- Other - if opt == "new" then opt, data = newFile() - elseif opt == "open" then opt, data = openFile() - elseif opt == "settings" then opt = settings() - end if opt == "exit" then break end - - -- Edit - if opt == "edit" and data then opt = edit(data) end - end -end - --- Load Theme -if fs.exists(themeLocation) then theme = loadTheme(themeLocation) end -if not theme and isAdvanced() then theme = defaultTheme -elseif not theme then theme = normalTheme end - --- Run -local _, err = pcall(function() - parallel.waitForAny(function() main(args) end, monitorKeyboardShortcuts) -end) - --- Catch errors -if err and not err:find("Terminated") then - term.setCursorBlink(false) - title("LuaIDE - Crash! D:") - - term.setBackgroundColor(colors[theme.err]) - for i = 6, 8 do - term.setCursorPos(5, i) - term.write(string.rep(" ", 36)) - end - term.setCursorPos(6, 7) - term.write("LuaIDE Has Crashed! D:") - - term.setBackgroundColor(colors[theme.background]) - term.setCursorPos(2, 10) - print(err) - - term.setBackgroundColor(colors[theme.prompt]) - local _, cy = term.getCursorPos() - for i = cy + 1, cy + 4 do - term.setCursorPos(5, i) - term.write(string.rep(" ", 36)) - end - term.setCursorPos(6, cy + 2) - term.write("Please report this error to") - term.setCursorPos(6, cy + 3) - term.write("GravityScore! ") - - term.setBackgroundColor(colors[theme.background]) - if isAdvanced() then centerPrint("Click to Exit...", h - 1) - else centerPrint("Press Any Key to Exit...", h - 1) end - while true do - local e = os.pullEvent() - if e == "mouse_click" or (not isAdvanced() and e == "key") then break end - end - - -- Prevent key from being shown - os.queueEvent(event_distract) - os.pullEvent() -end - --- Exit -term.setBackgroundColor(colors.black) -term.setTextColor(colors.white) -term.clear() -term.setCursorPos(1, 1) -centerPrint("Thank You for Using Lua IDE " .. version) -centerPrint("Made by GravityScore") diff --git a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua b/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua deleted file mode 100644 index be942df95..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze2d.lua +++ /dev/null @@ -1,327 +0,0 @@ ---[[ - Project info: - - Name: Maze - Creator: Jesusthekiller - Language: Lua (CC) - Website: None - License: GNU GPL - License file can be fount at www.jesusthekiller.com/license-gpl.html - - Version: 1.2 -]]-- - ---[[ - Changelog: - 1.0: - Initial Release - 1.1: - Typos D: - 1.2: - New logo - Time fixed -]]-- - ---[[ - LICENSE: - - Maze - Copyright (c) 2013 Jesusthekiller - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -]]-- - --- The maze - --- The cprint -local function cwrite(msg) - msg = tostring(msg) - local x, y = term.getCursorPos() - term.setCursorPos((51-#msg)/2, y) - write(msg) -end - -local function cprint(msg) - cwrite(msg.."\n") -end - --- The splash -term.setBackgroundColor(colors.black) -term.setTextColor(colors.white) -term.clear() - -term.setCursorPos(27, 8) -print("Nano maze!") - -paintutils.drawImage({[1]={[1]=1,[2]=1,[3]=1,[4]=1,[5]=1,[6]=1,[7]=1,[8]=1,[9]=1,[10]=1,[11]=0,[12]=1,[13]=0,[14]=0,[15]=1,[16]=0,[17]=0,[18]=1,[19]=0,[20]=0,[21]=1,[22]=0,[23]=0,[24]=1,[25]=0,[26]=0,[27]=1,},[2]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=0,[6]=1,[7]=0,[8]=0,[9]=0,[10]=1,[11]=0,[12]=1,[13]=1,[14]=0,[15]=1,[16]=0,[17]=1,[18]=0,[19]=1,[20]=0,[21]=1,[22]=1,[23]=0,[24]=1,[25]=0,[26]=1,[27]=0,[28]=1,},[3]={[1]=1,[2]=1,[3]=1,[4]=1,[5]=0,[6]=1,[7]=1,[8]=1,[9]=0,[10]=1,[11]=0,[12]=1,[13]=0,[14]=1,[15]=1,[16]=0,[17]=1,[18]=0,[19]=1,[20]=0,[21]=1,[22]=0,[23]=1,[24]=1,[25]=0,[26]=0,[27]=1,},[4]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=0,[6]=0,[7]=0,[8]=1,[9]=0,[10]=1,},[5]={[1]=1,[2]=0,[3]=1,[4]=1,[5]=1,[6]=1,[7]=0,[8]=1,[9]=0,[10]=1,[11]=0,[12]=1,[13]=0,[14]=0,[15]=0,[16]=1,[17]=0,[18]=0,[19]=1,[20]=0,[21]=0,[22]=1,[23]=1,[24]=0,[25]=0,[26]=1,[27]=1,[28]=1,},[6]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=0,[8]=0,[9]=0,[10]=1,[11]=0,[12]=1,[13]=1,[14]=0,[15]=1,[16]=1,[17]=0,[18]=1,[19]=0,[20]=1,[21]=0,[22]=0,[23]=1,[24]=0,[25]=0,[26]=1,[27]=1,},[7]={[1]=1,[2]=1,[3]=1,[4]=1,[5]=1,[6]=1,[7]=1,[8]=1,[9]=1,[10]=1,[11]=0,[12]=1,[13]=0,[14]=1,[15]=0,[16]=1,[17]=0,[18]=1,[19]=0,[20]=1,[21]=0,[22]=0,[23]=1,[24]=1,[25]=0,[26]=1,[27]=1,[28]=1,},}, 13, 5) - -parallel.waitForAny( - function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end, - function() term.setBackgroundColor(colors.black); term.setTextColor(colors.white) while true do term.setCursorPos(18, 14); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end -) - --- The size -local size - -repeat - term.setCursorPos(1, 14) - term.clearLine() - - cwrite("Enter maze size (5-99):") - size = read() - - size = tonumber(size) - if not size then - size = 0 - end -until size > 4 and size < 100 - --- The generate -local function mazeGen(mx, my) - - --[[ - Format: - - maze.x.y.(1/2/3/4) = true/false - - 1 - top - 2 - bottom - 3 - right - 4 - left - ]]-- - - local maze = {} - for i = 1, mx do - maze[i] = {} - for j = 1, my do - maze[i][j] = {} - for k = 1, 4 do - maze[i][j][k] = true - end - end - end - - local vis = 1 - local tot = mx * my - local curr = {} - curr.x = math.random(1, mx) - curr.y = math.random(1, my) - local stack = {} - - while vis < tot do - local intact = {} - local x = curr.x - local y = curr.y - - if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells - intact[#intact+1] = {x-1, y, 1} - end - - if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then - intact[#intact+1] = {x+1, y, 2} - end - - if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then - intact[#intact+1] = {x, y+1, 3} - end - - if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then - intact[#intact+1] = {x, y-1, 4} - end - - if #intact > 0 then - local i = math.random(1, #intact) -- Choose random - - if intact[i][3] == 1 then -- Set intact's attached wall to false - maze[intact[i][1]][intact[i][2]][2] = false - elseif intact[i][3] == 2 then - maze[intact[i][1]][intact[i][2]][1] = false - elseif intact[i][3] == 3 then - maze[intact[i][1]][intact[i][2]][4] = false - elseif intact[i][3] == 4 then - maze[intact[i][1]][intact[i][2]][3] = false - end - - maze[x][y][intact[i][3]] = false -- Set attached wall to false - - vis = vis + 1 -- Increase vis - - stack[#stack+1] = intact[i] -- Add to stack - else - local tmp = table.remove(stack) -- Get last cell - curr.x = tmp[1] - curr.y = tmp[2] - end - end - - return maze -end - -local m = mazeGen(size, size) - --- The game init -local posx = 2 -local posy = 2 - -local offsetx = 51/2-2 -local offsety = 19/2-2 - -local stime = os.clock() - --- The maze-to-table -local tab = {} - -for x = 1, size * 2 + 1 do - tab[x] = {} - - for y = 1, size * 2 + 1 do - if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty) - tab[x][y] = false - elseif x % 2 == 1 and y % 2 == 1 then -- Fill corners (full) - tab[x][y] = true - end - end -end - -for x, tV in ipairs(m) do - for y, v in ipairs(tV) do - tab[x*2-1][y*2] = v[1] -- Up - tab[x*2+1][y*2] = v[2] -- Down - tab[x*2][y*2+1] = v[3] -- Right - tab[x*2][y*2-1] = v[4] -- Left - end -end - --- The game itself -repeat - -- Print map - term.setBackgroundColor(colors.white) - term.clear() - - if posx == 2 and posy == 2 then - term.setCursorPos(1, 1) - term.setTextColor(colors.black) - print("Controls: WASD") - print("Back to start: R") - print("Quit: Q") - print("Goal: Step on # (It's on bottom right corner)") - print("\nGood Luck!") - end - - --[[ - term.setTextColor(colors.black) - term.setCursorPos(1, 19) - write("X: "..posx.." Y: "..posy) - ]] - - for x, tV in ipairs(tab) do -- Print the map - for y, v in ipairs(tV) do - if offsety+y > 20 then - break - end - - term.setCursorPos(offsetx+x, offsety+y) - - if v then - term.setBackgroundColor(colors.black) - else - term.setBackgroundColor(colors.white) - end - - if offsety+y < 20 and offsety+y > 0 and offsetx+x < 52 and offsetx+x > 0 then - if x == size*2 and y == size*2 then - if term.isColor() then - term.setTextColor(colors.cyan) - end - write("#") - else - write(" ") - end - end - end - - if offsetx+x > 51 then - break - end - end - - term.setCursorPos(51/2, 19/2) - term.setBackgroundColor(colors.white) - - if term.isColor() then - term.setTextColor(colors.red) - else - term.setTextColor(colors.black) - end - - write("X") - - -- Wait for key - - local e, k = os.pullEvent("char") - - if k == "a" and (not tab[posx-1][posy]) then - posx = posx - 1 - offsetx = offsetx + 1 - end - - if k == "d" and (not tab[posx+1][posy]) then - posx = posx + 1 - offsetx = offsetx - 1 - end - - if k == "w" and (not tab[posx][posy-1]) then - posy = posy - 1 - offsety = offsety + 1 - end - - if k == "s" and (not tab[posx][posy+1]) then - posy = posy + 1 - offsety = offsety - 1 - end - - if k == "q" then - break - end - - if k == "r" then - posx = 2 - posy = 2 - - offsetx = 51/2-2 - offsety = 19/2-2 - end -until posx == size*2 and posy == size*2 - --- The win/loose message -term.setBackgroundColor(colors.white) -term.setTextColor(colors.black) -term.clear() -term.setCursorPos(1, 1) - -if posx == size*2 and posy == size*2 then - local ntime = os.clock() - write("\n") - cprint("Congratulations!") - cprint("You made it in") - cprint(tostring(math.floor((ntime-stime)/60)).." minutes and "..tostring(math.ceil((ntime-stime)%60)).." seconds") - cprint("Size of maze: "..size) -else - write("\n") - cprint("Oh noes D:") -end - -parallel.waitForAny( - function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end, - function() term.setBackgroundColor(colors.white); term.setTextColor(colors.black) while true do term.setCursorPos(18, 14); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end -) - -term.setBackgroundColor(colors.black) -term.setTextColor(colors.white) -term.clear() -term.setCursorPos(1, 1) -cprint(" Maze by JTK. Thanks for playing!") diff --git a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua b/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua deleted file mode 100644 index a8a04ee85..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/JTK/maze3d/maze3d.lua +++ /dev/null @@ -1,614 +0,0 @@ ---[[ - Project info: - - Name: Maze 3D - Creator: Jesusthekiller - Language: Lua (CC) - Website: None - License: GNU GPL - License file can be fount at www.jesusthekiller.com/license-gpl.html - - Version: 2.1 -]]-- - ---[[ - Big thanks to Gopher for 3D engine! - http://www.computercraft.info/forums2/index.php?/topic/10786-wolf3d-style-3d-engine-proof-of-concept/page__hl__wolf3d -]]-- - ---[[ - Changelog: - 1.0: - Initial Release - 2.0: - No-HTTP version for Treasure disk - 2.1: - No more temp files! -]]-- - ---[[ - LICENSE: - - Maze 3D - Copyright (c) 2013 Jesusthekiller - - This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . -]]-- - --- The color check -if (not term.isColor()) or turtle then - print("This program has to be run on advanced computer.") - error() -end - --- The cprint -local function cwrite(msg) - msg = tostring(msg) - local x, y = term.getCursorPos() - term.setCursorPos((51-#msg)/2, y) - write(msg) -end - -local function cprint(msg) - cwrite(msg.."\n") -end - --- The splash -term.setBackgroundColor(colors.black) -term.setTextColor(colors.white) -term.clear() - -paintutils.drawImage({[1]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=0,[8]=1,[9]=1,[10]=0,[11]=0,[12]=0,[13]=1,[14]=1,[15]=1,[16]=1,[17]=0,[18]=1,[19]=1,[20]=1,[21]=1,},[2]={[1]=1,[2]=1,[3]=0,[4]=1,[5]=1,[6]=0,[7]=1,[8]=0,[9]=0,[10]=1,[11]=0,[12]=0,[13]=0,[14]=0,[15]=0,[16]=1,[17]=0,[18]=1,[19]=0,[20]=0,[21]=0,},[3]={[1]=1,[2]=0,[3]=1,[4]=0,[5]=1,[6]=0,[7]=1,[8]=1,[9]=1,[10]=1,[11]=0,[12]=0,[13]=0,[14]=1,[15]=1,[16]=0,[17]=0,[18]=1,[19]=1,[20]=1,[21]=0,},[4]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=1,[8]=0,[9]=0,[10]=1,[11]=0,[12]=0,[13]=1,[14]=0,[15]=0,[16]=0,[17]=0,[18]=1,[19]=0,[20]=0,[21]=0,},[5]={[1]=1,[2]=0,[3]=0,[4]=0,[5]=1,[6]=0,[7]=1,[8]=0,[9]=0,[10]=1,[11]=0,[12]=0,[13]=1,[14]=1,[15]=1,[16]=1,[17]=0,[18]=1,[19]=1,[20]=1,[21]=1,},[6]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=0,[6]=0,[7]=0,[8]=0,},[7]={[1]=0,[2]=0,[3]=0,[4]=16384,[5]=16384,[6]=16384,[7]=16384,[8]=0,[9]=0,[10]=0,[11]=0,[12]=512,[13]=512,[14]=512,[15]=512,[16]=0,[17]=0,[18]=0,[19]=0,[20]=0,[21]=0,},[8]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=128,[6]=128,[7]=128,[8]=16384,[9]=0,[10]=0,[11]=0,[12]=512,[13]=128,[14]=128,[15]=128,[16]=512,[17]=0,[18]=0,[19]=0,[20]=0,[21]=0,},[9]={[1]=0,[2]=0,[3]=0,[4]=16384,[5]=16384,[6]=16384,[7]=16384,[8]=0,[9]=128,[10]=0,[11]=0,[12]=512,[13]=128,[14]=0,[15]=0,[16]=512,[17]=128,[18]=0,[19]=0,[20]=0,[21]=0,},[10]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=128,[6]=128,[7]=128,[8]=16384,[9]=0,[10]=0,[11]=0,[12]=512,[13]=128,[14]=0,[15]=0,[16]=512,[17]=128,[18]=0,[19]=0,[20]=0,[21]=0,},[11]={[1]=0,[2]=0,[3]=0,[4]=16384,[5]=16384,[6]=16384,[7]=16384,[8]=0,[9]=128,[10]=0,[11]=0,[12]=512,[13]=512,[14]=512,[15]=512,[16]=128,[17]=128,[18]=0,[19]=0,[20]=0,[21]=0,},[12]={[1]=0,[2]=0,[3]=0,[4]=0,[5]=128,[6]=128,[7]=128,[8]=128,[9]=0,[10]=0,[11]=0,[12]=0,[13]=128,[14]=128,[15]=128,[16]=128,},}, 15, 3) - -parallel.waitForAny( - function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end, - function() term.setBackgroundColor(colors.black); term.setTextColor(colors.white) while true do term.setCursorPos(18, 16); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end -) - --- The size -local size - -repeat - term.setCursorPos(1, 16) - term.clearLine() - - cwrite("Enter maze size (5-99):") - size = read() - - size = tonumber(size) - if not size then - size = 0 - end -until size > 4 and size < 100 - --- The generate -local function mazeGen(mx, my) - - --[[ - Format: - - maze.x.y.(1/2/3/4) = true/false - - 1 - top - 2 - bottom - 3 - right - 4 - left - ]]-- - - local maze = {} - for i = 1, mx do - maze[i] = {} - for j = 1, my do - maze[i][j] = {} - for k = 1, 4 do - maze[i][j][k] = true - end - end - end - - local vis = 1 - local tot = mx * my - local curr = {} - curr.x = math.random(1, mx) - curr.y = math.random(1, my) - local stack = {} - - while vis < tot do - local intact = {} - local x = curr.x - local y = curr.y - - if x - 1 >= 1 and maze[x-1][y][1] and maze[x-1][y][2] and maze[x-1][y][3] and maze[x-1][y][4] then -- Check for full cells - intact[#intact+1] = {x-1, y, 1} - end - - if x + 1 <= mx and maze[x+1][y][1] and maze[x+1][y][2] and maze[x+1][y][3] and maze[x+1][y][4] then - intact[#intact+1] = {x+1, y, 2} - end - - if y + 1 <= my and maze[x][y+1][1] and maze[x][y+1][2] and maze[x][y+1][3] and maze[x][y+1][4] then - intact[#intact+1] = {x, y+1, 3} - end - - if y - 1 >= 1 and maze[x][y-1][1] and maze[x][y-1][2] and maze[x][y-1][3] and maze[x][y-1][4] then - intact[#intact+1] = {x, y-1, 4} - end - - if #intact > 0 then - local i = math.random(1, #intact) -- Choose random - - if intact[i][3] == 1 then -- Set intact's attached wall to false - maze[intact[i][1]][intact[i][2]][2] = false - elseif intact[i][3] == 2 then - maze[intact[i][1]][intact[i][2]][1] = false - elseif intact[i][3] == 3 then - maze[intact[i][1]][intact[i][2]][4] = false - elseif intact[i][3] == 4 then - maze[intact[i][1]][intact[i][2]][3] = false - end - - maze[x][y][intact[i][3]] = false -- Set attached wall to false - - vis = vis + 1 -- Increase vis - - stack[#stack+1] = intact[i] -- Add to stack - else - local tmp = table.remove(stack) -- Get last cell - curr.x = tmp[1] - curr.y = tmp[2] - end - end - - return maze -end - -local m = mazeGen(size, size) - --- The game init -local posx = 2 -local posy = 2 - -local offsetx = 51/2-2 -local offsety = 19/2-2 - --- The maze-to-table -local tab = {} - -for x = 1, size * 2 + 1 do - tab[x] = {} - - for y = 1, size * 2 + 1 do - if x % 2 == 0 and y % 2 == 0 then -- Fill cells (empty) - tab[x][y] = " " - elseif x % 2 == 1 and y % 2 == 1 then -- Fill corners (full) - tab[x][y] = "1" - end - end -end - -for x, tV in ipairs(m) do - for y, v in ipairs(tV) do - if x == size and y == size then - v[1] = v[1] and "2" or " " - v[2] = v[2] and "2" or " " - v[3] = v[3] and "2" or " " - v[4] = v[4] and "2" or " " - tab[x*2-1][y*2] = v[1] -- Up - tab[x*2+1][y*2] = v[2] -- Down - tab[x*2][y*2+1] = v[3] -- Right - tab[x*2][y*2-1] = v[4] -- Left - else - v[1] = v[1] and "1" or " " - v[2] = v[2] and "1" or " " - v[3] = v[3] and "1" or " " - v[4] = v[4] and "1" or " " - tab[x*2-1][y*2] = v[1] -- Up - tab[x*2+1][y*2] = v[2] -- Down - tab[x*2][y*2+1] = v[3] -- Right - tab[x*2][y*2-1] = v[4] -- Left - end - end -end - -local gtab = {} - -for k, v in ipairs(tab) do - gtab[#gtab+1] = table.concat(v) -end - -size = size * 2 + 1 - ---[[ -local template = fs.open("maze3d_template", "r") -local game = fs.open("maze3d_game", "w") - -game.writeLine("local mapH, mapW = "..size..","..size) -game.writeLine("local dir = "..(gtab[2]:sub(3,3) == " " and '0' or '88')) -game.writeLine("local map = {") - -for k, v in ipairs(gtab) do - game.writeLine('"'..v..'",') -end - -game.writeLine("}") - -game.writeLine(template.readAll()) -game.close() -template.close() - -shell.run("maze3d_game") - -fs.delete("maze3d_game") -fs.delete("maze3d_template")]] - -local mapH, mapW = size, size -local dir = gtab[2]:sub(3,3) == " " and '0' or '88' -local map = gtab -local startdir = dir - ------------------------------------------------------------------------------------------------------- ---GOPHER'S CODE HERE - -local buffer=term -local loadedAPI=false - -local stime = os.clock() - -if redirect then - buffer=redirect.createRedirectBuffer() - print("redirect API found, using buffer") -else - local pe=printError - rawset(_G,"printError",error) - local ok, err=pcall(os.loadAPI,"redirect") - if not ok then - print("trying "..shell.dir().."/redirect") - ok,err=pcall(os.loadAPI,shell.dir().."/redirect") - end - if ok then - print("Loaded redirect API, using buffer") - buffer=redirect.createRedirectBuffer() - loadedAPI=true - else - print("redirect API not found or could not be loaded, drawing directly; this may cause flickering.") - end - rawset(_G,"printError",pe) -end - -local colorSchemes = { - {0,8}, --white+gray - {3,11}, --blue - {6,14}, --red - {5,13}, --green - {4,1}, --yellow/orange -} - - -local function cast(cx,cy,angle) - --direction vector - local vx,vy=math.cos(angle), math.sin(angle) - local slope=vy/vx - --next distance, x and y axis points - local ndx, ndy - --steps, distance and block - local dsx, dsy, bsx, bsy - if vx<0 then - local x=(cx%1) - bsx=-1 - ndx=math.sqrt(x*x*(1+slope*slope)) - dsx=math.sqrt((1+slope*slope)) - else - local x=1-(cx%1) - bsx=1 - ndx=math.sqrt(x*x*(1+slope*slope)) - dsx=math.sqrt((1+slope*slope)) - end - - if vy<0 then - local y=(cy%1) - bsy=-1 - ndy=math.sqrt(y*y*(1+1/(slope*slope))) - dsy=math.sqrt((1+1/(slope*slope))) - else - local y=1-(cy%1) - bsy=1 - ndy=math.sqrt(y*y*(1+1/(slope*slope))) - dsy=math.sqrt((1+1/(slope*slope))) - end - - local x,y=math.floor(cx),math.floor(cy) - while x>0 and x<=mapW and y>0 and y<=mapH do - local hitD - local isX - if ndxgx - local left=math.floor(x-radius)gy - - local pushed=false - - if right and map[gy]:sub(gx+1,gx+1)~=" " then - --push left - pushed=true - x=gx+1-radius - elseif left and map[gy]:sub(gx-1,gx-1)~=" " then - --push right - pushed=true - x=gx+radius - end - - if front and map[gy-1]:sub(gx,gx)~=" " then - --push back - pushed=true - y=gy+radius - elseif back and map[gy+1]:sub(gx,gx)~=" " then - --push forward - pushed=true - - - - y=gy+1-radius - end - - --if I wasn't pushed out on any side, I might be hitting a corner - if not pushed then - --square rad - local r2=radius^2 - local pushx,pushy=0,0 - if left then - if front and map[gy-1]:sub(gx-1,gx-1)~=" " then - --check front-left - local dist2=(gx-x)^2+(gy-y)^2 - if dist2= mapW-1 and py >= mapH-1 then - win = true - break - end - end -end - - -if loadedAPI then - os.unloadAPI("redirect") -end - --- JESUS PART - --- The win/loose message -term.setBackgroundColor(colors.white) -term.setTextColor(colors.black) -term.clear() -term.setCursorPos(1, 1) - -if win then - local ntime = os.clock() - write("\n") - cprint("Congratulations!") - cprint("You made it in") - cprint(tostring(math.floor((ntime-stime)/60)).." minutes and "..tostring(math.ceil((ntime-stime)%60)).." seconds") - cprint("Size of maze: "..(mapW-1)/2) -sleep(1) -else - write("\n") - cprint("Oh noes D:") -end - - - -parallel.waitForAny( - function() coroutine.yield(); os.pullEvent("key"); coroutine.yield() end, - function() term.setBackgroundColor(colors.white); term.setTextColor(colors.black) while true do term.setCursorPos(18, 14); term.write("Press any key.."); sleep(0.5); term.clearLine(); sleep(0.5) end end -) - -term.setBackgroundColor(colors.black) -term.setTextColor(colors.white) -term.clear() -term.setCursorPos(1, 1) -cprint(" Maze 3D by JTK. Thanks for playing!") -cprint("3D engine by Gopher, He is A-W-E-S-O-M-E") diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/framebuffer.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/framebuffer.lua deleted file mode 100644 index 0d8ac2ae7..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/framebuffer.lua +++ /dev/null @@ -1,159 +0,0 @@ -function new(_sizeX, _sizeY, _color) - local redirect = {buffer = {text = {}, textColor = {}, backColor = {}, cursorX = 1, cursorY = 1, cursorBlink = false, curTextColor = "0", curBackColor = "f", sizeX = _sizeX or 51, sizeY = _sizeY or 19, color = _color}} - redirect.write = function(text) - text = tostring(text) - local pos = redirect.buffer.cursorX - if redirect.buffer.cursorY > redirect.buffer.sizeY or redirect.buffer.cursorY < 1 then - redirect.buffer.cursorX = pos + #text - return - end - local writeText - if pos + #text <= 1 then - --skip entirely. - redirect.buffer.cursorX = pos + #text - return - elseif pos < 1 then - --adjust text to fit on screen starting at one. - writeText = string.sub(text, math.abs(redirect.buffer.cursorX) + 2) - redirect.buffer.cursorX = 1 - elseif pos > redirect.buffer.sizeX then - --if we're off the edge to the right, skip entirely. - redirect.buffer.cursorX = pos + #text - return - else - writeText = text - end - local lineText = redirect.buffer.text[redirect.buffer.cursorY] - local lineColor = redirect.buffer.textColor[redirect.buffer.cursorY] - local lineBack = redirect.buffer.backColor[redirect.buffer.cursorY] - local preStop = redirect.buffer.cursorX - 1 - local preStart = math.min(1, preStop) - local postStart = redirect.buffer.cursorX + string.len(writeText) - local postStop = redirect.buffer.sizeX - redirect.buffer.text[redirect.buffer.cursorY] = string.sub(lineText, preStart, preStop)..writeText..string.sub(lineText, postStart, postStop) - redirect.buffer.textColor[redirect.buffer.cursorY] = string.sub(lineColor, preStart, preStop)..string.rep(redirect.buffer.curTextColor, #writeText)..string.sub(lineColor, postStart, postStop) - redirect.buffer.backColor[redirect.buffer.cursorY] = string.sub(lineBack, preStart, preStop)..string.rep(redirect.buffer.curBackColor, #writeText)..string.sub(lineBack, postStart, postStop) - redirect.buffer.cursorX = pos + string.len(text) - end - redirect.clear = function() - for i=1, redirect.buffer.sizeY do - redirect.buffer.text[i] = string.rep(" ", redirect.buffer.sizeX) - redirect.buffer.textColor[i] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX) - redirect.buffer.backColor[i] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX) - end - end - redirect.clearLine = function() - redirect.buffer.text[redirect.buffer.cursorY] = string.rep(" ", redirect.buffer.sizeX) - redirect.buffer.textColor[redirect.buffer.cursorY] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX) - redirect.buffer.backColor[redirect.buffer.cursorY] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX) - end - redirect.getCursorPos = function() - return redirect.buffer.cursorX, redirect.buffer.cursorY - end - redirect.setCursorPos = function(x, y) - redirect.buffer.cursorX = math.floor(tonumber(x)) or redirect.buffer.cursorX - redirect.buffer.cursorY = math.floor(tonumber(y)) or redirect.buffer.cursorY - end - redirect.setCursorBlink = function(b) - redirect.buffer.cursorBlink = b - end - redirect.getSize = function() - return redirect.buffer.sizeX, redirect.buffer.sizeY - end - redirect.scroll = function(n) - n = tonumber(n) or 1 - if n > 0 then - for i = 1, redirect.buffer.sizeY - n do - if redirect.buffer.text[i + n] then - redirect.buffer.text[i] = redirect.buffer.text[i + n] - redirect.buffer.textColor[i] = redirect.buffer.textColor[i + n] - redirect.buffer.backColor[i] = redirect.buffer.backColor[i + n] - end - end - for i = redirect.buffer.sizeY, redirect.buffer.sizeY - n + 1, -1 do - redirect.buffer.text[i] = string.rep(" ", redirect.buffer.sizeX) - redirect.buffer.textColor[i] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX) - redirect.buffer.backColor[i] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX) - end - elseif n < 0 then - for i = redirect.buffer.sizeY, math.abs(n) + 1, -1 do - if redirect.buffer.text[i + n] then - redirect.buffer.text[i] = redirect.buffer.text[i + n] - redirect.buffer.textColor[i] = redirect.buffer.textColor[i + n] - redirect.buffer.backColor[i] = redirect.buffer.backColor[i + n] - end - end - for i = 1, math.abs(n) do - redirect.buffer.text[i] = string.rep(" ", redirect.buffer.sizeX) - redirect.buffer.textColor[i] = string.rep(redirect.buffer.curTextColor, redirect.buffer.sizeX) - redirect.buffer.backColor[i] = string.rep(redirect.buffer.curBackColor, redirect.buffer.sizeX) - end - end - end - redirect.setTextColor = function(clr) - if clr and clr <= 32768 and clr >= 1 then - if redirect.buffer.color then - redirect.buffer.curTextColor = string.format("%x", math.floor(math.log(clr) / math.log(2))) - elseif clr == 1 or clr == 32768 then - redirect.buffer.curTextColor = string.format("%x", math.floor(math.log(clr) / math.log(2))) - else - return nil, "Colour not supported" - end - end - end - redirect.setTextColour = redirect.setTextColor - redirect.setBackgroundColor = function(clr) - if clr and clr <= 32768 and clr >= 1 then - if redirect.buffer.color then - redirect.buffer.curBackColor = string.format("%x", math.floor(math.log(clr) / math.log(2))) - elseif clr == 32768 or clr == 1 then - redirect.buffer.curBackColor = string.format("%x", math.floor(math.log(clr) / math.log(2))) - else - return nil, "Colour not supported" - end - end - end - redirect.setBackgroundColour = redirect.setBackgroundColor - redirect.isColor = function() - return redirect.buffer.color == true - end - redirect.isColour = redirect.isColor - redirect.render = function(inputBuffer) - for i = 1, redirect.buffer.sizeY do - redirect.buffer.text[i] = inputBuffer.text[i] - redirect.buffer.textColor[i] = inputBuffer.textColor[i] - redirect.buffer.backColor[i] = inputBuffer.backColor[i] - end - end - redirect.clear() - return redirect -end - -function draw(buffer, current) - for i=1, buffer.sizeY do - term.setCursorPos(1,i) - if (current and (buffer.text[i] ~= current.text[i] or buffer.textColor[i] ~= current.textColor[i] or buffer.backColor[i] ~= current.backColor[i])) or not current then - local lineEnd = false - local offset = 1 - while not lineEnd do - local textColorString = string.match(string.sub(buffer.textColor[i], offset), string.sub(buffer.textColor[i], offset, offset).."*") - local backColorString = string.match(string.sub(buffer.backColor[i], offset), string.sub(buffer.backColor[i], offset, offset).."*") - term.setTextColor(2 ^ tonumber(string.sub(textColorString, 1, 1), 16)) - term.setBackgroundColor(2 ^ tonumber(string.sub(backColorString, 1, 1), 16)) - term.write(string.sub(buffer.text[i], offset, offset + math.min(#textColorString, #backColorString) - 1)) - offset = offset + math.min(#textColorString, #backColorString) - if offset > buffer.sizeX then lineEnd = true end - end - if current then - current.text[i] = buffer.text[i] - current.textColor[i] = buffer.textColor[i] - current.backColor[i] = buffer.backColor[i] - end - end - end - term.setCursorPos(buffer.cursorX, buffer.cursorY) - term.setTextColor(2 ^ tonumber(buffer.curTextColor, 16)) - term.setBackgroundColor(2 ^ tonumber(buffer.curBackColor, 16)) - term.setCursorBlink(buffer.cursorBlink) - return current -end diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua deleted file mode 100644 index a8d7901d3..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/get.lua +++ /dev/null @@ -1,26 +0,0 @@ -if not nsh then print("No nsh session!") return end - -local args = {...} - -if #args < 2 then - print("Usage: get ") - print(": any file on the server") - print(": any non-existant file on the client") - return -end - -if fs.exists(args[1]) then - nsh.send("FS:;t="..args[2]) - local message = nsh.receive() - if message == "FR:;ok" then - nsh.send("FH:;"..args[1]) - local handle = io.open(args[1], "r") - if handle then - nsh.send("FD:;t="..handle:read("*a")) - handle:close() - end - nsh.send("FE:;end") - else - print("Client rejected file!") - end -end diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua deleted file mode 100644 index df62694fc..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/nsh.lua +++ /dev/null @@ -1,721 +0,0 @@ -local args = { ... } - -local connections = {} - -local nshAPI = { - connList = connections -} - -if not framebuffer then if not ((fs.exists("framebuffer") and os.loadAPI("framebuffer")) or (fs.exists("LyqydOS/framebuffer") and os.loadAPI("LyqydOS/framebuffer"))) then print("Couldn't find framebuffer API, using fallback") end end - -local function rawSend(id, msg) - if term.current then - return rednet.send(id, msg, "tror") - else - return rednet.send(id, msg) - end -end - -local function rawRecv(id, timeout) - if type(timeout) == "number" then timeout = os.startTimer(timeout) end - while true do - event = {os.pullEvent()} - if event[1] == "rednet_message" and (id == nil and true or event[2] == id) and (not term.current and true or event[4] == "tror") then - return event[3] - elseif event[1] == "timer" and event[2] == timeout then - return nil - end - end -end - - -nshAPI.getRemoteID = function() - --check for connected clients with matching threads. - for cNum, cInfo in pairs(nshAPI.connList) do - if cInfo.thread == coroutine.running() then - if cNum == "localShell" then - --if we are a client running on the server, return the remote server ID. - if nshAPI.serverNum then - return nshAPI.serverNum - else - return nil - end - end - return cNum - end - end - --client running without local server, return remote server ID. - if nshAPI.serverNum then return nshAPI.serverNum end - return nil -end - -nshAPI.send = function(msg) - local id = nshAPI.getRemoteID() - if id then - return rawSend(id, msg) - end - return nil -end - -nshAPI.receive = function(timeout) - return rawRecv(nshAPI.getRemoteID(), timeout) -end - -nshAPI.getClientCapabilities = function() - if nshAPI.clientCapabilities then return nshAPI.clientCapabilities end - nshAPI.send("SP:;clientCapabilities") - return nshAPI.receive(1) -end - -nshAPI.getRemoteConnections = function() - local remotes = {} - for cNum, cInfo in pairs(nshAPI.connList) do - table.insert(remotes, cNum) - if cInfo.outbound then - table.insert(remotes, cInfo.outbound) - end - end - return remotes -end - -nshAPI.packFile = function(path) - local data = {} - local count = 0 - local handle = io.open(path, "rb") - if handle then - local byte = handle:read() - repeat - data[#data + 1] = byte - count = count + 1 - if count % 1000 == 0 then - os.queueEvent("yield") - os.pullEvent("yield") - end - byte = handle:read() - until not byte - handle:close() - else - return false - end - local outputTable = {} - for i = 1, #data, 3 do - local num1, num2, num3 = data[i], data[i + 1] or 0, data[i + 2] or 0 - table.insert(outputTable, string.char(bit32.band(bit32.arshift(num1, 2), 63))) - table.insert(outputTable, string.char(bit32.bor(bit32.band(bit32.lshift(num1, 4), 48), bit32.band(bit32.arshift(num2, 4), 15)))) - table.insert(outputTable, string.char(bit32.bor(bit32.band(bit32.lshift(num2, 2), 60), bit32.band(bit32.arshift(num3, 6), 3)))) - table.insert(outputTable, string.char(bit32.band(num3, 63))) - end - --mark non-data (invalid) bytes - if #data % 3 == 1 then - outputTable[#outputTable] = "=" - outputTable[#outputTable - 1] = "=" - elseif #data % 3 == 2 then - outputTable[#outputTable] = "=" - end - return table.concat(outputTable, "") -end - -nshAPI.unpackAndSaveFile = function(path, data) - local outputTable = {} - for i=1, #data, 4 do - local char1, char2, char3, char4 = string.byte(string.sub(data, i, i)), string.byte(string.sub(data, i + 1, i + 1)), string.byte(string.sub(data, i + 2, i + 2)), string.byte(string.sub(data, i + 3, i + 3)) - table.insert(outputTable, bit32.band(bit32.bor(bit32.lshift(char1, 2), bit32.arshift(char2, 4)), 255)) - table.insert(outputTable, bit32.band(bit32.bor(bit32.lshift(char2, 4), bit32.arshift(char3, 2)), 255)) - table.insert(outputTable, bit32.band(bit32.bor(bit32.lshift(char3, 6), char4), 255)) - end - --clean invalid bytes if marked - if string.sub(data, #data, #data) == "=" then - table.remove(outputTable) - if string.sub(data, #data - 1, #data - 1) == "=" then - table.remove(outputTable) - end - end - local handle = io.open(path, "wb") - if handle then - for i = 1, #outputTable do - handle:write(outputTable[i]) - if i % 10 == 0 then - os.startTimer(0.1) - os.pullEvent("timer") - end - end - handle:close() - end -end - -local packetConversion = { - query = "SQ", - response = "SR", - data = "SP", - close = "SC", - fileQuery = "FQ", - fileSend = "FS", - fileResponse = "FR", - fileHeader = "FH", - fileData = "FD", - fileEnd = "FE", - textWrite = "TW", - textCursorPos = "TC", - textGetCursorPos = "TG", - textGetSize = "TD", - textInfo = "TI", - textClear = "TE", - textClearLine = "TL", - textScroll = "TS", - textBlink = "TB", - textColor = "TF", - textBackground = "TK", - textIsColor = "TA", - textTable = "TT", - event = "EV", - SQ = "query", - SR = "response", - SP = "data", - SC = "close", - FQ = "fileQuery", - FS = "fileSend", - FR = "fileResponse", - FH = "fileHeader", - FD = "fileData", - FE = "fileEnd", - TW = "textWrite", - TC = "textCursorPos", - TG = "textGetCursorPos", - TD = "textGetSize", - TI = "textInfo", - TE = "textClear", - TL = "textClearLine", - TS = "textScroll", - TB = "textBlink", - TF = "textColor", - TK = "textBackground", - TA = "textIsColor", - TT = "textTable", - EV = "event", -} - -local function openModem() - local modemFound = false - for _, side in ipairs(rs.getSides()) do - if peripheral.getType(side) == "modem" then - if not rednet.isOpen(side) then rednet.open(side) end - modemFound = true - break - end - end - return modemFound -end - -local function send(id, pType, message) - if pType and message then - return rawSend(id, packetConversion[pType]..":;"..message) - end -end - -local function awaitResponse(id, time) - id = tonumber(id) - local listenTimeOut = nil - local messRecv = false - if time then listenTimeOut = os.startTimer(time) end - while not messRecv do - local event, p1, p2 = os.pullEvent() - if event == "timer" and p1 == listenTimeOut then - return false - elseif event == "rednet_message" then - sender, message = p1, p2 - if id == sender and message then - if packetConversion[string.sub(message, 1, 2)] then packetType = packetConversion[string.sub(message, 1, 2)] end - message = string.match(message, ";(.*)") - messRecv = true - end - end - end - return packetType, message -end - -local function processText(conn, pType, value) - if not pType then return false end - if pType == "textWrite" and value then - term.write(value) - elseif pType == "textClear" then - term.clear() - elseif pType == "textClearLine" then - term.clearLine() - elseif pType == "textGetCursorPos" then - local x, y = term.getCursorPos() - send(conn, "textInfo", math.floor(x)..","..math.floor(y)) - elseif pType == "textCursorPos" then - local x, y = string.match(value, "(%-?%d+),(%-?%d+)") - term.setCursorPos(tonumber(x), tonumber(y)) - elseif pType == "textBlink" then - if value == "true" then - term.setCursorBlink(true) - else - term.setCursorBlink(false) - end - elseif pType == "textGetSize" then - x, y = term.getSize() - send(conn, "textInfo", x..","..y) - elseif pType == "textScroll" and value then - term.scroll(tonumber(value)) - elseif pType == "textIsColor" then - send(conn, "textInfo", tostring(term.isColor())) - elseif pType == "textColor" and value then - value = tonumber(value) - if (value == 1 or value == 32768) or term.isColor() then - term.setTextColor(value) - end - elseif pType == "textBackground" and value then - value = tonumber(value) - if (value == 1 or value == 32768) or term.isColor() then - term.setBackgroundColor(value) - end - elseif pType == "textTable" then - local linesTable = textutils.unserialize(value) - for i=1, linesTable.sizeY do - term.setCursorPos(1,i) - local lineEnd = false - local offset = 1 - while not lineEnd do - local textColorString = string.match(string.sub(linesTable.textColor[i], offset), string.sub(linesTable.textColor[i], offset, offset).."*") - local backColorString = string.match(string.sub(linesTable.backColor[i], offset), string.sub(linesTable.backColor[i], offset, offset).."*") - term.setTextColor(2 ^ tonumber(string.sub(textColorString, 1, 1), 16)) - term.setBackgroundColor(2 ^ tonumber(string.sub(backColorString, 1, 1), 16)) - term.write(string.sub(linesTable.text[i], offset, offset + math.min(#textColorString, #backColorString) - 1)) - offset = offset + math.min(#textColorString, #backColorString) - if offset > linesTable.sizeX then lineEnd = true end - end - end - term.setCursorPos(linesTable.cursorX, linesTable.cursorY) - term.setCursorBlink(linesTable.cursorBlink) - end - return -end - -local function textRedirect(id) - local textTable = {} - textTable.id = id - textTable.write = function(text) - return send(textTable.id, "textWrite", text) - end - textTable.clear = function() - return send(textTable.id, "textClear", "nil") - end - textTable.clearLine = function() - return send(textTable.id, "textClearLine", "nil") - end - textTable.getCursorPos = function() - send(textTable.id, "textGetCursorPos", "nil") - local pType, message = awaitResponse(textTable.id, 2) - if pType and pType == "textInfo" then - local x, y = string.match(message, "(%-?%d+),(%-?%d+)") - return tonumber(x), tonumber(y) - end - end - textTable.setCursorPos = function(x, y) - return send(textTable.id, "textCursorPos", math.floor(x)..","..math.floor(y)) - end - textTable.setCursorBlink = function(b) - if b then - return send(textTable.id, "textBlink", "true") - else - return send(textTable.id, "textBlink", "false") - end - end - textTable.getSize = function() - send(textTable.id, "textGetSize", "nil") - local pType, message = awaitResponse(textTable.id, 2) - if pType and pType == "textInfo" then - local x, y = string.match(message, "(%d+),(%d+)") - return tonumber(x), tonumber(y) - end - end - textTable.scroll = function(lines) - return send(textTable.id, "textScroll", lines) - end - textTable.isColor = function() - send(textTable.id, "textIsColor", "nil") - local pType, message = awaitResponse(textTable.id, 2) - if pType and pType == "textInfo" then - if message == "true" then - return true - end - end - return false - end - textTable.isColour = textTable.isColor - textTable.setTextColor = function(color) - return send(textTable.id, "textColor", tostring(color)) - end - textTable.setTextColour = textTable.setTextColor - textTable.setBackgroundColor = function(color) - return send(textTable.id, "textBackground", tostring(color)) - end - textTable.setBackgroundColour = textTable.setBackgroundColor - return textTable -end - -local function getServerID(server) - if tonumber(server) then - return tonumber(server) - elseif term.current then - return rednet.lookup("tror", args[1]) - end -end - -local function resumeThread(conn, event) - local cInfo = connections[conn] - if not connections[conn].filter or event[1] == connections[conn].filter then - connections[conn].filter = nil - local _oldTerm = term.redirect(connections[conn].target) - local passback = {coroutine.resume(connections[conn].thread, table.unpack(event))} - if passback[1] and passback[2] then - connections[conn].filter = passback[2] - end - if coroutine.status(connections[conn].thread) == "dead" then - send(conn, "close", "disconnect") - connections[conn] = nil - end - if _oldTerm then - term.redirect(_oldTerm) - else - term.restore() - end - if connections[conn] and conn ~= "localShell" and framebuffer then - send(conn, "textTable", textutils.serialize(connections[conn].target.buffer)) - end - end -end - -local eventFilter = { - key = true, - char = true, - mouse_click = true, - mouse_drag = true, - mouse_scroll = true, -} - -local function newSession(conn, x, y, color) - local session = {} - local path = "/rom/programs/shell" - if #args >= 2 and shell.resolveProgram(args[2]) then path = shell.resolveProgram(args[2]) end - session.thread = coroutine.create(function() shell.run(path) end) - if framebuffer then - session.target = framebuffer.new(x, y, color) - else - session.target = textRedirect(conn) - end - session.status = "open" - _oldTerm = term.redirect(session.target) - coroutine.resume(session.thread) - if _oldTerm then - term.redirect(_oldTerm) - else - term.restore() - end - if framebuffer then - send(conn, "textTable", textutils.serialize(session.target.buffer)) - end - return session -end - -if #args >= 1 and args[1] == "host" then - _G.nsh = nshAPI - if not openModem() then return end - if term.current then - if args[4] then - rednet.host("tror", args[4]) - elseif os.getComputerLabel() then - rednet.host("tror", os.getComputerLabel()) - else - print("No label or hostname provided!") - return - end - end - local connInfo = {} - connInfo.target = term.current and term.current() or term.native - local path = "/rom/programs/shell" - if #args >= 3 and shell.resolveProgram(args[3]) then path = shell.resolveProgram(args[3]) end - connInfo.thread = coroutine.create(function() shell.run(path) end) - connections.localShell = connInfo - term.clear() - term.setCursorPos(1,1) - coroutine.resume(connections.localShell.thread) - - while true do - event = {os.pullEventRaw()} - if event[1] == "rednet_message" then - if type(event[3]) == "string" and packetConversion[string.sub(event[3], 1, 2)] then - --this is a packet meant for us. - conn = event[2] - packetType = packetConversion[string.sub(event[3], 1, 2)] - message = string.match(event[3], ";(.*)") - if connections[conn] and connections[conn].status == "open" then - if packetType == "event" or string.sub(packetType, 1, 4) == "text" then - local eventTable = {} - if packetType == "event" then - eventTable = textutils.unserialize(message) - else - --we can pass the packet in raw, since this is not an event packet. - eventTable = event - end - resumeThread(conn, eventTable) - elseif packetType == "query" then - local connType, color, x, y = string.match(message, "(%a+):(%a+);(%d+),(%d+)") - if connType == "connect" or (connType == "resume" and (not framebuffer)) then - --reset connection - send(conn, "response", "OK") - connections[conn] = newSession(conn, tonumber(x), tonumber(y), color == "true") - elseif connType == "resume" then - --restore connection - send(conn, "response", "OK") - send(conn, "textTable", textutils.serialize(connections[conn].target.buffer)) - end - elseif packetType == "close" then - connections[conn] = nil - send(conn, "close", "disconnect") - --close connection - else - --we got a packet, have an open connection, but despite it being in the conversion table, don't handle it ourselves. Send it onward. - resumeThread(conn, event) - end - elseif packetType ~= "query" then - --usually, we would send a disconnect here, but this prevents one from hosting nsh and connecting to other computers. Pass these to all shells as well. - for cNum, cInfo in pairs(connections) do - resumeThread(cNum, event) - end - else - --open new connection - send(conn, "response", "OK") - local color, x, y = string.match(message, "connect:(%a+);(%d+),(%d+)") - local connInfo = newSession(conn, tonumber(x), tonumber(y), color == "true") - connections[conn] = connInfo - end - else - --rednet message, but not in the correct format, so pass to all shells. - for cNum, cInfo in pairs(connections) do - resumeThread(cNum, event) - end - end - elseif eventFilter[event[1]] then - --user interaction. - coroutine.resume(connections.localShell.thread, table.unpack(event)) - if coroutine.status(connections.localShell.thread) == "dead" then - for cNum, cInfo in pairs(connections) do - if cNum ~= "localShell" then - send(cNum, "close", "disconnect") - end - end - return - end - else - --dispatch all other events to all shells - for cNum, cInfo in pairs(connections) do - resumeThread(cNum, event) - end - end - end - -elseif #args <= 2 and nsh and nsh.getRemoteID() then - print(nsh.getRemoteID()) - --forwarding mode - local conns = nsh.getRemoteConnections() - for i = 1, #conns do - if conns[i] == serverNum then - print("Cyclic connection refused.") - return - end - end - local fileTransferState = nil - local fileData = nil - local serverNum = getServerID(args[1]) - if not serverNum then - print("Server Not Found") - return - end - send(serverNum, "query", "connect") - local pType, message = awaitResponse(serverNum, 2) - if pType ~= "response" then - print("Connection Failed") - return - else - nsh.connList[nsh.getRemoteID()].outbound = serverNum - term.clear() - term.setCursorPos(1,1) - end - local clientID = nsh.getRemoteID() - local serverID = tonumber(args[1]) - while true do - event = {os.pullEvent()} - if event[1] == "rednet_message" then - if event[2] == clientID or event[2] == serverID then - if event[2] == serverID and string.sub(event[3], 1, 2) == "SC" then break end - rednet.send((event[2] == clientID and serverID or clientID), event[3]) - end - elseif eventFilter[event[1]] then - rednet.send(serverID, "EV:;"..textutils.serialize(event)) - end - end - nsh.connList[nsh.getRemoteID()].outbound = nil - term.clear() - term.setCursorPos(1, 1) - print("Connection closed by server") - -elseif #args >= 1 then --either no server running or we are the local shell on the server. - if not openModem() then return end - local serverNum = getServerID(args[1]) - if not serverNum then - print("Server Not Found") - return - end - if nsh then - local conns = nsh.getRemoteConnections() - for i = 1, #conns do - if conns[i] == serverNum then - print("Connection refused.") - return - end - end - end - local fileTransferState = nil - local fileData = nil - local fileBinaryData = nil - local unpackCo = {} - local color = term.isColor() - local x, y = term.getSize() - if args[2] == "resume" then - send(serverNum, "query", "resume:"..tostring(color)..";"..tostring(x)..","..tostring(y)) - else - send(serverNum, "query", "connect:"..tostring(color)..";"..tostring(x)..","..tostring(y)) - end - local timeout = os.startTimer(2) - while true do - local event = {os.pullEvent()} - if event[1] == "timer" and event[2] == timeout then - print("Connection failed.") - return - elseif event[1] == "rednet_message" and event[2] == serverNum and string.sub(event[3], 1, 2) == "SR" then - if nsh then nshAPI = nsh end - if nshAPI.connList and nshAPI.connList.localShell then nshAPI.connList.localShell.outbound = serverNum end - nshAPI.serverNum = serverNum - nshAPI.clientCapabilities = "-fileTransfer-extensions-" - term.clear() - term.setCursorPos(1,1) - break - end - end - - while true do - event = {os.pullEventRaw()} - if #unpackCo > 0 then - for i = #unpackCo, 1, -1 do - if coroutine.status(unpackCo[i]) ~= "dead" then - coroutine.resume(unpackCo[i], table.unpack(event)) - else - table.remove(unpackCo, i) - end - end - end - if event[1] == "rednet_message" and event[2] == serverNum then - if packetConversion[string.sub(event[3], 1, 2)] then - packetType = packetConversion[string.sub(event[3], 1, 2)] - message = string.match(event[3], ";(.*)") - if string.sub(packetType, 1, 4) == "text" then - processText(serverNum, packetType, message) - elseif packetType == "data" then - if message == "clientCapabilities" then - rednet.send(serverNum, nshAPI.clientCapabilities) - end - elseif packetType == "fileQuery" then - --send a file to the server - local mode, file = string.match(message, "^(%a)=(.*)") - if fs.exists(file) then - send(serverNum, "fileHeader", file) - if mode == "b" then - local fileString = nshAPI.packFile(file) - send(serverNum, "fileData", "b="..fileString) - else - local handle = io.open(file, "r") - if handle then - send(serverNum, "fileData", "t="..handle:read("*a")) - handle:close() - end - end - else - send(serverNum, "fileHeader", "fileNotFound") - end - send(serverNum, "fileEnd", "end") - elseif packetType == "fileSend" then - --receive a file from the server, but don't overwrite existing files. - local mode, file = string.match(message, "^(%a)=(.*)") - if not fs.exists(file) then - fileTransferState = "receive_wait:"..file - send(serverNum, "fileResponse", "ok") - if mode == "b" then - fileBinaryData = "" - fileData = nil - else - fileData = "" - fileBinaryData = nil - end - else - send(serverNum, "fileResponse", "reject") - end - elseif packetType == "fileHeader" then - if message == "fileNotFound" then - fileTransferState = nil - end - elseif packetType == "fileData" then - if fileTransferState and string.match(fileTransferState, "(.-):") == "receive_wait" then - if string.match(message, "^(%a)=") == "b" then - fileBinaryData = fileBinaryData..string.match(message, "^b=(.*)") - else - fileData = fileData..string.match(message, "^t=(.*)") - end - end - elseif packetType == "fileEnd" then - if fileTransferState and string.match(fileTransferState, "(.-):") == "receive_wait" then - if fileBinaryData then - local co = coroutine.create(nshAPI.unpackAndSaveFile) - coroutine.resume(co, string.match(fileTransferState, ":(.*)"), fileBinaryData) - if coroutine.status(co) ~= "dead" then - table.insert(unpackCo, co) - end - elseif fileData then - local handle = io.open(string.match(fileTransferState, ":(.*)"), "w") - if handle then - handle:write(fileData) - handle:close() - end - end - fileTransferState = nil - end - elseif packetType == "close" then - if term.isColor() then - term.setBackgroundColor(colors.black) - term.setTextColor(colors.white) - end - term.clear() - term.setCursorPos(1, 1) - print("Connection closed by server.") - nshAPI.serverNum = nil - if nshAPI.connList and nshAPI.connList.localShell then nshAPI.connList.localShell.outbound = nil end - return - end - end - elseif event[1] == "mouse_click" or event[1] == "mouse_drag" or event[1] == "mouse_scroll" or event[1] == "key" or event[1] == "char" then - --pack up event - send(serverNum, "event", textutils.serialize(event)) - elseif event[1] == "terminate" then - nshAPI.serverNum = nil - if nshAPI.localShell then nshAPI.localShell.outbound = nil end - term.clear() - term.setCursorPos(1, 1) - print("Connection closed locally.") - return - end - end -else - print("Usage: nsh [resume]") - print(" nsh host [remote [local [name]]]") -end diff --git a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua b/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua deleted file mode 100644 index a31fe0be9..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/Lyqyd/nsh/put.lua +++ /dev/null @@ -1,35 +0,0 @@ -if not nsh then print("No nsh session!") return end - -local args = {...} - -if #args < 2 then - print("Usage: put ") - print(": any file on the client") - print(": any file on the server") - return -end - -local fileData = "" - -nsh.send("FQ:;t="..args[1]) -local message = nsh.receive() -if message ~= "fileNotFound" then - while true do - message = nsh.receive() - pType = string.sub(message, 1, 2) - if pType == "FD" then - fileData = fileData..string.match(message, "^FD:;t=(.*)") - elseif pType == "FE" then - break - end - end - if #fileData > 0 then - local handle = io.open(args[2], "w") - if handle then - handle:write(fileData) - handle:close() - end - else - print("Empty file not written!") - end -end diff --git a/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua b/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua deleted file mode 100644 index 88e394b1e..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/TheOriginalBIT/tictactoe/tictactoe.lua +++ /dev/null @@ -1,444 +0,0 @@ ---[[ -Author: TheOriginalBIT -Version: 1.1.2 -Created: 26 APR 2013 -Last Update: 30 APR 2013 - -License: - -COPYRIGHT NOTICE -Copyright © 2013 Joshua Asbury a.k.a TheOriginalBIT [theoriginalbit@gmail.com] - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and -associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - --The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. --Visible credit is given to the original author. --The software is distributed in a non-profit way. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -]]-- - --- make sure that its only a computer terminal that is displaying -local sw, sh = term.getSize() - -if sw ~= 51 and sh ~= 19 then - error("Sorry this game can only run on computers", 0) -end - --- the wining directions -local winCombos = { - -- horizontal - {1,2,3}, {4,5,6}, {7,8,9}, - -- vertical - {1,4,7}, {2,5,8}, {3,6,9}, - -- diagonal - {1,5,9}, {3,5,7} -} - -local players = {x = 'Player', o = 'The Computer'} --- whether an AI is active, could be used later to allow SP -local activeAI = true -local currentPlayer -local opposites = { x = 'o', o = 'x' } -local board -local winner -local move -local allowedBgColors = { colors.orange, colors.lightBlue, colors.gray, colors.cyan, colors.purple, colors.blue, colors.brown, colors.green, colors.red, colors.black } -local bg - -local function clear(col) - term.setBackgroundColor(col or colors.black) - term.clear() - term.setCursorPos(1,1) -end - --- function thanks to Mads... found here: http://www.computercraft.info/forums2/index.php?/topic/11771-print-coloured-text-easily/page__p__105389#entry105389 -local function writeWithFormat(...) - local s = "&0" - for k, v in ipairs(arg) do - s = s .. v - end - s = s .. "&0" - local fields = {} - local lastcolor, lastpos = "0", 0 - for pos, clr in s:gmatch"()&(%x)" do - table.insert(fields, {s:sub(lastpos + 2, pos - 1), lastcolor}) - lastcolor, lastpos = clr , pos - end - for i = 2, #fields do - term.setTextColor(2 ^ (tonumber(fields[i][2], 16))) - write(fields[i][1]) - end -end - --- modification of Mads' function to get the length of the string without the color modifiers -local function countFormatters(text) - return #(text:gsub("()&(%x)", '')) -end - --- print a color formatted string in the center of the screen -local function cwriteWithFormat(text, y) - local sw,sh = term.getSize() - local _,cy = term.getCursorPos() - term.setCursorPos(math.floor((sw-countFormatters(text))/2)+(countFormatters(text) % 2 == 0 and 1 or 0), y or cy) - writeWithFormat(text) -end - --- writes the text at the give location -local function writeAt(text, x, y) - local _,cy = term.getCursorPos() - term.setCursorPos(x or 1, y or cy) - write(text) -end - -local function reset() - bg = allowedBgColors[math.random(1, #allowedBgColors)] - currentPlayer = 'x' - board = {} - for i = 1, 9 do - board[i] = ' ' - end - winner = nil - move = nil -end - -local function search(match) - for _, check in ipairs(winCombos) do - if board[check[1]] == board[check[2]] and board[check[1]] == match and board[check[3]] == ' ' then - return check[3] - elseif board[check[1]] == board[check[3]] and board[check[1]] == match and board[check[2]] == ' ' then - return check[2] - elseif board[check[2]] == board[check[3]] and board[check[2]] == match and board[check[1]] == ' ' then - return check[1] - end - end -end - -local function getAIMove() - -- make it seem like the computer actually has to think about its move - sleep(0.8) - - -- check if AI can win and return the 3rd tile to create a win, if it cannot, check for a human attempt at winning and stop it, if there is none, return a random - return (search(currentPlayer) or search(opposites[currentPlayer])) or math.random(1,9) -end - -local function modread( _mask, _history, _limit ) - term.setCursorBlink(true) - - local input = "" - local pos = 0 - if _mask then - _mask = _mask:sub(1,1) - end - local historyPos = nil - - local sw, sh = term.getSize() - local sx, sy = term.getCursorPos() - - local function redraw( _special ) - local scroll = (sx + pos >= sw and (sx + pos) - sw or 0) - local replace = _special or _mask - term.setCursorPos( sx, sy ) - term.write( replace and string.rep(replace, #input - scroll) or input:sub(scroll + 1) ) - term.setCursorPos( sx + pos - scroll, sy ) - end - - while true do - local event = {os.pullEvent()} - if event[1] == 'char' and (not _limit or #input < _limit) then - input = input:sub(1, pos)..event[2]..input:sub(pos + 1) - pos = pos + 1 - elseif event[1] == 'key' then - if event[2] == keys.enter then - break - elseif event[2] == keys.backspace and pos > 0 then - redraw(' ') - input = input:sub(1, pos - 1)..input:sub(pos + 1) - pos = pos - 1 - elseif event[2] == keys.delete and pos < #input then - redraw(' ') - input = input:sub(1, pos)..input:sub(pos + 2) - elseif event[2] == keys.home then - pos = 0 - elseif event[2] == keys['end'] then - pos = #input - elseif event[2] == keys.left and pos > 0 then - pos = pos - 1 - elseif event[2] == keys.right and pos < #input then - pos = pos + 1 - elseif _history and event[2] == keys.up or event[2] == keys.down then - redraw(' ') - if event[2] == keys.up then - if not historyPos then - historyPos = #_history - elseif historyPos > 1 then - historyPos = historyPos - 1 - end - else - if historyPos ~= nil and historyPos < #_history then - historyPos = historyPos + 1 - elseif historyPos == #_history then - historyPos = nil - end - end - - if historyPos then - input = string.sub(_history[historyPos], 1, _limit) or "" - pos = #input - else - input = "" - pos = 0 - end - end - elseif event[1] == 'mouse_click' then - local xPos, yPos = event[3], event[4] - if xPos == sw and yPos == 1 then - -- exit and make sure to fool the catch-all - error('Terminated', 0) - end - local row = (xPos >= 16 and xPos <= 21) and 1 or (xPos >= 23 and xPos <= 28) and 2 or (xPos >= 30 and xPos <= 35) and 3 or 10 - local col = (yPos >= 4 and yPos <= 6) and 1 or (yPos >= 8 and yPos <= 10) and 2 or (yPos >= 12 and yPos <= 16) and 3 or 10 - local ret = (col - 1) * 3 + row - if ret >= 1 and ret <= 9 then - return ret - end - end - - redraw(_mask) - end - - term.setCursorBlink(false) - term.setCursorPos(1, sy + 1) - - return input -end - -local function getHumanMove() - writeWithFormat('&b[1-9] >>&f ') - return modread() -end - -local function processInput() - -- set the cursor pos ready for the input - term.setCursorPos(3, sh-1) - move = (currentPlayer == 'x' and getHumanMove or getAIMove)() -end - -local function output(msg) - -- if the player is not an AI, print the error - if not (activeAI and currentPlayer == 'o') then - term.setCursorPos(3, sh-1) - writeWithFormat('&eERROR >> '..msg) - sleep(2) - end -end - -local function checkMove() - -- if the user typed exit - if not tonumber(move) and move:lower() == 'exit' then - -- exit and make sure to fool the catch-all - error('Terminated', 0) - end - - -- attempt to convert the move to a number - local nmove = tonumber(move) - -- if it wasn't a number - if not nmove then - output(tostring(move)..' is not a number between 1 and 9!') - return false - end - -- if it is not within range of the board - if nmove > 9 or nmove < 1 then - output('Must be a number between 1 and 9!') - return false - end - -- if the space is already taken - if board[nmove] ~= ' ' then - output('Position already taken!') - return false - end - -- keep the conversion - move = tonumber(move) - return true -end - -local function checkWin() - for _, check in ipairs(winCombos) do - if board[check[1]] ~= ' ' and board[check[1]] == board[check[2]] and board[check[1]] == board[check[3]] then - return board[check[1]] - end - end - - for _, tile in ipairs(board) do - if tile == ' ' then - return nil - end - end - - return 'tie' -end - -local function update() - if checkMove() then - board[move] = currentPlayer - winner = checkWin() - - currentPlayer = currentPlayer == 'x' and 'o' or 'x' - end -end - -local function render() - -- clear the screen light blue - clear(bg) - - -- draw the ascii borders - term.setTextColor(colors.white) - for i = 2, sh-1 do - writeAt('|', 1, i) - writeAt('|', sw, i) - end - writeAt('+'..string.rep('-', sw-2)..'+', 1, 1) - writeAt('+'..string.rep('-', sw-2)..'+', 1, 3) - writeAt('+'..string.rep('-', sw-2)..'+', 1, sh-2) - writeAt('+'..string.rep('-', sw-2)..'+', 1, sh) - - if term.isColor and term.isColor() then - term.setCursorPos(sw, 1) - term.setBackgroundColor(colors.red) - term.setTextColor(colors.black) - writeWithFormat('X') - end - - -- set our colours - term.setBackgroundColor(colors.white) - term.setTextColor(colors.black) - - -- clear an area for the title - writeAt(string.rep(' ', sw-2), 2, 2) - writeAt('Tic-Tac-Toe!', sw/2-5, 2) - - -- clear an area for the input - writeAt(string.rep(' ', sw-2), 2, sh-1) - - -- clear the area for the board - local h = sh - 6 - for i = 0, h - 1 do - writeAt(string.rep(' ', sw - 2), 2, 4+i) - end - - -- draw the grid - for i = 0, 10 do - writeAt(((i == 3 or i == 7) and '------+------+------' or ' | | '), 16, i + 4) - end - - -- draw the first line moves - for i = 1, 3 do - if board[i] ~= ' ' then - writeAt((board[i] == 'x' and '\\/' or '/\\'), 18+((i-1)*7), 5) - writeAt((board[i] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 6) - end - end - -- draw the second line moves - for i = 1, 3 do - if board[i + 3] ~= ' ' then - writeAt((board[i + 3] == 'x' and '\\/' or '/\\'), 18+((i-1)*7), 9) - writeAt((board[i + 3] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 10) - end - end - -- draw the third line moves - for i = 1, 3 do - if board[i + 6] ~= ' ' then - writeAt((board[i + 6] == 'x' and '\\/' or '/\\'), 18+((i-1)*7), 13) - writeAt((board[i + 6] == 'x' and '/\\' or '\\/'), 18+((i-1)*7), 14) - end - end - - -- draw the current player - term.setCursorPos(3, sh - 3) - if not winner then - writeWithFormat('&bCurrent Player: &f'..players[currentPlayer]) - end -end - -local function main(arc, argv) - clear() - writeWithFormat('&0Welcome to CCTicTacToe by &8TheOriginal&3BIT&0\n\nPlease enter your name\n\n&4>>&0 ') - players.x = read() or 'Player' - - -- setup the game, will later be used to - reset() - - -- initial render - render() - - -- game loop - while not winner do - processInput() - update() - render() - - -- highly unorthodox having something that isn't in input, update, render! - -- print the winner info - if winner then - writeWithFormat('&f'..(winner == 'tie' and 'There was no winner :(&f' or players[winner]..'&f is the winner!')) - -- allow the player to start a new game or quit - writeAt("Press 'R' to play again, 'Q' to quit...", 3, sh - 1) - while true do - local _, k = os.pullEvent('key') - if k == 16 then - break - elseif k == 19 then - reset() -- reset the game - render() -- render the new game ready to wait for input - break - end - end - os.pullEvent() -- remove the char event that would be waiting - end - end - - return true -end - --- create a terminal object with a non-advanced computer safe version of setting colors -local oldTermObj = term.current() -local termObj = { - setTextColor = function(n) if term.isColor and term.isColor() then local ok, err = pcall(oldTermObj.setTextColor , n) if not ok then error(err, 2) end end end, - setBackgroundColor = function(n) if term.isColor and term.isColor() then local ok, err = pcall(oldTermObj.setBackgroundColor , n) if not ok then error(err, 2) end end end -} --- also override the English spelling of the colour functions -termObj.setTextColour = termObj.setTextColor -termObj.setBackgroundColour = termObj.setBackgroundColor - --- make the terminal object refer to the native terminal for every other function -termObj.__index = oldTermObj -setmetatable(termObj, termObj) - --- redirect the terminal to the new object -term.redirect(termObj) - --- run the program -local ok, err = pcall(main, #{...}, {...}) - --- catch-all -if not ok and err ~= 'Terminated' then - clear() - print('Error in runtime!') - print(err) - sleep(5) -end - --- print thank you message -clear() -cwriteWithFormat('&4Thank you for playing CCTicTacToe v1.0', 1) -cwriteWithFormat('&4By &8TheOriginal&3BIT\n', 2) - --- restore the default terminal object -term.redirect( oldTermObj ) diff --git a/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua b/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua deleted file mode 100644 index dc1672f70..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua +++ /dev/null @@ -1,47 +0,0 @@ - -local filmText = '2\n\n\n\n\n\n\n\n\n\n\n\n\n\n15\n\n\n\n\n WWW.ASCIIMATION.CO.NZ\n\n\n presents\n\n\n\n\n\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n .......... @@@@@ @@@@@.......\n ......... @ @ @ @.......\n ........ @@@ @ @........\n ....... @@ @ @ .......\n ...... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@.........\n ......... @ @ @ @.........\n ........ @@@ @ @ .........\n ....... @@ @ @ .........\n ....... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ........ @@@ @ @ .........\n ....... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .......\n .... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ .......\n ..... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ .........\n ....... @@ @ @ .......\n ...... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ..\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ .........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ......\n ...... @@@@@@@ @@@@@ th ......\n ...... ----------------------- ....\n ..... C E N T U R Y ...\n .... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ...........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ......... @@@ @ @ .........\n ........ @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ........ @@@ @ @ ..........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ .........\n .......... @ @ @ @ .........\n ......... @@@ @ @ .........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n .... ----------------------- ........\n ... C E N T U R Y .......\n .. ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ......\n .......... @ @ @ @ .......\n ........ @@@ @ @ ........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- ........\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ............. @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- ........\n ..... C E N T U R Y .......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n............ @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ........ ----------------------- ........\n ....... C E N T U R Y .......\n ..... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n.......... @@@@@ @@@@@ .......\n.......... @ @ @ @ ........\n .......... @@@ @ @ ........\n ........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- .......\n ...... C E N T U R Y ......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n....... @@@@@ @@@@@ .........\n........ @ @ @ @ .........\n......... @@@ @ @ .........\n ......... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th ........\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ........\n...... @ @ @ @ ........\n....... @@@ @ @ ........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- .....\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ...........\n...... @ @ @ @ ..........\n....... @@@ @ @ .........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ...........\n...... @ @ @ @ ..........\n....... @@@ @ @ .........\n........ @@ @ @ .......\n ........ @@@@@@@ @@@@@ th ......\n ....... ----------------------- ......\n ...... C E N T U R Y ....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ..........\n...... @ @ @ @ ..........\n....... @@@ @ @ ........\n........ @@ @ @ .......\n ........ @@@@@@@ @@@@@ th ......\n ....... ----------------------- ......\n ...... C E N T U R Y ....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n....... @@@@@ @@@@@ ..........\n........ @ @ @ @ .........\n........ @@@ @ @ .........\n ........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- ......\n ..... C E N T U R Y ....\n .... ----------------------- ...\n ... @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n......... @@@@@ @@@@@ ...........\n......... @ @ @ @ ...........\n ......... @@@ @ @ ..........\n ........ @@ @ @ .........\n ........ @@@@@@@ @@@@@ th .......\n ...... ----------------------- ......\n ..... C E N T U R Y ....\n .... ----------------------- ...\n ... @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........ @@@@@ @@@@@ ...........\n ........ @ @ @ @ ...........\n ....... @@@ @ @ ..........\n ........ @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ...........\n ......... @ @ @ @ ...........\n ........ @@@ @ @ ..........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@...........\n ......... @ @ @ @..........\n ........ @@@ @ @...........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@........\n ......... @ @ @ @........\n ........ @@@ @ @.........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@.......\n ......... @ @ @ @.......\n ........ @@@ @ @........\n ...... @@ @ @ .......\n ..... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@.........\n ........ @ @ @ @.........\n ....... @@@ @ @ .........\n ...... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th .......\n .... ----------------------- ......\n ... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ........ @@@ @ @ .........\n ....... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .......\n .... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ .......\n ..... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ .........\n ....... @@ @ @ .......\n ...... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ..\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ .........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ......\n ...... @@@@@@@ @@@@@ th ......\n ...... ----------------------- ....\n ..... C E N T U R Y ...\n .... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ...........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ......... @@@ @ @ .........\n ........ @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ........ @@@ @ @ ..........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ .........\n .......... @ @ @ @ .........\n ......... @@@ @ @ .........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n .... ----------------------- ........\n ... C E N T U R Y .......\n .. ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ......\n .......... @ @ @ @ .......\n ........ @@@ @ @ ........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- ........\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ............. @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- ........\n ..... C E N T U R Y .......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n............ @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ........ ----------------------- ........\n ....... C E N T U R Y .......\n ..... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n.......... @@@@@ @@@@@ .......\n.......... @ @ @ @ ........\n .......... @@@ @ @ ........\n ........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- .......\n ...... C E N T U R Y ......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n....... @@@@@ @@@@@ .........\n........ @ @ @ @ .........\n......... @@@ @ @ .........\n ......... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th ........\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ........\n...... @ @ @ @ ........\n....... @@@ @ @ ........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- .....\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ...........\n...... @ @ @ @ ..........\n....... @@@ @ @ .........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n10\n\n\n\n\n\n\n\n\n\n\n\n\n\n30\n\n\n\n\n A long time ago in a galaxy far,\n far away....\n\n\n\n\n\n\n\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n40\n\n 8888888888 888 88888\n 88 88 88 88 88 88\n 8888 88 88 88 88888\n 88 88 888888888 88 88\n 88888888 88 88 88 88 888888\n\n 88 88 88 888 88888 888888\n 88 88 88 88 88 88 88 88\n 88 8888 88 88 88 88888 8888\n 888 888 888888888 88 88 88\n 88 88 88 88 88 8888888\n\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n8\n\n\n\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n8\n\n\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n8\n\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n8\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n8\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n8\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n8\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n\n8\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n8\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n\n8\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n8\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n8\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n8\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n8\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n8\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n8\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n8\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n8\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n\n8\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n8\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n\n8\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n8\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n\n8\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n8\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n\n8\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n8\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n\n8\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n8\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n\n8\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n8\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n\n8\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n8\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n8\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n8\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n8\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n8\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n8\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n8\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n8\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n8\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n8\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n8\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n8\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n8\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n8\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n8\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n8\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n8\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n8\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n8\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n8\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n8\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n8\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n8\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n8\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n8\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n\n8\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n\n\n8\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n\n\n\n11\n\n\n\n\n\n\n\n\n\n\n\n\n\n8\n . . . . . .\n .\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n2\n .\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n1\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n1\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n . .\n2\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n2\n . 88888888888888\n 8888888888888888 . . .\n 8888888888888888\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n2\n 8888888888888888 . . .\n 8888888888888888\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n2\n 8888888888888888\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n2\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n2\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n2\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n2\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n\n2\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n\n\n2\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n\n\n\n2\n . . .\n\n . .\n\n\n\n\n\n\n\n\n\n\n2\n\n . .\n\n\n\n\n\n\n\n\n\n\n\n2\n . .\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<8\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=O\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=O<\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O-\n O=<88>=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O______ ) _____\n / \\__/_________\\ /-\\ / __|\n . |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n . |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n . |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n .|====__ _________ |(O)|===|__\n. \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n. _\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n . ___\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n. .\n\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n.\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n. / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n .__ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____|\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __. _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n .\\__/ \\_________/ \\-/ \\_____|\n. <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ . _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ . _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n\n . _____\n __ ._<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n\n . \'__\n __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n ,\n . \'._\n __ _<>______ `) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n ; \' ,\n. . \'\n __ _<>______ : * _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . , . . .\n \' ,\n. . : * ,\n __ _<>______" *** _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . \' \'\n . \' ; \' . . .\n *\n. . ; , ***, \'\n __ _<>______ ***** _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . \' "\n . * \'. . .\n " * * ,\n. . , * * "\n __ _<>______ * ** _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . *\n " . . . .\n\n. . * * \'\n __ _<>______ _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . \'\n . . . .\n \'\n. .\n __ _<>______ _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n17\n .\n . . . .\n\n. .\n __ _<>______ _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_________________[_]_[_]_[_]________/_]_[_\\________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_______________[_]_[_]_[_]________/_]_[_\\__________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_________________[_]_[_]_[_]________/_]_[_\\________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_______________[_]_[_]_[_]________/_]_[_\\__________________________\n7\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n15\n /~\\\n |oo ) Did you hear that?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n ( oo| They\'ve shut down\n _\\=/_ the main reactor.\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n15\n /~\\\n ( oo| They\'ve shut down\n _\\=/_ the main reactor.\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\ #\n / ()\\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n15\n /~\\\n |oo ) We\'re doomed!\n _\\=/_\n ___ # / _ \\ #\n /() \\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n . .\n . . .\n .\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n______| . |__________________\n . . .\n .\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n======| . |==================\n______| . . |__________________\n .\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . |\n======| . . |==================\n______| |__________________\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . |\n | . . |\n======| |==================\n______| . . |__________________\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . ## ## |\n | . . |\n | |\n======| . . |==================\n______| . |__________________\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . ## ## |\n | ## . . ## |\n | |\n | . . |\n======| . |==================\n______| |__________________\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . ## ## |\n | ## . . ## |\n | ## ## |\n | . . |\n | . |\n======| |==================\n______| . __ _<>______ . _____ |__________________\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n1\n | . ## ## |\n | ## . . ## |\n | ## ## |\n | . ## ## . |\n | . |\n | |\n======| . __ _<>______ . _____ |==================\n______| / \\__/_________\\ /-\\ / __| |__________________\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . #### #### |\n | ## . . ## |\n | ## ## |\n | . ## ## . |\n | ## . ## |\n | |\n | . __ _<>______ . _____ |\n======| / \\__/_________\\ /-\\ / __| |==================\n______| |====__ _________ |(O)|===|__ |__________________\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n _________________________________________\n | #### . . #### |\n | ## ## |\n | . ## ## . |\n | ## . ## |\n | ## ## |\n | . __ _<>______ . _____ |\n | / \\__/_________\\ /-\\ / __| |\n======| |====__ _________ |(O)|===|__ |==================\n______| \\__/ \\_________/ \\-/ \\_____| |__________________\n . <>\n . .\n . .\n2\n\n _________________________________________\n | #### #### |\n | . ## ## . |\n | ## . ## |\n | ## ## |\n | . __ ##_<>______ . ##_____ |\n | / \\__/_________\\ /-\\ / __| |\n | |====__ _________ |(O)|===|__ |\n======| \\__/ \\_________/ \\-/ \\_____| |==================\n______| . <> |__________________\n . .\n . .\n2\n\n\n _________________________________________\n | . #### #### . |\n | ## . ## |\n | ## ## |\n | . __ ##_<>______ . ##_____ |\n | / \\_##_________\\ /-\\## __| |\n | |====__ _________ |(O)|===|__ |\n | \\__/ \\_________/ \\-/ \\_____| |\n======| . <> |==================\n______| . |__________________\n . .\n14\n\n\n\n _________________________________________\n | #### . #### |\n | ## ## |\n | . __ ##_<>______ . ##_____ |\n | / \\_##_________\\ /-\\## __| |\n | |====_##_________ |(O)##==|__ |\n | \\__/ \\_________/ \\-/ \\_____| |\n | . <> |\n======| . |==================\n______| . .|__________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n15\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // _____ \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // __*__ \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\____*____// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // _***_ \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\___***___// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // ***** \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\__*****__// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // ******* \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\_*******_// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | //*********\\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\*********// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | |* / \\ *| | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | |* \\_____/ *| | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | |* / \\ *| | | |\n | | | |* | \\ / | *| | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | |* | / \\ | *| | | |\n | | | |* \\_____/ *| | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | |* / \\ *| | | |\n | | | |* | \\ / | *| | | |\n | | | |* | | *| | | |\n | | | |* | | *| | | |\n | | | |* | / \\ | *| | | |\n | | | |* \\_____/ *| | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | ********* | | |\n | | | . ************* . | | |\n | | | ** / \' \\ ** | | |\n | | | .** | \\ / | ** | | |\n | | | . ** | . \'| ** : | | |\n | | | ** | | ** | | |\n | | | . ** | / . \\ | ** . | | |\n | | | ** \\_____/ ** | | |\n | | | . ************* . | | |\n | | |__________***********__________| | |\n |_| / \\ |_|\n / / / . . \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | " ********* | | |\n | | | ************* \' . | | |\n | | | " *************** | | |\n | | | ***| " |*** . " | | |\n | | | \' ***| " |*** | | |\n | | | ***| |*** . | | |\n | | | ,***| \' |*** " | | |\n | | | " *************** | | |\n | | | " ************* " | | |\n | | |__________***********__________| | |\n |_| / \'. \\ |_|\n / / / " \' " \\ \\ \\\n1\n \\_\\ \\ ____#____*************#________ / /_/\n | | | * _________ * | | |\n | | | # * ************* * " | | |\n | | | . * * # * * # | | |\n | | | * * . # "* *. | | |\n | | | \' * * " * * #| | |\n | | | # .* * \' * *. | | |\n | | | * * . \' * * " | | |\n | | | " * * # * * | | |\n | | | # * ************* * | | |\n | | |_________*____________*__"__#__| | |\n |_| / # ************ \\ |_|\n / / / \' \'\' # \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ # . | . | |\n | | # | . /***********\\ # | |\n | | | * * | | |\n | | . | # . * | | |\n | | | * * | | |\n | | | . * * |# . | |\n | | #| * . * . | | |\n | | | . * * | | |\n | | | \\**********#/ | . | |\n | | . |_______________________________| | |\n |_| /# # #\\ |_|\n / / / . # . . \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | # // \\\\ . | | |\n | | # | || || | | |\n | | | || || | # | |\n | | | . || || | | |\n | | | || || | | |\n | | . | || || # | \' | |\n | | | || || | | |\n | | | \\\\_________// | | |\n | | # |_________________________#_____| | |\n |_| / \\ # |_|\n / / # / \' # \\ \\ \\\n1\n \\_\\ \\ _#_____________________________ / /_/\n | | | _________ . | | |\n | | | // \\\\ | | |\n | | \' | || || | | |\n | | | || || | | |\n #| | | || || | | |\n | | | || || | # | |\n | | | || || | .| |\n | | | || || | | |\n | | | . \\\\_________// | # | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / /# # \\ # \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | . || || . | | |\n | | | || || | | |\n | | | || || | | |\n # | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | \\\\_________// #| |#|\n | | . |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n # | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / # \\ |_|\n / / / \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / # \\ \\ \\\n4\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | //| __ |\\\\ | |\n | | || |/ \\| \\\\ | |\n | | || [][][] \\\\ | |\n | | || |\\ /| \'| | |\n | | \'] |_||_| | |\n | | [I [ ][ ] | |\n | \\_____I_|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | //| ()\\|| | |\n | | || |/ \\ | | |\n | | || [][][\\/ | |\n | | || |\\ /| | |\n | | \'] |_||_| | |\n | | [I [ ][ ] | |\n | \\_____I_|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=O\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=*\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ | |\n | | ||/***|| | |\n | | | / *\\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / *** \\ | |\n | | ||*****| | |\n | | | /*** | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ | |\n | | ||/***|| | |\n | | | / *\\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=*\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=O\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=*\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ | |\n | | ||/***|| || |\n | | | / *\\ | || |\n | | \\/][][\\/ || |\n | | |\\ /| \'| |\n | | |_||_| [| |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / *** \\ | |\n | | ||*****| || |\n | | | /*** | || |\n | | \\/][][\\/ || |\n | | |\\ /| \'| |\n | | |_||_| [| |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ /| |\n | | ||/***|| | | |\n | | | / *\\ | ||| |\n | | \\/][][\\/ ||| |\n | | |\\ /| \']| |\n | | |_||_| [I| |\n | | [ ][ ] I| |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ /| |\n | | ||/=*\\|| | | |\n | | | / \\ | ||| |\n | | \\/][][\\/ ||| |\n | | |\\ /| \']| |\n | | |_||_| [I| |\n | | [ ][ ] I| |\n | \\_______|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| || |\n | | (_/\\_) (| |\n | | / \\ / | |\n | | ||/=O\\|| | || |\n | | | / \\ | |||| |\n | | \\/][][\\/ ||[| |\n | | |\\ /| \']|| |\n | | |_||_| [I|| |\n | | [ ][ ] I[| |\n | \\_______|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| |<| |\n | | (_/\\_) (_| |\n | | / \\ / | |\n | | ||/=O\\|| | | | |\n | | | / \\ | |||/| |\n | | \\/][][\\/ ||[]| |\n | | |\\ /| \']|\\| |\n | | |_||_| [I|_| |\n | | [ ][ ] I[ | |\n | \\_______|_||_|_____|/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | | |<><>| |<>| |\n | | (_/\\_) (_/| |\n | | / \\ / | |\n | | ||/=*\\|| | | _| |\n | | | / \\ | |||/ | |\n | | \\/][][\\/ ||[][| |\n | | |\\ /| \']|\\ | |\n | | |_||_| [I|_|| |\n | | [ ][ ] I[ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | | |<><>| |<>| |\n | | (_/\\_) (_/| |\n | | / * \\ / | |\n | | ||/***|| | | _| |\n | | | / *\\ | |||/ | |\n | | \\/][][\\/ ||[][| |\n | | |\\ /| \']|\\ | |\n | | |_||_| [I|_|| |\n | | [ ][ ] I[ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | | |<><>| |<>| |\n | | (_/\\_) (_/| |\n | |\\ / *** \\ / | |\n | || ||*****| ||/=| |\n | || | /*** | | / | |\n | |/ \\/][][\\/ \\/][| |\n | | |\\ /| |\\ | |\n | | |_||_| |_|| |\n | | [ ][ ] [ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | || |<><>| |<>| |\n | |) (_/\\_) (_/| |\n | | \\ / * \\ / | |\n | ||| ||/***|| ||/=| |\n | | | | / *\\ | | / | |\n | |\\/ \\/][][\\/ \\/][| |\n | || |\\ /| |\\ | |\n | || |_||_| |_|| |\n | |] [ ][ ] [ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | |>| |<><>| |<>| |\n | |_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |\\|| ||/=*\\|| ||/=| |\n | |\\ | | / \\ | | / | |\n | | \\/ \\/][][\\/ \\/][| |\n | |/| |\\ /| |\\ | |\n | |_| |_||_| |_|| |\n | | ] [ ][ ] [ ]| |\n | \\|______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /\\ /__\\ /\\ |\n | |<>| |<><>| |<>| |\n | |\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |O\\|| ||/=O\\|| ||/*| |\n | | \\ | | / \\ | | / | |\n | |][\\/ \\/][][\\/ \\/][| |\n | | /| |\\ /| |\\ | |\n | ||_| |_||_| |_|| |\n | |[ ] [ ][ ] [ ]| |\n | \\_|_____|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /_\\ /__\\ /\\ |\n | |><>| |<><>| |<>| |\n | |/\\_) (_/\\_) (_/| |\n | | \\ / \\ / *| |\n | |=*\\|| ||/=O || ||**| |\n | | \\ | | / \\ | | /*| |\n | |[][\\/ \\/][][\\/ \\/][| |\n | | /| |\\ /| |\\ | |\n | |||_| |_||_| |_|| |\n | |][ ] [ ][ ] [ ]| |\n | \\|_|____|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | * \\ / \\ / | |\n | |/***|| ||/=* || ||/*| |\n | |/ *\\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | *** \\ / * \\ / | |\n | |*****| ||/***|| ||/O| |\n | |/*** | | / *\\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | * \\ / *** \\ / | |\n | |/***|| ||*****| ||/*| |\n | |/ *\\ | | /*** | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / * \\ / *| |\n | |/=* || ||/***|| ||**| |\n | |/ \\ | | / *\\ | | /*| |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |/=O || ||/=*\\|| ||/*| |\n | |/ \\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |/=O || ||/=O\\|| ||/=| |\n | |/ \\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |/=* || ||/=O\\|| ||/=| |\n | |/ \\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | * \\ / \\ / | |\n | |/***|| ||/=*\\|| ||/=| |\n | |/ *\\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | *** \\ / * \\ / | |\n | |*****| ||/***|| ||/=| |\n | |/*** | | / *\\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | |\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\| | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | |\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==* -- | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | ---\n / \\ / \\ | |\n //__ __*\\\\ | |\n \\--([=*** \\ -----\n | * \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ _***\\ | |\n \\--([*****\\ | |-----\n | *** \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __* \\ | |\n \\--([=***\\\\ | | -----\n | * \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==* \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | *--\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | .* \'\n _\\ -/_ | ***\n / \\ / \\ | *\n //__ __|\\\\ | | \' ----\n \\--([==* -- | | -\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ |: * # \'\n /_/- -| | ***\n _\\ -/_ | *****\n / \\ / \\ |# *** .\n //__ __*\\\\ | * # -----\n \\--([=***\\\\----- | \'\n | * \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ \' | * #\n /_/- -| | *** \'\n _\\ o/_ \' *****\n / \\ / \\ | *** \'\n //__ _***\\ # * -----\n \\--([*****\\ | .-----\n | *** \\\\ | | #\n |====| \')| . | \'\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ \' | *\n /_/0 0| | */|\\* \' \'\n _\\ o/_ |*|\\|| *\n / \\ / \\ \' | *\\|/*\n //__ __*\\\\ | * -----\n \\--([=***\\\\ | | ----- \'\n | * #\\ | |\n |====| \')| | \'\n | || | |\' | #\n____________________( )( )___._| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /*\\ \'\n _\\ -/_ | |*|*\n / \\ / \\ | \\*/\n //__ __|\\\\ | | -----\n \\--([==* \\\\ | | -----\n | | \\\\ | |\n |====| \')| | \'\n | || |# | |\n____________________( )( )_____| |\n | || | \\ | #\n |_||_| \\ | \'\n [_][__\\\' \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n //__ __|\\\\ | | -----\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | |# | \\ |\n |_||_| \\ |\n [_][__\\ \\|___________#___________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n //__ __|\\\\ | -----\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ | #\n #[_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n //__ __|\\\\----- |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ | #\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ o/_ | | ||\n / \\ / \\ | \\|/\n //__ *---- | |\n \\--([==o \\\\ | | ---\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ | #\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/- o| | /|\\\n _\\ O/_ | | ||\n / \\*/ \\ | \\|/\n //__***|\\\\ | |\n \\--([*=o \\\\ | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n___________________( )( )_____| |\n | || | \\ |\n |_||_| \\ | #\n [_][__\\ \\|________________________________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\ O/_ | | ||\n / *** \\ | \\|/\n //_*****\\\\ | |\n \\--(***o \\\\ | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|____________________#__________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\***_ | | ||\n / *****\\ | \\|/\n //*******\\ | |\n \\--***** \\\\ | |\n | ***| \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ | #\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\ -/_ | | ||\n / *** \\ | \\|/\n //_*****\\\\ | |\n \\--(***o \\\\ | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|______________________#________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\ -/_ | | ||\n / \\*/ \\ | \\|/\n // ***|\\\\ | |\n \\\\ * | \\\\ | |\n \\\\ | \\\\ | |\n [==o=| \')| |\n /| || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________#_______\n3\n /~___\\ | |\n /_/x x| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n // |\\\\ | |\n || | \\\\ | |\n || | | \\\\ | |\n || |====| \')| |\n (\' | || | | |\n____________________( )( )_____| |\n [==o| || | \\ |\n / |_||_| \\ |\n [_][__\\ \\|________________________#______\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n10\n __ /~~\\ __\n /__\\ |<><>| /__\\\n |<><>| /_/\\_\\ |<><>|\n (_/\\_) /\\___/\\ (_/\\_)\n / \\ // [ ]|\\\\ / \\\n ||/(===o ||| [_]| \\\\ //| __ |\\\\\n | / \\ | ||| | \\\\ || |/ \\| \\\\\n \\/][][\\/ |||====| \\\\ || [][][] \\\\\n |\\ /| #/|\\ /I\\ # || |\\ /| \')\n |_||_| / | || I \\ \'] |_||_|\n [ ][ ] / | || | \\ [I [ ][ ]\n | || | / | || | \\ I | || |\n | || | / | || | \\ | || |\n6\n __ /~~\\ __\n /__\\ |<><>| /__\\\n |<><>| /_/\\_\\ |<><>|\n (_/\\_) /\\___/\\ (_/\\_)\n / \\ // [ ]|\\\\ / \\\n ||/(===o ||| [_]| \\\\ ||/(===o\\\n | / \\ | ||| | \\\\ | / \\| \\\\\n \\/][][\\/ |||====| \\\\ \\/][][] \\\\\n |\\ /| #/|\\ /I\\ # |\\ /| \')\n |_||_| / | || I \\ |_||_|\n [ ][ ] / | || | \\ [ ][ ]\n | || | / | || | \\ | || |\n | || | / | || | \\ | || |\n18\n __ /~~\\ __\n /__\\ |<><>| /__\\\n |<><>| /_/\\_\\ |<><>|\n (_/\\_) /\\___/\\ (_/\\_)\n / \\ // [ ]|\\\\ / \\\n ||/(===o //| [_]| \\\\ ||/(===o\n | / \\ | \\\\| | // | / \\||\n \\/][][\\/ \\#====|#/ \\/][][\\/\n |\\ /| /|\\ /I\\ |\\ /|\n |_||_| / | || I \\ |_||_|\n [ ][ ] / | || | \\ [ ][ ]\n | || | / | || | \\ | || |\n | || | / | || | \\ | || |\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n30\n /~~\\\n |<><>| Commander, tear this ship apart\n /_/\\_\\ until you\'ve found those plans.\n /\\___/\\\n // [ ]|\\\\\n //| [_]| \\\\\n \\\\| | //\n \\#====|#/\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n2\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\\n // [ ]|\\\\\n //| [_]| \\\\\n \\\\| | //\n \\#====|#/\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n30\n /~~\\\n |<><>| And bring me the passengers.\n /_/\\_\\ # I want them alive!\n /\\___/\\ //\n // [ ]|\\\\//\n //| [_]| \\/\n \\\\| |\n \\#====|\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n5\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\\n // [ ]|\\\\\n //| [_]| \\\\\n \\\\| | //\n \\#====|#/\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n /~\\\n |oo )\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n11\n /~\\\n ( oo|\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n11\n /~\\\n |oo )\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n11\n /~\\\n ( oo|\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n6\n /~\\\n |oo )\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n || \\_/ ||\n || |\\ /| ||\n # \\_ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n6\n /~\\\n R2-D2! |oo )\n Where are you? _\\=/_\n / _ \\\n //|/.\\|\\\\\n || \\_/ ||\n || |\\ /| ||\n # \\_ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n9\n /~\\\n R2-D2! |oo )\n Where are you? # _\\=/_ #\n \\\\ / _ \\ //\n \\\\//|/.\\|\\\\//\n \\/ \\_/ \\/\n |\\ /|\n \\_ _/\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n9\n /~\\\n R2-D2! |oo )\n Where are you? # _\\=/_ #\n \\\\ / _ \\ //\n \\\\//|/.\\|\\\\//\n \\/ \\_/ \\/\n |\\ /|\n \\_ _/\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n8\n /~\\\n ( oo|\n # _\\=/_ #\n \\\\ / _ \\ //\n \\\\//|/.\\|\\\\//\n \\/ \\_/ \\/\n |\\ /|\n \\_ _/\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n ,===\n (@o o@\n \\ -/\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @ | | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n______________________(_)(__\\______[_]_____[_]_____________________\n11\n ,===\n (@o o@\n \\ -/\n //~ ~~\\ ___\n / ( ) \\ / ()\\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n______________________(_)(__\\______[_]_____[_]_____________________\n8\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n11\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) / ()\\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n7\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n6\n\n ===,\n @o o@)\n / \\-_/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n16\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n7\n ===,\n @o o@)\n \\- /\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n1\n ===,\n @o o@)\n \\- /\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ [_] /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n10\n ===,\n @o o@)\n \\- /\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\ /=\\\n_______________________(_)(__\\_____[_]_[_]_[_]_____________________\n13\n ,===\n (@o o@\n \\ -/\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @ | | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\ /=\\\n_______________________(_)(__\\_____[_]_[_]_[_]_____________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n20\n /~\\\n |oo ) At last!\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n7\n /~\\\n |oo ) Where have\n _\\=/_ you been?\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo ) Where have\n _\\=/_ you been?\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n9\n /~\\\n |oo ) Where have\n _\\=/_ you been?\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\ #\n /() \\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n /() \\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\ #\n /() \\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n /() \\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n21\n /~\\\n |oo ) Secret mission?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n12\n /~\\\n |oo ) What plans?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo ) What plans?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n8\n /~\\\n |oo ) What plans?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /__\\ /__\\\n |<><>| |<><>|\n (_/\\_) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n__________________________/__][_]_________[_][__\\__________________\n3\n /__\\ /__\\\n |<><>| |<><>|\n (_/\\_) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n___________________________/__][_]_________[_][__\\_________________\n3\n /__\\ /__\\\n |><> | |<><>|\n (/\\__) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n____________________________/__][_]_________[_][__\\________________\n3\n /__\\ /__\\\n |><> | |<><>|\n (/\\__) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n_____________________________/__][_]_________[_][__\\_______________\n3\n /__\\ /__\\\n |><> | |<><>|\n (/\\__) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n______________________________/__][_]_________[_][__\\______________\n3\n /__\\ /__\\\n |><> | |><> |\n (/\\__) (/\\__)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n_______________________________/__][_]_________[_][__\\_____________\n3\n /__\\ /__\\\n |><> | |><> |\n (/\\__) (/\\__)\n / \\ / \\\n\\ //| __ |\\\\ ||/(===o\n| // |/ \\| \\\\ | / \\ |\n| // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n________________________________/__][_]_________[_][__\\____________\n3\n /__\\ /__\\\n |><> | |><> |\n (/\\__) (/\\__)\n\\ / \\ / \\\n \\ //| __ |\\\\ ||/(===o\no| // |/ \\| \\\\ | / \\ |\n|| // [][][] || \\/][][\\/\n@ |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n_________________________________/__][_]_________[_][__\\___________\n3\n /__\\ /__\\\n@ |><> | |><> |\n (/\\__) (/\\__)\n~\\ / \\ / \\\n\\ \\ //| __ |\\\\ ||/(===o\n=o| // |/ \\| \\\\ | / \\ |\n || // [][][] || \\/][][\\/\n @ |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n\\ | || | | || |\n~ |_||_| |_||_|\n\\_________________________________/__][_]_________[_][__\\__________\n3\n= /__\\ /__\\\no@ |><> | |><> |\n/ (/\\__) (/\\__)\n~~\\ / \\ / \\\n)\\ \\ //| __ |\\\\ ||/(===o\n==o| // |/ \\| \\\\ | / \\ |\n| || // [][][] || \\/][][\\/\n| @ |\' |\\ /| [\' |\\ /|\n| |_||_| I] |_||_|\n| [ ][ ] I [ ][ ]\n \\ | || | | || |\n~~ |_||_| |_||_|\n_\\_________________________________/__][_]_________[_][__\\_________\n3\n== /__\\ /__\\\n o@ |><> | |><> |\n-/ (/\\__) (/\\__)\n ~~\\ / \\ / \\\n )\\ \\ //| __ |\\\\ ||/(===o\n@==o| // |/ \\| \\\\ | / \\ |\n | || // [][][] || \\/][][\\/\n | @ |\' |\\ /| [\' |\\ /|\n | |_||_| I] |_||_|\n | [ ][ ] I [ ][ ]\n \\ | || | | || |\n~~~ |_||_| |_||_|\n(_\\_________________________________/__][_]_________[_][__\\________\n3\n=== /__\\ /__\\\no o@ |><> | |><> |\n -/ (/\\__) (/\\__)\n ~~\\ / \\ / \\\n_ )\\ \\ //| __ |\\\\ ||/(===o\n/@==o| // |/ \\| \\\\ | / \\ |\n /| || // [][][] || \\/][][\\/\n| | @ |\' |\\ /| [\' |\\ /|\n| | |_||_| I] |_||_|\n| | [ ][ ] I [ ][ ]\n| \\ | || | | || |\n~~~~ |_||_| |_||_|\n)(_\\_________________________________/__][_]_________[_][__\\_______\n3\n,=== /__\\ /__\\\n@o o@ |><> | |><> |\n\\ -/ (/\\__) (/\\__)\n~ ~~\\ / \\ / \\\n__ )\\ \\ //| __ |\\\\ ||/(===o\n_/@==o| // |/ \\| \\\\ | / \\ |\n\\ /| || // [][][] || \\/][][\\/\n | | @ |\' |\\ /| [\' |\\ /|\n | | |_||_| I] |_||_|\n | | [ ][ ] I [ ][ ]\n | \\ | || | | || |\n~~~~~ |_||_| |_||_|\n_)(_\\_________________________________/__][_]_________[_][__\\______\n3\n ,=== /__\\ /__\\\n(@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n/~ ~~\\ / \\ / \\\n\\__ )\\ \\ //| __ |\\\\ ||/(===o\n\\_/@==o| // |/ \\| \\\\ | / \\ |\n\\\\ /| || // [][][] || \\/][][\\/\n| | | @ |\' |\\ /| [\' |\\ /|\n| | | |_||_| I] |_||_|\n| | | [ ][ ] I [ ][ ]\n | \\ | || | | || |\n~~~~~~ |_||_| |_||_|\n(_)(_\\_________________________________/__][_]_________[_][__\\_____\n3\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n//~ ~~\\ / \\ / \\\n \\__ )\\ \\ //| __ |\\\\ ||/(===o\n\\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n/ | \\ | || | | || |\n~~~~~~~ |_||_| |_||_|\n_(_)(_\\_________________________________/__][_]_________[_][__\\____\n2\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\\\\\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n7\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n18\n ,=== /__\\ /__\\\n (@o o@ There\'s one. |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n3\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n8\n ,=== /__\\ /__\\\n (@o o@ Set for stun! |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ /o===)\\|| ||/(===o\n \\\\_/@==o| // |/ \\ | | / \\ |\n |\\ /| || // [][][\\/ \\/][][\\/\n | | | @ |\' |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n9\n ,=== /__\\ /__\\\n (@o o@ Set for stun! |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ o===)\\|| ||/(===o\n \\\\_/@==o| ||/ \\ | | / \\ |\n |\\ /| || \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n5\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ o===)\\|| ||/(===o\n \\\\_/@==o| ||/ \\ | | / \\ |\n |\\ /| || \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ *===)\\|| ||/(===o\n \\\\_/@==*| ||/ \\ | | / \\ |\n |\\ /| || \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ | / \\ / \\\n\\ \\__ )\\ \\ | | o===)\\|| ||/(===o\n \\\\_/@=***---- | ||/ \\ | | / \\ |\n |\\ /| *| \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ | (/\\__) (/\\__)\n //~ ~~* | | / \\ / \\\n\\ \\__ )* * | | | o===)\\|| ||/(===o\n \\\\_/@***** ----- | | ||/ \\ | | / \\ |\n |\\ /|*** | \\/][][\\/ \\/][][\\/\n | | | * |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ | |><> | |><> |\n \\ -/ | | (/\\__) (/\\__)\n //~ ~~\\ | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | o===)\\|| ||/(===o\n \\\\_/@=*** ----- | | | ||/ \\ | | / \\ |\n |\\ /| *| | | \\/][][\\/ \\/][][\\/\n | | | @ | |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | /__\\ /__\\\n (@o o@ | | |><> | |><> |\n \\ -/ | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | o===)\\|| ||/(===o\n \\\\_/@==*| ----| | | ||/ \\ | | / \\ |\n |\\ /| || | | | \\/][][\\/ \\/][][\\/\n | | | @ | | |\\ /| |\\ /|\n | | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | | /__\\ /__\\\n (@o o@ | | | |><> | |><> |\n \\ -/ | | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | | o===)\\|| ||/(===o\n \\\\_/@==o| | | |---|- | ||/ \\ | | / \\ |\n |\\ /| || | | | | \\/][][\\/ \\/][][\\/\n | | | @ | | | |\\ /| |\\ /|\n | | | | | |_||_| |_||_|\n | | | | [ ][ ] [ ][ ]\n / | \\ | | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | | | /__\\ /__\\\n (@o o@ | | | | |><> | |><> |\n \\ -/ | | | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | | | o===)\\|| ||/(===o\n \\\\_/@==o| | | | | | --|-- ||/ \\ | | / \\ |\n |\\ /| || | | | | | \\/][][\\/ \\/][][\\/\n | | | @ | | | | |\\ /| |\\ /|\n | | | | | | |_||_| |_||_|\n | | | | | [ ][ ] [ ][ ]\n / | \\ | | | || | | || |\n ~~~~~~~ | |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | | | | /__\\ /__\\\n (@o o@ | | | | | |><> | |><> |\n \\ -/ | | | | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | | | o===)\\|| ||/(===o\n \\\\_/@==o| | | | | | | | ----* \\ | | / \\ |\n |\\ /| || | | | | | | \\/][][\\/ \\/][][\\/\n | | | @ | | | | | |\\ /| |\\ /|\n | | | | | | | |_||_| |_||_|\n | | | | | | [ ][ ] [ ][ ]\n / | \\ | | | | || | | || |\n ~~~~~~~ | | |_||_| |_||_|\n__(_)(_\\____|____________________________/__][_]_________[_][__\\___\n1\n ,=== | | | | | /__\\ /__\\\n (@o o@| | | | | | |><> | |><> |\n \\ -/ | | | | | | | (/\\__) (/\\__)\n //~ ~~| | | | | | | | / \\ / \\\n\\ \\__ )\\|\\ | | | | | | | o=*=)\\|| ||/(===o\n \\\\_/@==|| | | | | | | | |*** \\ | | / \\ |\n |\\ /| || | | | | | | \\/*[][\\/ \\/][][\\/\n | | | | | | | | | |\\ /| |\\ /|\n | | | | | | | | |_||_| |_||_|\n | | | | | | | [ ][ ] [ ][ ]\n / | \\| | | | | || | | || |\n ~~~~~~~| | | |_||_| |_||_|\n__(_)(_\\|___|____________________________/__][_]_________[_][__\\___\n1\n ,|== | | | | | /__\\ /__\\\n (@| -@| | | | | | |><> | |><> |\n \\|-/ | | | | | | | (/\\__) (/\\__)\n //~| ~~| | | | | | | / * \\ / \\\n\\ \\_| )\\|\\ | | | | | | o***)\\|| ||/(===o\n \\\\_|@==|| | | | | | | *****\\ | | / \\ |\n |\\|/| || | | | | | | \\***][\\/ \\/][][\\/\n | | | | | | | | | |* /| |\\ /|\n | | | | | | | | |_||_| |_||_|\n | | | | | | | [ ][ ] [ ][ ]\n / | \\| | | | | || | | || |\n ~~~|~~~| | | |_||_| |_||_|\n__(_|(_\\|___|____________________________/__][_]_________[_][__\\___\n1\n| ,|== | | | | | /__\\ /__\\\n| (@| -@| | | | | | |<><>| |><> |\n| \\|-/ | | | | | | | (_/\\_) (/\\__)\n|//~| ~~| | | | | | | / \\ / \\\n| \\_| )\\|\\ | | | | | | o=*=)\\|| ||/(===o\n|\\\\_|@==|| | | | | | | |*** \\ | | / \\ |\n| |\\|/| || | | | | | | \\/*[][\\/ \\/][][\\/\n| | | | | | | | | | | /| |\\ /|\n| | | | | | | | | |_||_| |_||_|\n| | | | | | | | [ ][ ] [ ][ ]\n|/ | \\| | | | | || | | || |\n|~~~|~~~| | | |_||_| |_||_|\n|_(_|(_\\|___|____________________________/__][_]_________[_][__\\___\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /__\\\n | <><|\n (__/\\)\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n12\n /__\\\n | <><| Inform Lord Vader we have\n (__/\\) a prisoner.\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n7\n /__\\\n |<><>| Inform Lord Vader we have\n (_/\\_) a prisoner.\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n5\n /__\\\n |<><>|\n (_/\\_)\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /----------------------\\\n | |oo ) |\n | _\\=/_ |\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n10\n /----------------------\\\n | |oo ) | I\'m going to\n | _\\=/_ | regret this.\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n7\n /----------------------\\\n | ( oo| | I\'m going to\n | _\\=/_ | regret this.\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n7\n /----------------------\\\n | |oo ) | I\'m going to\n | _\\=/_ | regret this.\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n2\n /----------------------\\\n | |oo ) |\n | _\\=/_ |\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n |\\____________________/|\n | _\\=/_ |\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n |\\____________________/|\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n | / \\ |\n |\\____________________/|\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | \\________/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | | || |\n | \\________/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | | || |\n | | | |\n | \\_______// |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | | || |\n | | _| |\n | |_ / | |\n | \\\\_____/_/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n | | _| |\n | |_ / | |\n | |)\\ //|| |\n | \\_|___||_/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | \\ ________ / |\n | / \\ |\n | |_ / | |\n | |)\\ //|| |\n | |__|_ || | |\n | \\_|_|_||_/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n \\----------------------/\n___________________________________________________________________\n10\n /----------------------\\\n | \\ / |\n | \\ ________ / |\n | / /\\ |\n | |)\\ //|| |\n | |__|_ || | |\n | |= | | || || |\n | \\_|_|__#_/ |\n | / \\ |\n | / \\ |\n |/ \\ |\n \\----------------------/\n___________________________________________________________________\n10\n /----------------------\\\n | \\ / |\n | \\ ________ / |\n | / /\\ |\n | |)\\ //|| |\n | |__|_ || | |\n | |= | | || || |\n | \\_|_|_#__/ |\n | / \\ |\n | / \\ |\n |/ \\ |\n \\----------------------/\n___________________________________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ /___ ___\\ /\n / / / \\ / \\ \\ \\\n | / | || | \\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\ | || | / |\n \\ \\ \\___/ \\___/ / /\n / \\__________/ \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ * /___ ___\\ * /\n / / / \\ / \\ \\ \\\n | / | || | \\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\ | || | / |\n \\ \\ \\___/ \\___/ / /\n / * \\__________/ * \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ ** /___ ___\\/** /\n / ** / \\ / \\ ** \\\n | / | || | \\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\ | || | / |\n \\ ** \\___/ \\___/ ** /\n / ** \\__________/ ** \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ ****___ ___**** /\n /****/ \\ / \\****\\\n | /**| || |**\\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\**| || |**/ |\n \\****\\___/ \\___/****/\n / ***\\__________/*** \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ /**_________*\\ / /\n \\ *****__ __***** /\n /***** \\ / *****\\\n | **** || *****|\n | *** \\___/ \\___/ **|\n | | |*|\n | | ___ ___ | |\n | * / \\ / \\ ****|\n |****| || ******|\n \\*****___/ \\___*****/\n / *****________***** \\\n / \\***________*/ \\\n1\n \\ ____________ /\n \\ \\ /******__****\\ / /\n \\ ******* ******* /\n /****** \\ / *******\\\n |******* || *******|\n |******___/ \\___/ ****|\n |** ***|\n |*| ___ ___ ***|\n |**** / \\ / \\*****|\n |****** || *******|\n \\******__/ \\_*******/\n / *******_____****** \\\n / \\*****___****/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ****************** /\n /********************\\\n |******* || *********|\n |******___/ \\_********|\n |***** *******|\n |***** ___ _********|\n |******** \\ /*********|\n |********* ||**********|\n \\********************/\n / ****************** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ****************** /\n /********************\\\n |**********************|\n |**********************|\n |**********************|\n |**********************|\n |**********************|\n |**********************|\n \\********************/\n / ****************** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ****************** /\n /********************\\\n |********* ************|\n |********/ \\ **********|\n |******| \\_/\\_*********|\n |*******|/ \\/ ********|\n |********\\ / **********|\n |********** ***********|\n \\********************/\n / ****************** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ********* .******* /\n /****** ______ ****\\\n |****** / _ _ \\ *****|\n |***** | / \\/ \\ |. ****|\n |***. | \\_/\\_/ | ****|\n |***** | / \\/ \\ | *****|\n |***** | \\_/\\_/ |******|\n |****** \\______/*******|\n \\******* .* *******/\n / ******** ******** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /** . *\\ / /\n \\ *** . * /\n /** . * *\\\n |*** .* **|\n |* ---- . *|\n |* . |()()| |\n |. | |. * |\n |* |()()| **|\n |** * .---- ***|\n \\*** . . ***/\n / **** . *** \\\n / \\***____*___*/ \\\n1\n \\ ____________ /\n \\ \\ / . * \\ / /\n \\ * . * /\n / . \\\n |* . |\n | ---- . |\n | . |()()| |\n |. | |. * |\n | |()()| . |\n | .---- |\n \\ * . . /\n / . ** \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / . \\ / /\n \\ . /\n / . * \\\n | . |\n | -- . |\n | . |OO| |\n |. * .|OO| . |\n | -- . |\n | . |\n \\ . . /\n / . \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / . \\ / /\n \\ . /\n / . \\\n | . |\n | -- . |\n | . |OO| |\n |. .|OO| . |\n | -- . |\n | . |\n \\ . . /\n / . \\\n / \\____________/ \\\n2\n \\ ____________ /\n \\ \\ / . \\ / /\n \\ . /\n / . \\\n | . |\n | _ . |\n | . (_) |\n |. . . |\n | . |\n | . |\n \\ . . /\n / . \\\n / \\____________/ \\\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | o . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | " . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n5\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n24\n ____________\n / \\ / . \\ / \\\n There goes \\ \\ . / /\n another one. / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n25\n ____________\n / \\ / . \\ / \\\n \\ \\ . / / Hold your fire!\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n24\n ____________\n / \\ / . \\ / \\\n \\ \\ . / / There\'s no\n / \\ / \\ / \\ life forms.\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n5\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ____________\n / __________ \\\n /__|O=<88>=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O<>| |><> |\n (_/\\_) (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][_] \\________________[_][__\\____\n37\n /__\\ /__\\\n |<><>| Someone was |><> |\n (_/\\_) in the pod. (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][_] \\________________[_][__\\____\n5\n /__\\ /__\\\n |<><>| |><> |\n (_/\\_) (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][_] \\________________[_][__\\____\n6\n /__\\ /__\\\n | <><| Look sir - |><> |\n (__/\\) droids. (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][__\\ \\________________[_][__\\____\n34\n /__\\ /__\\\n | <><| Look sir - |><> |\n (__/\\) droids. (/\\__)\n / \\ /O / \\\n //| __ \\\\// ||/(===o\n // |/ \\| \\/ | / \\ |\n //__[][][] \\/][][\\/\n ____/|\' |\\ /|. |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][__\\ \\________________[_][__\\____\n6\n /__\\ /__\\\n | <><| |><> |\n (__/\\) (/\\__)\n / \\ /O / \\\n //| __ \\\\// ||/(===o\n // |/ \\| \\/ | / \\ |\n //__[][][] \\/][][\\/\n ____/|\' |\\ /|. |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][__\\ \\________________[_][__\\____\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n\n\n .\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n\n\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n\n .\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n\n| .\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n\n|\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n_\n=|\n/ |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n_\n=| .\n/ |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n__\n =| .\n / |\n/ _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n__\n =|\n / |\n/ _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n___\n =|\n / |\n / _________ .|\n/ __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n____\n =| .\n / |\n / _________ .|\n_/ __/ o o o o \\ .||.\no____________________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n_____\n =| .\n / |\n / _________ .|\n__/ __/ o o o o \\ .||.\noo___________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n_____\n =|\n / |\n / _________ .|\n__/ __/ o o o o \\ .||.\noo___________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n______\n =|\n] / |\n / _________ .|\n___/ __/ o o o o \\ .||.\nooo__________________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n______\n =| .\n] / |\n / _________ .|\n___/ __/ o o o o \\ .||.\nooo__________________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n_______\n_ =| .\n_] / |\n / _________ .|\n____/ __/ o o o o \\ .||.\n_ooo_________________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n_______\n_ =|\n_] / |\n / _________ .|\n____/ __/ o o o o \\ .||.\n_ooo_________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n________\n _ =|\n[_] / |\n / _________ .|\n_____/ __/ o o o o \\ .||.\n__ooo________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n_________\n _ =| .\n [_] / |\n / _________ .|\n______/ __/ o o o o \\ .||.\no__ooo_______________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n__________\n _ =| .\n [_] / |\n / _________ .|\n_______/ __/ o o o o \\ .||.\noo__ooo______________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n__________\n _ =|\n [_] / |\n / _________ .|\n_______/ __/ o o o o \\ .||.\noo__ooo______________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n___________\n _ =|\n [_] / |\n / _________ .|\n________/ __/ o o o o \\ .||.\nooo__ooo_____________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n___________\n _ =| .\n [_] / |\n / _________ .|\n________/ __/ o o o o \\ .||.\nooo__ooo_____________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n ___________\n| _ =| .\n| [_] / |\n| / _________ .|\n|________/ __/ o o o o \\ .||.\n_ooo__ooo____________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n| _ =|\n| [_] / |\n| / _________ .|\n|________/ __/ o o o o \\ .||.\n_ooo__ooo____________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n__ooo__ooo___________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n__ooo__ooo___________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n___ooo__ooo__________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n____ooo__ooo_________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n_____ooo__ooo________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n_____ooo__ooo________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo______________________________||__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo______________________________||__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo______________________________||__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo_____________________________|_|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo_____________________________|_|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo_____________________________|_|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo____________________________|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo____________________________|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________________|__||__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________________|__||__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________________|__|_|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________________|__|_|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________________|__|_|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________________|__|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________________|__|__|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________________|__|___|__|__________|__|[]|_\n\n1\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________________|__|___|__|__________|__|[]|_\n\n5\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________________|__|___|__|__________|__|[]|_\n\n1\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________________|___|___|__|__________|__|[]|_\n\n6\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________________|___|___|__|__________|__|[]|_\n\n4\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________________|___|___|__|__________|__|[]|_\n\n2\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n4\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n2\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n2\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n4\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_____________________|______|__|__|__________|__|[]|_\n\n6\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_____________________|______|__|__|__________|__|[]|_\n\n6\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo____________________|_______|__|__|__________|__|[]|_\n\n4\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo____________________|_______|__|__|__________|__|[]|_\n\n2\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________|________|__|__|__________|__|[]|_\n\n5\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________|________|__|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________|________|__|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________|_________|__|__|__________|__|[]|_\n\n4\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________|_________|__|__|__________|__|[]|_\n\n4\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________|_________|__|__|__________|__|[]|_\n\n2\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________|__________|__|__|__________|__|[]|_\n\n6\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________|__________|__|__|__________|__|[]|_\n\n2\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________|__________|__|__|__________|__|[]|_\n\n4\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________|___________|__|__|__________|__|[]|_\n\n6\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________|___________|__|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________|___________|__|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________|____________|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | \\\\\n || | | | \\\\\n (` |====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n20\n ====\n ~~o o Doesn\'t look like we have\n _\\ -/_ much of a choice...\n / \\ / \\\n //| | |\\\\\n || | | | \\\\\n || | | | \\\\\n (` |====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n3\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | \\\\\n || | | | \\\\\n (` |====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n2\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n \\\\| | | \\\\\n \\\\ | | \\\\\n )====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n31\n ====\n ~~o o ...but I\'ll remind him.\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n \\\\| | | \\\\\n \\\\ | | \\\\\n )====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n6\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n \\\\| | | \\\\\n \\\\ | | \\\\\n )====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n9\n /~\\ / / / \\\n |oo ) | | | |\n _____ _\\=/_ | | | |\n / \\ / _ \\ \\ \\ \\_____/\n | o o| //|/.\\|\\\\ \\ \\\n _|_____|_ || \\_/ || \\ \\\n | | === | | || |\\ /| || \\ \\ _____\n |_| o |_| # \\_ _/ # \\ \\ / \\\n || o || | | | \\ \\ | |\n ||__*__|| | | | \\ \\ | |\n |~ \\___/ ~| []|[] \\ \\ \\_____/\n /=\\ /=\\ /=\\ | | | \\ \\_____________\n------[_]-[_]-[_]--------/_]-[_\\--------------------\\______________\n6\n /~\\ / / / \\\n ( oo| | | | |\n _____ _\\=/_ | | | |\n / \\ / _ \\ \\ \\ \\_____/\n | o o| //|/.\\|\\\\ \\ \\\n _|_____|_ || \\_/ || \\ \\\n | | === | | || |\\ /| || \\ \\ _____\n |_| o |_| # \\_ _/ # \\ \\ / \\\n || o || | | | \\ \\ | |\n ||__*__|| | | | \\ \\ | |\n |~ \\___/ ~| []|[] \\ \\ \\_____/\n /=\\ /=\\ /=\\ | | | \\ \\_____________\n------[_]-[_]-[_]--------/_]-[_\\--------------------\\______________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n30\n /""\\ ====\n / o o Luke! Take these two o o~~\n _\\ -/_ over to the garage. _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n30\n /""\\ ====\n / o o I want them cleaned o o~~\n _\\ -/_ up before dinner. _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n30\n /""\\ ====\n / o o But I was going o o~~\n _\\ -/_ into Toshi station _\\- /_\n /\\\\ //\\ to pick up some / \\ / \\\n // \\\\// \\\\ power converters. //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n29\n /""\\ ====\n / o o You can waste o o~~\n _\\ -/_ time with your _\\- /_\n /\\\\ //\\ friends later. / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n14\n /""\\ ====\n / o o All right. o o~~\n _\\ -/_ Come on. _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n5\n /""\\ ====\n / o o All right. ~~o o\n _\\ -/_ Come on. _\\ -/_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n13\n /""\\ ====\n / o o All right. ~~o o\n _\\ -/_ Come on. _\\ -/_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n3\n /""\\ ====\n / o o ~~o o\n _\\ -/_ _\\ -/_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n6\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n30\n /""\\ ====\n / o o Come on Red! o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n1\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n9\n / / / \\\n | | | |\n _____ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n6\n / / / \\\n | | | |\n _____ | | | |\n / \\ \\ \\ \\_____/\n |o o | \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n2\n / / / \\\n | | | |\n _____ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n __.__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . / / / \\\n . ** \' | | | |\n *||*_ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . ** \' / / / \\\n **** | | | |\n . **||** | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n **** / / / \\\n ****** | | | |\n **||** | | | |\n . / \\ \' \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n . | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n ** / / / \\\n **** | | | |\n *||*_ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \' \\ \\\n . | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n . ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n ** | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n . || o || \' \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n . /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n * | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \' \\ \\ \\_____/\n. /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . / / / \\\n * | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \' \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . / / / \\\n . | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]---------\'-------------------------\\______________\n1\n . / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \' \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \' \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \' \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \' \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]----------------------------\'------\\______________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | \\\\\n || |\\ /| || || | | | \\\\\n # \\_ _/ # (` |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| Uncle Owen! o o~~\n _\\=/_ This R2 unit has _\\- /_\n / _ \\ a bad motivator. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | \\\\\n || |\\ /| || || | | | \\\\\n # \\_ _/ # (` |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n14\n /~\\ ====\n |oo ) Uncle Owen! o o~~\n _\\=/_ This R2 unit has _\\- /_\n / _ \\ a bad motivator. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | \\\\\n || |\\ /| || || | | | \\\\\n # \\_ _/ # (` |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n |oo ) Uncle Owen! o o~~\n _\\=/_ This R2 unit has _\\- /_\n / _ \\ a bad motivator. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || || | | //\n # \\_ _/ # (` |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n3\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || || | | //\n # \\_ _/ # (` |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n ( oo| Excuse me sir! o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || || | | //\n # \\_ _/ # (` |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n ( oo| Excuse me sir! o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n ( oo| That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n |oo ) That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n |oo ) That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || \\\\| | |//\n // |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n19\n /~\\ ====\n |oo ) That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || \\\\| | |//\n // |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n7\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || \\\\| | |//\n // |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n20\n\n\n\n ___\n / ()\\\n _|_____|_\n | | === | |\n |_| O |_|\n || O ||\n ||__*__||\n |~ \\___/ ~|\n /=\\ /=\\ /=\\\n________________[_]_[_]_[_]________________________________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n21\n /~\\ ====\n ( oo| Uncle Owen! o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n18\n /~\\ ====\n ( oo| What about o o~~\n _\\=/_ that one? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n |oo ) What about o o~~\n _\\=/_ that one? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n11\n /~\\ ====\n |oo ) What about o o~~\n _\\=/_ that one? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || // | | |//\n || |\\ /| || // | | //\n # \\_ _/ # (\' |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n7\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo ) Now don\'t you\n _\\=/_ forget this.\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n11\n /~\\\n |oo ) Now don\'t you\n _\\=/_ forget this.\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ // \\_/ ||\n | | === | | // |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n17\n /~\\\n |oo ) Now don\'t you\n _\\=/_ forget this.\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n9\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n /_] [_\\ ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n | | | ====\n /_] [_\\ o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n []|[] ====\n | | | o o~~\n /_] [_\\ _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n | | | ====\n []|[] o o~~\n | | | _\\- /_\n /_] [_\\ ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n | | | ====\n | | | o o~~\n []|[] _\\- /_\n | | | ___ / \\ / \\\n /_] [_\\ / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n # \\_ _/ # ====\n | | | o o~~\n | | | _\\- /_\n []|[] ___ / \\ / \\\n | | | / ()\\ //| | |\\\\\n /_] [_\\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n || |\\ /| || ====\n # \\_ _/ # o o~~\n | | | _\\- /_\n | | | ___ / \\ / \\\n []|[] / ()\\ //| | |\\\\\n | | | _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n || \\_/ || ====\n || |\\ /| || o o~~\n # \\_ _/ # _\\- /_\n | | | ___ / \\ / \\\n | | | / ()\\ //| | |\\\\\n []|[] _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n //|/.\\|\\\\ ====\n || \\_/ || o o~~\n || |\\ /| || _\\- /_\n # \\_ _/ # ___ / \\ / \\\n | | | / ()\\ //| | |\\\\\n | | | _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n / _ \\ ====\n //|/.\\|\\\\ o o~~\n || \\_/ || _\\- /_\n || |\\ /| || ___ / \\ / \\\n # \\_ _/ # / ()\\ //| | |\\\\\n | | | _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n _\\=/_ ====\n / _ \\ Thank the maker! o o~~\n //|/.\\|\\\\ _\\- /_\n || \\_/ || ___ / \\ / \\\n || |\\ /| || / ()\\ //| | |\\\\\n # \\_ _/ # _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n ( oo| ====\n _\\=/_ Thank the maker! o o~~\n / _ \\ _\\- /_\n //|/.\\|\\\\ ___ / \\ / \\\n || \\_/ || / ()\\ //| | |\\\\\n || |\\ /| || _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n /~\\ ====\n ( oo| Thank the maker! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n ====\n /~\\ Thank the maker! o o~~\n ( oo| _\\- /_\n _\\=/_ ___ / \\ / \\\n / _ \\ / ()\\ //| | |\\\\\n //|/.\\|\\\\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n22\n ====\n Thank the maker! o o~~\n /~\\ _\\- /_\n ( oo| ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n3\n ====\n o o~~\n /~\\ _\\- /_\n ( oo| ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n15\n ====\n This oil bath o o~~\n /~\\ is going to _\\- /_\n ( oo| feel so good. ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n12\n ====\n This oil bath o o~~\n /~\\ is going to _\\- /_\n |oo ) feel so good. ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n5\n ====\n o o~~\n /~\\ _\\- /_\n |oo ) ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n1\n ====\n o o~~\n /~\\ _\\- /_\n ( oo| ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n31\n ====\n o o~~ Well, my\n _\\- /_ little friend...\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n15\n ====\n o o~~ ...you\'ve got\n _\\- /_ something jammed\n ___ / \\ / \\ in here real good.\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n16\n ====\n o o~~ ...you\'ve got\n _\\- /_ something jammed\n ___ / \\ / \\ in here real good.\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n4\n ====\n o o~~\n _\\O /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n Help me, o o~~\n Obi-Wan Kenobi! _\\O /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n15\n ====\n You\'re my only o o~~\n hope! _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n Help me, o o~~\n Obi-Wan Kenobi! _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n15\n ====\n You\'re my only o o~~\n hope! _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n1\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__ __|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n1\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__ __|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n11\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n8\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n9\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n10\n ====\n He says it\'s o o~~\n nothing sir. _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n18\n ====\n He says it\'s o o~~\n nothing sir. _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n28\n ====\n Old data. o o~~\n Pay it no mind. _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n3\n ====\n o o~~\n _\\o /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| (===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n11\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| (===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n10\n ====\n o o~~ Where\'d she go?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| (===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n17\n ====\n o o~~ Where\'d she go?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | | \\\\\n | | === | | // | | | \\\\\n |_| O |_|(\' |====| `)\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n8\n ====\n o o~~ Where\'d she go?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| )===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n9\n ====\n o o~~ Bring her back!\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| )===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n21\n ====\n o o~~ Bring her back!\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| )===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n1\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n14\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n13\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n3\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n2\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n8\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\/() //| | |\\\\\n || \\/ |\\/ \\\\| |__|//\n ------------------------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n29\n /""\\ ====\n / o o o o~~ If these new\n _\\ -/_ _\\- /_ droids do work\n /\\\\ //\\ / \\ / \\ out...\n | \\\\// \\/() //| | |\\\\\n || \\/ |\\/ \\\\| |__|//\n ------------------------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n / o o o o~~ ...I want to\n _\\ -/_ _\\- /_ transmit my\n /\\\\ //\\ / \\ / \\ application\n | \\\\// \\/() //| | |\\\\ to the...\n || \\/ |\\/ \\\\| |__|//\n ------------------------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n / o o o o~~ ...I want to\n _\\ -/_ _\\- /_ transmit my\n /\\\\ //\\ / \\ / \\ application\n | \\\\// \\ //| | |\\\\ to the...\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n / o o o o~~ ...Academy\n _\\ -/_ _\\- /_ this year.\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n6\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n But harvest / o o o o~~\n is when I need _\\ -/_ _\\- /_\n you the most! /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n15\n /""\\ ====\n But harvest / o o o o~~\n is when I need _\\ -/_ _\\- /_\n you the most! /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n29\n /""\\ ====\n / o o o o~~ But it\'s a\n _\\ -/_ _\\- /_ whole \'nother\n /\\\\ //\\ / \\ / \\ year!\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n4\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n1\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n /\n -------------------------------------------------------\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n41\n /""\\ ====\n / o o Where are o o~~\n _\\ -/_ you going? _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n4\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n31\n /""\\ Looks like I\'m ====\n / o o going nowhere! o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n3\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n30\n /""\\ I have to go finish ====\n / o o cleaning those droids. o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n14\n ====\n ~~o o\n _\\ -/_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n10\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n5\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n2\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ // | | |//\n \\ \\ // | | //\n \\ \\ *(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\_______/~\\_________ // | | |//\n \\ \\ // | | //\n \\ \\ *(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ /~\\ //| | |\\\\\n____\\______( oo|________ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n _\\- /_\n\\ /~\\ / \\ / \\\n \\ ( oo| //| | |\\\\\n____\\_______\\=/_________ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n /~\\ _\\- /_\n\\ ( oo| / \\ / \\\n \\ _\\=/_ //| | |\\\\\n____\\_____/_____\\_______ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n /~\\ o o~~\n ( oo| _\\- /_\n\\ _\\=/_ / \\ / \\\n \\ / _ \\ //| | |\\\\\n____\\____//|/_\\|\\\\______ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n3\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ *(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n30\n /~\\ ====\n ( oo| What are you doing o o~~\n _\\=/_ hiding back there? _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n30\n /~\\ ====\n ( oo| It wasn\'t my fault o o~~\n _\\=/_ sir... _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n30\n /~\\ ====\n ( oo| ...he kept babbling o o~~\n _\\=/_ about his mission. _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n20\n /~\\ ====\n ( oo| Oh no! o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n9\n /~\\ ====\n ( oo| Oh no! o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~\\ ====\n |oo ) ([__])"\n _\\=/_ | \\-/||\n / _ \\ ||\\ /||\n //|/.\\|\\\\ \\/ | \\/\n // \\_/ || | | |\n // |\\ /| || | | |\n # \\_ _/ # |====|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n10\n /~\\ ====\n ( oo| ([__])"\n _\\=/_ | \\-/||\n / _ \\ ||\\ /||\n //|/.\\|\\\\ \\/ | \\/\n // \\_/ || | | |\n // |\\ /| || | | |\n # \\_ _/ # |====|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| ([__])"\n _\\=/_ | \\-/||\n / _ \\ ||\\ /||\n //|/.\\|\\\\ \\/ | \\/\n || \\_/ || | | |\n || |\\ /| || | | |\n # \\_ _/ # |====|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __>_______________. <__\n -- / \\___________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.000.0 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| /|\n --| / |\n -- \\__ / __/\n --- __>__________. | <__\n -- / \\___________________|____\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.010.0 \\______________/\n\n1\n _______________________________________\n / \\\n | ____|\n --| / |\n --| / |\n -- \\__ / __/\n --- __>_____. | <__\n -- / \\___________________|_________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.020.0 \\______________/\n\n1\n _______________________________________\n / \\\n | _________|\n --| / |\n --| / |\n -- \\__ / __/\n --- __>. | <__\n -- / \\___________________|______________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.040.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\|\n -- \\__ / __/\n --- __> | <__\n -- /___________________|___________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.050.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\__ / \\__/\n --- __> | <__\n -- /______________|______________________|_\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.060.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\__ / \\ __/\n --- __> | | <__\n -- /_________|______________________|______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.070.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\__ / \\ __/\n --- __> | | <__\n -- /____|______________________|___________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.080.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\/_ \\ __/\n --- __> | <__\n -- /______________________|________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.090.1 \\______________/\n\n1\n _______________________________________\n / \\\n | ___________ |\n --| \\ |\n --| \\ |\n -- \\__ \\ __/\n --- __> | <__\n -- /_________________|_____________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.100.1 \\______________/\n\n1\n _______________________________________\n / \\\n |_______ |\n --| \\ |\n --| \\ |\n -- \\__ \\ __/\n --- __> | <__\n -- /____________|__________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.110.1 \\______________/\n\n1\n _______________________________________\n / \\\n |__ |\n --| \\ |\n --| \\ |\n -- \\__ \\ __/\n --- __> | <__\n -- /_______|_______________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --|\\ |\n -- \\_\\ __/\n --- __> <__\n -- /__|____________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.130.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.140.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.150.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.160.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.170.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.180.1 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"_[/\n --- __> ]|<__\n -- /__________________________________]|"|[\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.190.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /_____________________________]|"|[_____\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.200.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /________________________]|"|[__________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.210.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /___________________]|"|[_______________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.220.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /______________]|"|[____________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.230.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /_________]|"|[_________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.240.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /____]|"|[______________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.250.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --|]|"|[ |\n -- \\|_|[ __/\n --- __>[ <__\n -- /|"|[___________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.260.2 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.270.2 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,<__\n -- /__________________________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.280.2 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,_____<__\n -- /_____________________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.290.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,__________<__\n -- /________________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.300.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,_______________<__\n -- /___________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.310.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,____________________<__\n -- /______________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.320.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,______________________. <__\n -- /_________/ \\____\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.330.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> .______________________. <__\n -- /____/ \\_________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.340.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __>____________________. <__\n -- / \\______________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.350.0 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __>_______________. <__\n -- / \\___________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.000.0 \\______________/\n\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n |oo ) Pardon me sir... o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n13\n /~\\ ====\n ( oo| Pardon me sir... o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n10\n /~\\ ====\n ( oo| Pardon me sir... o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n ( oo| ...but couldn\'t we o o~~\n _\\=/_ go after him? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n20\n /~\\ ====\n ( oo| ...but couldn\'t we o o~~\n _\\=/_ go after him? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n9\n /~\\ ====\n ( oo| It\'s too dangerous o o~~\n _\\=/_ with all the _\\- /_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n11\n /~\\ ====\n ( oo| It\'s too dangerous ~~o o\n _\\=/_ with all the _\\ -/_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| It\'s too dangerous o o~~\n _\\=/_ with all the _\\- /_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n ( oo| It\'s too dangerous o o~~\n _\\=/_ with all the _\\- /_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n15\n /~\\ ====\n ( oo| We\'ll have to o o~~\n _\\=/_ wait until morning. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n11\n /~\\ ====\n ( oo| We\'ll have to o o~~\n _\\=/_ wait until morning. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || ||__ | | ||\n # \\_ _/ # ([__]===| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n7\n /~\\ ====\n ( oo| We\'ll have to o o~~\n _\\=/_ wait until morning. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || ||__ | | ||\n # \\_ _/ # ([__]===| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || ||__ | | ||\n # \\_ _/ # ([__]===| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n\n\n __________ ___\n / \\ ______________ /\n/ \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n __________ ____\n/ \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n__________ _____\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n1\n\n\n\n\n\n_________ ______\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n1\n\n Look, there\'s a droid\n on the scanner.\n\n\n_________ ______\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n________ _______\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n_______ ________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n_____ __________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n____ ___________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n___ ____________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n__ _____________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n_ ______________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n _______________\n\\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n ________________\n ______________ /\n\\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n _________________\n ______________ /\n________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n _________________\n ______________ /\n_______/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n ___________________\n ______________ /\n______/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n ____________________\n ______________ /\n_____/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _____________________\n ______________ /\n____/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n ______________________\n ______________ /\n___/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n ______________ /\n__/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n ______________ / \\\n_/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n ______________ / \\_\n/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n______________ / \\__\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n_____________ / \\___\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n____________ / \\____\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n___________ / \\_____\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n__________ / \\______\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_________ / \\_______\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n________ / \\________\n \\ /\n \\______________________/\n =_+_\n__________====\'____________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_______ / \\_________\n \\ /\n \\______________________/\n =_+_\n___________====\'___________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n______ / \\__________\n \\ /\n \\______________________/\n =_+_\n____________====\'__________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_____ / \\___________\n \\ /\n \\______________________/\n =_+_\n_____________====\'_________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n____ / \\____________\n \\ /\n \\______________________/\n =_+_\n______________====\'________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n___ / \\_____________\n \\ /\n \\______________________/\n =_+_\n_______________====\'_______________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n__ / \\______________\n \\ /\n \\______________________/\n =_+_\n________________====\'______________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_ / \\_______________\n \\ /\n \\______________________/\n =_+_\n_________________====\'_____________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\________________\n\\ /\n \\______________________/\n =_+_\n__________________====\'____________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\_________________\n /\n\\______________________/\n =_+_\n___________________====\'___________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\__________________\n /\n______________________/\n =_+_\n_____________________====\'_________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\___________________\n /\n_____________________/\n =_+_\n_______________________====\'_______________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\___________________\n /\n____________________/\n =_+_\n_________________________====\'_____________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\_____________________\n /\n___________________/\n =_+_\n___________________________====\'___________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\______________________\n /\n__________________/\n =_+_\n_____________________________====\'_________________________________\n\n\n1\n\n\n\n\n\n _______________________\n / \\_______________________\n /\n_________________/\n =_+_\n_______________________________====\'_______________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\________________________\n /\n________________/\n =_+_\n_________________________________====\'_____________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\_________________________\n /\n_______________/\n =_+_\n___________________________________====\'___________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\__________________________\n /\n______________/\n =_+_\n_____________________________________====\'_________________________\n\n\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ Where do you think ====\n ( oo| you\'re going? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n15\n /~\\ Where do you think ====\n ( oo| you\'re going? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ Where do you think ====\n ( oo| you\'re going? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n \\\\ \\_/ // _|_____|_ \\\\| | |//\n \\\\\\ /// | | === | | \\\\ | //\n #_ _# |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n7\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n16\n /~\\ What\'s wrong with ====\n ( oo| him now? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n17\n /~\\ What\'s wrong with ====\n ( oo| him now? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ (, / \\ / \\ ,)\n //|/.\\|\\\\ / ()\\ \\\\//| | |\\\\//\n || \\_/ || _|_____|_ \\/ | | | \\/\n || |\\ /| || | | === | | | | |\n # \\_ _/ # |_| O |_| |====|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n1\n /~\\ What\'s wrong with ====\n ( oo| him now? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n21\n /~\\ There are several ====\n ( oo| creatures... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ ...approaching from ====\n ( oo| the southeast. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ ...approaching from ====\n ( oo| the southeast. o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n20\n /~\\ ====\n ( oo| Sand People! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n12\n /~\\ ====\n ( oo| Or worse! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n14\n /~\\ ====\n |oo ) Or worse! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n10\n\n /\n |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n15\n\n Well there are two /\n Banthas down there... |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n14\n\n Well there are two /\n Banthas down there... |\n /\n\\ /~\\ ==== /\n \\ ( oo| ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n20\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} {}|~~~~~~} <__\n -- /_________||~~||___________||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n16\n\n ...but I don\'t see /\n any... wait a second! |\n /\n\\ /~\\ ==== /\n \\ ( oo| ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n11\n\n ...but I don\'t see /\n any... wait a second! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n6\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} {}|~~~~~~} <__\n -- /_________||~~||___________||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n6\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{}+ {}|~~~~~~} <__\n -- /_________||~~||___|_______||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n15\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} + {}|~~~~~~} <__\n -- /_________||~~||____|______||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n21\n\n They\'re Sand People /\n all right! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n20\n\n I can see one of /\n of them now! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} + {}|~~~~~~} <__\n -- /_________||~~||____|______||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} + {}|~~~~~~} <__\n -- /_________||~~||____|______||~~||_______\\\n --| ############################ |\n --| ############################## |\n | ###########.-------.############ |\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| ############################ |\n -- \\__ ############################## __/\n --- __> ################################<__\n -- /___##################################__\\\n --| #################################### |\n --| ###################################### |\n | ###############.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / ############################## \\\n | ################################ |\n --| ################################## |\n --| #################################### |\n -- \\_######################################/\n --- __>#################################<__\n -- /#######################################\\\n --|#########################################|\n --|#########################################|\n |################.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / ######################################\\\n | ########################################|\n --|#########################################|\n --|#########################################|\n -- \\#######################################/\n --- __>#################################<__\n -- /#######################################\\\n --|#########################################|\n --|#########################################|\n |################.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n /#######################################\\\n |#########################################|\n --|#########################################|\n --|#########################################|\n -- \\#######################################/\n --- __>#################################<__\n -- /#######################################\\\n --|#########################################|\n --|#########################################|\n |################.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n\n I can see one of /\n of them now! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n /~~\\ ,\n1\n\n I can see one of /\n of them now! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n /~~\\ ,\n ( o o| /(*)\n \\\'#\'_// `\n1\n\n /\n |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/~~\\ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n ( o o| /(*)\n _ \'#\'_// `\n /\\-<=>//\n / / // \\\n1\n\n /\n |\n /\n\\ /~\\ ==== /\n \\ /~~\\ , |oo ) ([__])" ______/\n \\ ( o o| /(*) _\\=/_ | \\-/ | /\n | _\\\'#\'_//_` / _ \\ ||\\ /|| /\n \\__/\\-<=>// \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n / / // \\\n \\ \\ //|\\ \\\n \\(//|| \\()\n |//==|\n1\n\n /\n /~~\\ , |\n ( o o| /(*) /\n\\ _\\\'#\'_// ` /~\\ ==== /\n \\ /\\-<=>// |oo ) o o~~ ______/\n \\ / / // \\ _\\=/_ _\\o /_ /\n | \\ \\ //|\\ \\ / _ \\ / \\ / \\ /\n \\___\\(//|| \\()__//|/.\\|\\\\______//|_|_|_\\\\_______/\n |//==|\n // ||\n // / |\n // / |\n2\n /~~\\ ,\n ( o o| /(*) /\n _\\\'#\'_// ` |\n /\\-<=>// /\n\\ / / // \\ /~\\ ==== /\n \\ \\ \\ //|\\ \\ |oo ) o o~~ ______/\n \\ \\(//|| \\() _\\=/_ _\\o /_ /\n | |//==|___ / _ \\ / \\ / \\ /\n \\___// || \\___//|/.\\|\\\\______//|_|_|_\\\\_______/\n // / |\n // / |\n ^/ |\n /________\\\n2\n /~~\\ ,\n ( o o| /(*) /\n _\\\'#\'_ // ` |\n /\\-<=> // /\n\\ | | //\\ /~\\ ==== /\n \\ \\ \\ //\\ \\ |oo ) o o~~ ______/\n \\ \\_(//| \\() _\\=/_ _\\o /_ /\n | | //=|___ / _ \\ / \\ / \\ /\n \\___|// || \\___//|/.\\|\\\\______//|_|_|_\\\\_______/\n // / |\n /// |\n .^ |\n /________\\\n8\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n7\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|__|====\'_--+__/\n\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|_~|====\'_--+__/\n\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + ~+=_._ _______________/\n_____________|_____|______|__|====\'_--+__/\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|_~|====\'_--+__/\n\n\n8\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|_~|====\'_--+__/\n\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|__|====\'_--+__/\n ~\n\n4\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ________|\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ _______|_\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ______|__\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ _____|___\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ____|____\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ___|_____\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ __|______\n / \\ + + =_._ _______________/\n_____________|_____|_____|_|__====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ _|_______\n / \\ + + =_._ _______________/\n_____________|_____|____|_|___====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____|___|_|____====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____|__|_|_____====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____|_|_|______====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____||_|_______====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\+ + =_._ _______________/\n_____________|_____|_|________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / + + =_._ _______________/\n_____________|____|_|_________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / +\\+ =_._ _______________/\n_____________|___|_|__________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / + =_._ _______________/\n_____________|____||__________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / +\\ =_._ _______________/\n_____________|___|_|__________====\'_--+__/\n ~\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ =_._ _______________/\n_____________|_____|__________====\'_--+__/\n ~\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n10\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / |\n| /| | |\\ | / ==== /\n|| | | | || / x x~~ /\n(\' | | | `) | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n3\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / |\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / x x~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n2\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / x x~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n21\n ==== / ,_____________/\n ("- -) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / x x~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n8\n ==== / ,_____________/\n ("- -) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n1\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n4\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n3\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n7\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n1\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/______________________\n5\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n7\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n5\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n21\n ==== / ,_____________/\n ("o o) Oh, don\'t worry... / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n15\n ==== / ,_____________/\n ("o o) ...he\'ll be alright. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n25\n ==== / ,_____________/\n ("o o) ...he\'ll be alright. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / - -~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n10\n ==== / ,_____________/\n ("o o) ...he\'ll be alright. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n10\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n16\n ==== / ,_____________/\n ("o o) Ben? / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n4\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n20\n ==== / ,_____________/\n ("o o) Ben Kenobi? / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n3\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n32\n\n\n Tell me, young Luke,\n what brings you\n out this far?\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n5\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n Oh, this little droid!\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n32\n\n\n He claims to be the property\n of an Obi-Wan Kenobi.\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n7\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n Obi-Wan Kenobi.\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n16\n\n\n Obi-Wan?\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n7\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n31\n\n Now that\'s a name\n I\'ve not heard\n in a long time.\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n22\n\n A long time.\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n2\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n You know him?\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n3\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n21\n\n\n Of course I know him.\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n21\n\n\n He\'s me!\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n2\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n2\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n1\n ==== ==== / ,_____________/\n ("o o) ~~o o / /\n _\\ -/_ _ _\\ -/_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n7\n ==== ==== / ,_____________/\n ("o o) ~~o o / /\n _\\ -/_ _ _\\ -/_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n7\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n I think we better get indoors.\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n9\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n16\n\n\n Threepio!\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |-- )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n5\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n16\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ I must have taken\n || | | | \\\\ |oo ) a bad step.\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n12\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ I must have taken\n || | | | \\\\ ( oo| a bad step.\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n6\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ ( oo|\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n15\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ Leave me.\n || | | | \\\\ ( oo| I\'m done for!\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n11\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ Leave me.\n || | | | \\\\ |oo ) I\'m done for!\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n6\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n19\n ====\n What kind of ~~o o __\n talk is that! _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n7\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n21\n\n\n___\n \\\n \\____\n \\__\n \\ ________\n \\ =_._ / o o o \\__\n______________\\_______________====\'______|_________|__|_______\n \\\n |\n \\\n \\\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n4\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n13\n /~\\ ====\n ( oo| ~~o o You fought\n _\\=/_ _\\ -/_ in the clone wars?\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n9\n /~\\ ====\n ( oo| ~~o o You fought\n _\\=/_ _\\ -/_ in the clone wars?\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n3\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n10\n ====\n (o o") Yes.\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n12\n ====\n (o o") Yes.\n _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n6\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n19\n ====\n (o o") I was once\n _\\- /_ a Jedi Knight\n ___ / \\ / \\ the same as\n / ()\\ / \\/ \\ your father.\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n26\n ====\n (o o") I was once\n _\\- /_ a Jedi Knight\n ___ / \\ / \\ the same as\n /() \\ / \\/ \\ your father.\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n6\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n3\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n10\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n4\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n3\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n14\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n6\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| ===(= | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n25\n ====\n (o o") I have\n _\\- /_ something here\n ___ / \\ / \\ for you.\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| ===(= | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n4\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| ===(= | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n9\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n5\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || // | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n3\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || // | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ // | | | ||\n (\' |====| \')==(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n3\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ // | | | ||\n (\' |====| =)==(` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n2\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ // | | | ||\n (\' |====| =)===(` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || // | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n5\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n14\n ==== ====\n ~~o o (o o") Your father\'s\n _\\ -/_ _\\- /_ lightsabre!\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n12\n ==== ====\n ~~o o (o o") Your father\'s\n _\\ o/_ _\\- /_ lightsabre!\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ o/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n ====\n ~~o o\n _\\ o/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o This is the\n _\\ o/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n4\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===***\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===******\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*********\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n7\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n5\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n10\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====|=)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n3\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n3\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====|=)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n14\n ====\n ~~o o An elegant\n _\\ -/_ weapon for a\n / \\ / \\ more civilised\n //| | |\\\\ day.\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o An elegant\n _\\ -/_ weapon for a\n / \\ / \\ more civilised\n //| | |\\\\ day.\n || | | | ||\n || | | | ||\n (\' |====|=)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n5\n ====\n ~~o o An elegant\n _\\ -/_ weapon for a\n / \\ / \\ more civilised\n //| | |\\\\ day.\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n2\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===**********\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*******\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===****\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n5\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n20\n ====\n ~~o o How did my\n _\\ -/_ father die?\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n2\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o A young Jedi called\n _\\ -/_ Darth Vader, who was a\n / \\ / \\ pupil of mine until\n //| | |\\\\ he turned to evil,...\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o ...helped the Empire\n _\\ -/_ hunt down and destroy\n / \\ / \\ the Jedi Knights.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n45\n ====\n ~~o o He betrayed and\n _\\ -/_ murdered your father.\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o Vader was seduced\n _\\ -/_ by the Dark side of\n / \\ / \\ the Force.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n36\n ====\n ~~o o The Force?\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o The Force is what\n _\\ -/_ gives the Jedi\n / \\ / \\ his power.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n51\n ====\n ~~o o It\'s an energy field\n _\\ -/_ created by all\n / \\ / \\ living things.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o It surrounds us and\n _\\ -/_ penetrates us.\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o It binds the galaxy\n _\\ -/_ together.\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n9\n Now let\'s see if we ====\n can\'t figure out what (o o")\n you are. _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n21\n Now let\'s see if we ====\n can\'t figure out what (o o")\n you are. _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n2\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n2\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n9\n ====\n I saw part (o o")\n of the message... _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n11\n ====\n I saw part (o o")\n of the message... _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n ,@ | | === | | || | | | ||\n /=- |_| O |_| (\' | | | `)\n || || O || | | |\n || ||__*__|| | |\\ |\n --~~--- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n30\n I seem to have ====\n found it! (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n ,@ | | === | | || | | | ||\n /=- |_| O |_| (\' | | | `)\n || || O || | | |\n || ||__*__|| | |\\ |\n --~~--- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n4\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n ,@ | | === | | || | | | ||\n /=- |_| O |_| (\' | | | `)\n || || O || | | |\n || ||__*__|| | |\\ |\n --~~--- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n69\n\n General Kenobi. Years ago you\n served my father in the Clone\n wars. Now he begs you to help\n him in his struggle against\n the Empire.\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n59\n\n I have placed information vital\n to the survival of the Rebellion\n into the memory systems of this\n R2 unit.\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n55\n\n You must see this droid safely\n delivered to him on Alderaan.\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n36\n\n Help me Obi-Wan Kenobi!\n You\'re my only hope!\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n5\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ~~\n ~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n -------\n || ||\n______________||___||______________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n28\n ==== ====\n ~~o o (o o") You must learn\n _\\ -/_ _\\- /_ the ways of the\n / \\ / \\ / \\ / \\ Force...\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n40\n ==== ====\n ~~o o (o o") ...if you are\n _\\ -/_ _\\- /_ to come with me\n / \\ / \\ / \\ / \\ to Alderaan.\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n . .\n . . .\n . . .\n. . .\n . . . .\n . .\n . . .\n . . .\n . .\n . . . .\n . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . .\n . . . .\n . .\n . . .\n . . .\n . .\n . . . .\n . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . .\n . . . .\n . .\n . . .\n . . .\n . .\n . . . .\n . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . .\n . . . .\n . .\n . . .\n . .\n . .\n . . . .\n. . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n. . . .\n . . . .\n . .\n . . .\n . .\n . .\n . . . .\n . . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . . .\n . . . .\n: . .\n| . . .\n| . .\n: . .\n . . . .\n . . .\n. . . . .\n . . .\n2\n .\n . . .\n . .\n . . . .\n\\ . . .\n.: . .\n_| . . .\n.| . .\n : . .\n/ . . . .\n . . .\n . . . .\n . . .\n2\n .\n . . .\n . .\n\\ . . . .\n:\\ . . .\n..: . .\n__| . . .\n..| . .\n: : . .\n./ . . . .\n/ . . .\n . . . .\n . . .\n2\n .\n . . .\n\\ . .\n.\\ . . . .\n :\\ . . .\n...: . .\n___| . . .\n...| . .\n : : . .\n../ . . . .\n / . . .\n/ . . . .\n . . .\n2\n .\n. . . .\n.\\ . .\n .\\ . . . .\n| :\\ . . .\n....: . .\n____| . . .\n....| . .\n : : . .\n.../ . . .\n / . . .\n./ . . . .\n . . .\n2\n .\n-. . . .\n .\\ . .\n\\ .\\ . . . .\n | :\\ . . .\n/....: . .\n_____| . . .\n.....| . .\n : : . .\n..../ . . .\n. / . . .\n_./ . . . .\n . . .\n2\n .\n\'-. . . .\n_ .\\ . .\n \\ .\\ . . . .\n) | :\\ . . .\n_/....: .\n______| . . .\n......| . .\n: : : . .\n...../ . . .\n . / . . .\n._./ . . . .\n- . . .\n2\n_ .\n.\'-. . . .\n__ .\\ . .\n \\ .\\ . . . .\n() | :\\ . . .\n__/....: .\n_______| . . .\n.......| . .\n : : : . .\n....../ . . .\n . / . . .\n.._./ . . . .\n.- . . .\n2\n__ .\n..\'-. . . .\n.__ .\\ . .\n/ \\ .\\ . . . .\n () | :\\ . . .\n\\__/....: .\n________| . . .\n........| . .\n : : : . .\n......./ . . .\n. . / . . .\n..._./ . . .\n..- . . .\n2\n-__ .\n...\'-. . . .\n .__ .\\ . .\n./ \\ .\\ . . . .\n| () | :\\ . . .\n.\\__/....: .\n_________| . . .\n.........| . .\n : : : . .\n......../ . . .\n . . / . . .\n...._./ . . .\n_..- . . .\n2\n--__ .\n:...\'-. . . .\n: .__ .\\ .\n../ \\ .\\ . . . .\n:| () | :\\ . . .\n..\\__/....: .\n__________| . . .\n..........| . .\n: : : : . .\n........./ . . .\n: . . / . . .\n....._./ . . .\n__..- . . .\n2\n---__ .\n.:...\'-. . . .\n : .__ .\\ .\n.../ \\ .\\ . . . .\n :| () | :\\ . . .\n...\\__/....: .\n___________| . . .\n...........| . .\n : : : : . .\n........../ . . .\n : . . / . . .\n......_./ . . .\n___..- . . .\n2\n_---__ .\n..:...\'-. . . .\n. : .__ .\\ .\n..../ \\ .\\ . . . .\n :| () | :\\ . . .\n....\\__/....: .\n____________| . . .\n............| .\n : : : : . .\n.........../ . . .\n. : . . / . . .\n......._./ . . .\n.___..- . . .\n2\n__---__ .\n...:...\'-. . . .\n . : .__ .\\ .\n...../ \\ .\\ . . . .\n :| () | :\\ . . .\n.....\\__/....: .\n_____________| . . .\n.............| .\n : : : : . .\n............/ . . .\n . : . . / . . .\n........_./ . . .\n..___..- . . .\n2\n __---__ .\n\'...:...\'-. . . .\n . : .__ .\\ .\n....../ \\ .\\ . . . .\n: :| () | :\\ . .\n......\\__/....: .\n______________| . . .\n..............| .\n: : : : : . .\n............./ . . .\n . : . . / . . .\n........._./ . . .\n-..___..- . .\n2\n __---__ .\n-\'...:...\'-. . .\n. . : .__ .\\ .\n......./ \\ .\\ . . . .\n : :| () | :\\ . .\n.......\\__/....: .\n_______________| . . .\n...............| .\n : : : : : . .\n............../ . . .\n. . : . . / . . .\n_........._./ . . .\n -..___..- . .\n2\n __---__ .\n.-\'...:...\'-. . .\n . . : .__ .\\ .\n......../ \\ .\\ . . . .\n : :| () | :\\ . .\n........\\__/....: .\n________________| . . .\n................| .\n : : : : : . .\n.............../ . . .\n . . : . . / . . .\n._........._./ . . .\n -..___..- . .\n2\n __---__ .\n .-\'...:...\'-. . .\n/ . . : .__ .\\ .\n........./ \\ .\\ . . . .\n: : :| () | :\\ . .\n.........\\__/....: .\n_________________| . . .\n.................| .\n: : : : : : . .\n................/ . . .\n . . : . . / . . .\n\\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n .-\'...:...\'-. . .\n / . . : .__ .\\ .\n/........./ \\ .\\ . . . .\n : : :| () | :\\ . .\n..........\\__/....: .\n__________________| . . .\n..................| .\n : : : : : : . .\n................./ . . .\n\\ . . : . . / . . .\n \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . . .\n/ : : :| () | :\\ . .\n...........\\__/....: .\n___________________| . . .\n...................| .\n : : : : : : . .\n\\................./ . .\n \\ . . : . . / . . .\n \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n. .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . . .\n / : : :| () | :\\ . .\n:...........\\__/....: .\n|___________________| . . .\n|...................| .\n: : : : : : : . .\n \\................./ . .\n \\ . . : . . / . . .\n \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . . .\n |...................| .\n : : : : : : : . .\n \\................./ . .\n \\ . . : . . / . . .\n. \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n. \\................./ . .\n \\ . . : . . / . . .\n . \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . . .\n . \\._........._./ . . .\n -..___..- . .\n2\n. __---__\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n. /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n2\n . __---__\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n2\n . __---__\n. . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n. : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n2\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n. |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n12\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n39\n This station is now /~~\\\n the ultimate power |<><>|\n in the universe. /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n31\n I suggest /~~\\\n we use it! |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n29\n The ability to destroy /~~\\\n a planet is insignificant... |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n4\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n13\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o | o o //|[ ] \\\\\n _\\ -/_ _\\ -/_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n10\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n11\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n9\n Don\'t try to frighten /~~\\\n us with your sorcerer\'s |<><>|\n ways, Lord Vader... /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n21\n Don\'t try to frighten /~~\\\n us with your sorcerer\'s |<><>|\n ways, Lord Vader... /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n10\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( O O o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - | o o \\\\//|[ ] \\\\\n _\\ o/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - | o o \\\\//|[ ] \\\\\n _\\ o/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - | o o \\\\//|[ ] \\\\\n _\\ o/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n8\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n5\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n11\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n23\n I find your lack of /~~\\\n faith disturbing. |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n16\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ Vader, ==== # /\\___/\\\n ( x x release him! | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n7\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ Vader, ==== # /\\___/\\\n ( o o release him! | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n10\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ Vader, ==== # /\\___/\\\n ( o o release him! | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n10\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n1\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'() ") /"\'==\'"\\ \\\\ | |//\n | | \\\\// | | ::: | \\#|====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n3\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ o/_ _\\- /_ // |[_] |\\\\\n /"\'() ") /"\'==\'"\\ \\\\ | |//\n | | \\\\// | | ::: | \\#|====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n4\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ o/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n11\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n13\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) o o~~ | | | *| .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) o o~~ | | | *| .##\n _\\ -/_ _\\- /_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) o o~~ | | | * .##\n _\\ -/_ _\\- /_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) o o~~ | | | * .##\n _\\ -/_ _\\- /_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) o o~~ | | | *| .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n29\n\n It looks like the\n Sand People did this.\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n29\n\n They didn\'t. But we are\n meant to think they did.\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n28\n\n Only Imperial stormtroopers\n are so precise.\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n30\n\n If they traced the\n robots here that would\n lead them...\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n15\n\n\n ...home!\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n2\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= ++ |______#_/\n____________\'====_________||_____ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + |______#_/\n____________\'====_________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= ++ |______#_/\n____________\'====________||______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_______|_|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====______|__|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_____|___|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====____|____|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====___|_____|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====__|______|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_|_______|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._=+ + |______#_/\n____________\'====|________|______ooo__ooo__________________________\n\n16\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n____________\'====_________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n___________\'====__________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n__________\'====___________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n_________\'====____________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n________\'====_____________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n______\'====_______________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n____\'====_________________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n__\'====___________________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n\'====_____________________|______ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n+_= + |______#_/\n===_______________________|______ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n= + |______#_/\n=_________________________|______ooo__ooo__________________________\n\n8\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n + |______#_/\n__________________________|______ooo__ooo__________________________\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n\'____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n+_ __/ o\\*/o o \\ .||.\n==\'__________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n=_+_ __/ o\\*/o o \\ .||.\n====\'________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n__====\'______________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n____====\'____________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n______====\'__________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_______====\'_________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n________====\'________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________====\'_______________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n__________====\'______________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n___________====\'_____________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n____________====\'____________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_____________====\'___________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n______________====\'__________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_______________====\'_________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n________________====\'________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________====\'_______________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n__________________====\'______________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n___________________====\'_____________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n____________________====\'____________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_____________________====\'___________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n______________________====\'__________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_______________________====\'_________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n________________________====\'________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . |\n . : : : : : : : . |\n . \\................./ . . |\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . ./\n |...................| . |\n . : : : : : : : . |-\n . \\................./ . . |\n \\ . . : . . / . . \\\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . _\n . |___________________| . /\n |...................| . | \\\n . : : : : : : : . |-{\n . \\................./ . . | /\n \\ . . : . . / . . \\_\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . __\n . |___________________| . /\n |...................| . | \\_\n . : : : : : : : . |-{\n . \\................./ . . | /~\n \\ . . : . . / . .\\__\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . /\n |...................| . | \\_/\n . : : : : : : : . |-{ }\n . \\................./ . . | /~\\\n \\ . . : . . / . \\___\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\\n |...................| . | \\_/\n . : : : : : : : . |-{ }-\n . \\................./ . . | /~\\\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\.\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/.\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : .|-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . __\n . |___________________| . / \\ .\n |...................| . |_\\/_|\n . : : : : : : : | /\\ |\n . \\................./ . . \\__/\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . __\n . |___________________| . / \\ .\n |...................| . |_\\/_|\n . : : : : : : : | /\\ |\n . \\................./ . . \\__/\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . -- .\n |...................| . |\\/|\n . : : : : : : : |/\\| .\n . \\................./ . . --\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . -- .\n |...................| . |\\/|\n . : : : : : : : |/\\| .\n . \\................./ . . --\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . []\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . []\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . "\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . "\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . \'\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\'\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \'\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \'.\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................|\' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n5\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~\\\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n16\n / \\ ===,\n And now your | | @o o@)\n highness... | | \\- /\n | | /~~ ~\\\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n And now your | | @o o@)\n highness... | | \\- /\n | | /~~ ~\\\\\n | \'| / ( ) \\\n | =| /_/\\ /\\_|\n | \'| \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n And now your | | @o o@)\n highness... | | \\- /\n | /| /~~ ~\\\\\n | \'-| / ( ) \\\n | ==| /_/\\ /\\_|\n | \' | \\\\ \\ // ||\n | \\| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | | \\- /\n your hidden | / | /~~ ~\\\\\n Rebel base. | \'--| / ( ) \\\n | ===| /_/\\ /\\_|\n | \' o| \\\\ \\ // ||\n | \\ | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | _| \\- /\n your hidden | / | /~~ ~\\\\\n Rebel base. | \'--|| / ( ) \\\n | ====| /_/\\ /\\_|\n | \' o | \\\\ \\ // ||\n | \\ _| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __| \\- /\n your hidden | / _| /~~ ~\\\\\n Rebel base. | \'--| | / ( ) \\\n | =====| /_/\\ /\\_|\n | \' o | \\\\ \\ // ||\n | \\ __| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\- /\n your hidden | / __| /~~ ~\\\\\n Rebel base. | \'--| "| / ( ) \\\n | ======| /_/\\ /\\_|\n | \' o || \\\\ \\ // ||\n | \\ __ | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\- /\n your hidden | / __\\| /~~ ~\\\\\n Rebel base. | \'--| ""| / ( ) \\\n | =======| /_/\\ /\\_|\n | \' o |_| \\\\ \\ // ||\n | \\ __ /| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\'| / ( ) \\\n | ========| /_/\\ /\\_|\n | \' o |_\'| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=-| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n1\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=* | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n1\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== * | /_/\\ /\\_|\n | \' o |_\'+***| \\\\ \\ // ||\n | \\ __ / * | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n1\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=* | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n17\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n3\n / \\ ===,\n | | @o o@)\n | __ | \\o /\n | / __\\ | /~~ ~\\\\\n | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n6\n / \\ ===,\n | | @o o@)\n | __ | \\- /\n | / __\\ | /~~ ~\\\\\n | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n15\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n + |______#_/ . +\n__________________________|______ooo__ooo_____<^"..|_|_____________\n ~~\'`\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n + |______#_/ . +\n__________________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n + |______#_/ . +\n\'_________________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n+_ + |______#_/ . +\n==\'_______________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n=_+_ + |______#_/ . +\n====\'_____________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n__====\'___________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n____====\'_________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n______====\'_______________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_______====\'______________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n________====\'_____________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_________====\'____________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n__________====\'___________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n___________====\'__________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n____________====\'_________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_____________====\'________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n______________====\'_______|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_______________====\'______|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n________________====\'_____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n________________====\'_____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'|____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'|____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'_|___|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'_|___|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n25\n\n\n\n =_._ + + Mos Eisley Spaceport.\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n1\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n36\n\n\n You will never find a\n =_._ + + more wretched hive of\n______________====\'___|_|_ scum and villainy.\n \\\n |\n /\n /\n |\n |\n |\n |\n1\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n26\n\n\n\n =_._ + + We must be cautious.\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n4\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n\'___/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n_ |~~| | | o o o o | | O O O O |__ o o| o o\n=\'__/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n+_ |~~| | | o o o o | | O O O O |__ o o| o o\n==\'_/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n_+_ |~~| | | o o o o | | O O O O |__ o o| o o\n===\'/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n=_+_ |~~| | | o o o o | | O O O O |__ o o| o o\n====/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =_+_|~~| | | o o o o | | O O O O |__ o o| o o\n_===/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =_+|~~| | | o o o o | | O O O O |__ o o| o o\n__==/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =_|~~| | | o o o o | | O O O O |__ o o| o o\n___=/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =|~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|_ | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\\'|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|+_| | o o o o | | O O O O |__ o o| o o\n____/|[]|\\=\'___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|_+_ | o o o o | | O O O O |__ o o| o o\n____/|[]|\\==\'__|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|=_+_ | o o o o | | O O O O |__ o o| o o\n____/|[]|\\===\'_|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| =_+_ | o o o o | | O O O O |__ o o| o o\n____/|[]|\\====\'|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| =_+_| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_====|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| |=_+| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|===|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | =_| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|_==|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | =| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|__=|_________|_____|___________|__|____________|_||____\n7\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|\'____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|=\'___|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |+_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|==\'__|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |_+_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|===\'_|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |=_+_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|====\'|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =_+_| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_====|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =_+| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|__===|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =_| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|___==|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|____=|___________|__|____________|_||____\n12\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|\'___________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |=_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|=\'__________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |_=_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|==\'_________|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__=_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|===\'________|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|====\'_______|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|_====\'______|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|__====\'_____|_||____\n7\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n Let me see your\n identification.\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n26\n\n\n\n\n\n You don\'t need to\n see his identification.\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n We don\'t need to see his\n identification.\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n\n\n\n These aren\'t the\n droids you\'re looking for.\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n These aren\'t the droids\n we\'re looking for.\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n26\n\n\n\n\n\n Move along.\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n Move along! Move along!\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o | o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'_____|_|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'______||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'_______|____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|____====\'______|____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_____====\'_____|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|______====\'____|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_______====\'___|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|________====\'__|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_________====\'_|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|__________====\'|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_| o o\n____/|[]|\\_|___|_________|_____|___________|__|___________====|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________===|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_| o o\n____/|[]|\\_|___|_________|_____|___________|__|_____________==|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =| o o\n____/|[]|\\_|___|_________|_____|___________|__|______________=|____\n5\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_______________|____\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n29\n ==== ====\nI can\'t understand ~~o o (o o")\n how we got by _\\ -/_ _\\- /_\n those troops. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n2\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n8\n ==== ====\n ~~o o (o o") The Force can\n _\\ -/_ _\\- /_ have a strong\n / \\ / \\ / \\ / \\ influence...\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n17\n ==== ====\n ~~o o (o o") The Force can\n _\\ -/_ _\\- /_ have a strong\n / \\ / \\ / \\ / \\ influence...\n //| | |\\\\ / \\/ \\\n \\\\| | | || | /| | |\\ |\n \\\\ | | || || | | | ||\n )====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n19\n ==== ====\n ~~o o (o o") ...on the\n _\\ -/_ _\\- /_ weak minded.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | || | /| | |\\ |\n \\\\ | | || || | | | ||\n )====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n7\n ==== ====\n ~~o o (o o") ...on the\n _\\ -/_ _\\- /_ weak minded.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n29\n ==== ====\n Do you really ~~o o (o o")\n think we\'re _\\ -/_ _\\- /_\n going to find... / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n8\n ==== ====\n ...a pilot here ~~o o (o o")\n to take us to _\\ -/_ _\\- /_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ...a pilot here ~~o o (o o")\n to take us to _\\ -/_ _\\- /_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | || | /| | |\\ |\n \\\\ | | || || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n8\n ==== ====\n ...a pilot here ~~o o (o o")\n to take us to _\\ -/_ _\\- /_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | \\\\ | /| | |\\ |\n \\\\ | | \\\\ || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n20\n ==== ====\n ...a pilot here ~~o o ("o o)\n to take us to _\\ -/_ _\\ -/_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | \\\\ | /| | |\\ |\n \\\\ | | \\\\ || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n3\n ==== ====\n ~~o o ("o o)\n _\\ -/_ _\\ -/_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | \\\\ | /| | |\\ |\n \\\\ | | \\\\ || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ~~o o ("o o)\n _\\ -/_ _\\ -/_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n32\n ==== ====\n ~~o o ("o o) Most of the best\n _\\ -/_ _\\ -/_ freighter pilots\n / \\ / \\ / \\ / \\ can be found here.\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n6\n ==== ====\n ~~o o (o o") Most of the best\n _\\ -/_ _\\- /_ freighter pilots\n / \\ / \\ / \\ / \\ can be found here.\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n31\n ==== ====\n ~~o o (o o") Only watch your\n _\\ -/_ _\\- /_ step.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n34\n ==== ====\n ~~o o (o o") This place can\n _\\ -/_ _\\- /_ be a little rough.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n == // | |\\\\ / === \\\n || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n == // | |\\\\ / === \\\n {\\---/} || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n {\\---/} == // | |\\\\ / === \\\n {<><> } || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n {\\---/} /-===-\\ _\\!^!/_\n {<><> } == // | |\\\\ / === \\\n \\ - / || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n7\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n {<><> } /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { }\n {\\---/} \\ / | |\n {<><> } /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n {<><> } /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n6\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n---------------. \\\\ | | \\\\ .--//---|_|------.\n-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n_|___________|______[_][__]______|_____________|___________________\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n--------------. \\\\ | | \\\\ .--//---|_|------.\n. .-\' =\\)=== () \'- {} .-\'\n| | | || | | |\n| | ( )| ) | |\n| | | || | | |\n| | | || | | |\n|___________|______[_][__]______|_____________|___________________/\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n-------------. \\\\ | | \\\\ .--//---|_|------. (\n .-\' =\\)=== () \'- {} .-\'\n | | || | | |\n | ( )| ) | | (\n | | || | | | |\n | | || | | | |\n___________|______[_][__]______|_____________|___________________/_\n2\n / _\\ /\\_/\\\n | (__) { . . }\n{\\---/} \\ / | |\n{ <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | || /\n------------. \\\\ | | \\\\ .--//---|_|------. (\n .-\' =\\)=== () \'- {} .-\' \\\n | | || | | | -\n | ( )| ) | | (\n | | || | | | |_\n | | || | | | |\n__________|______[_][__]______|_____________|___________________/__\n2\n / _\\ /\\_/\\\n | (__) { . . }\n\\---/} \\ / | |\n<><> } /-===-\\ _\\!^!/_\n\\ - / == // | |\\\\ / === \\ _\n | | || \\\\ | | \\\\ //| | | || //\n-----------. \\\\ | | \\\\ .--//---|_|------. (\n .-\' =\\)=== () \'- {} .-\' \\\n | | || | | | -=\n | ( )| ) | | (\n | | || | | | |__\n | | || | | | |\n_________|______[_][__]______|_____________|___________________/___\n2\n / _\\ /\\_/\\\n | (__) { . . }\n---/} \\ / | |\n><> } /-===-\\ _\\!^!/_\n - / == // | |\\\\ / === \\ __\n| | || \\\\ | |// //| | | || //\\\n----------. \\\\ | // .--//---|_|------. (\n .-\' =\\)==) \'- {} .-\' \\\n | | || | | | -==\n | ( )| ) | | ( _\n | | || | | | |___\n | | || | | | |\n________|______[_][__]______|_____________|___________________/____\n2\n / _\\ /\\_/\\\n | (__) { }\n--/} \\ / | |\n<> } /-===-\\ _\\!^!/_\n- / == // | |\\\\ / === \\ __\n | || \\\\ | |// //| | | || //\\\\\n---------. \\\\ | // .--//---|_|------. ( O\n .-\' =\\)==) \'- {} .-\' \\ /\n | | || | | | -==-\n | ( )| ) | | ( __\n | | || | | | |____\n | | || | | | |\n_______|______[_][__]______|_____________|___________________/_____\n2\n / __\\ /\\_/\\\n | (___) { . . }\n-/} \\ / | |\n> } /-===-\\ _\\!^!/_\n / == // | |\\\\ / === \\ __\n| || \\\\ | |// //| | | || //\\\\\n--------. \\\\ | // .--//---|_|------. ( O!\n .-\' =\\)==) \'- {} .-\' \\ /\'\n | | || | | | -==-/\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n______|______[_][__]______|_____________|___________________/______\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n/} \\ / | |\n } /-===-\\ _\\!^!/_\n/ == // | |\\\\ / === \\ __\n || \\\\ | |// //| | | || //\\\\\n-------. \\\\ | // .--//---|_|------. ( O!\n .-\' =\\)==) \'- {} .-\' \\ /\'/\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n_____|______[_][__]______|_____________|___________________/______\\\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n} \\ / | |\n} /-===-\\ _\\!^!/_\n == // | |\\\\ ( === \\ __\n || \\\\ | |// \\\\/{ } || //\\\\\n------. \\\\ | // .-----\\/|_|------. ( O!\n .-\' =\\)==) \'- .-\' \\ /\'/(\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n____|______[_][__]______|_____________|___________________/______\\_\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n \\ / | |\n /-===-\\ _\\===/_\n == // | |\\\\ ( { } \\ __\n || \\\\ | |// \\\\//_| || //\\\\\n-----. \\\\ | // .-----\\/---------. ( O!\n .-\' =\\)==) \'- .-\' \\ /\'/()\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n___|______[_][__]______|_____________|___________________/______\\__\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n \\ / | |\n /-===-\\ _\\===/_\n== // | |\\\\ ( { } \\ __\n|| \\\\ | |// \\\\//_| || //\\\\\n----. \\\\ | // .-----\\/---------. ( O! .\n .-\' =\\)==) \'- .-\' \\ /\'/()\'\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n__|______[_][__]______|_____________|___________________/______\\___\n2\n / __\\ /\\_/\\\n | (___| { }\n \\ / | |\n /-===-\\ _\\===/_\n= // | |\\\\ ( { } \\ __\n| \\\\ | |// \\\\//_| || //\\\\\n---. \\\\ | // .-----\\/---------. ( O! .-\n .-\' =\\)==) \'- .-\' \\ /\'/()\'-\n | | || | | | -==-// |\n | ( )| ) | | ( __/ |\n | | || | | | |____| |\n | | || | | | | | |\n_|______[_][__]______|_____________|___________________/______\\___|\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\===/_\n // | |\\\\ ( { } \\ __\n \\\\ | |// \\\\//_| || //\\\\\n--. \\\\ | // .-----\\/---------. ( O! .--\n.-\' =\\)==) \'- .-\' \\ /\'/()\'--\n| | || | | | -==-// |\n| ( )| ) | | ( __/ |\n| | || | | | |____| |\n| | || | | | | | |\n|______[_][__]______|_____________|___________________/______\\___|_\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __\n \\\\ | |// \\\\/{ } || //\\\\\n-. \\\\ | // .-----\\/|_|------. ( O! .---\n-\' =\\)==) \'- .-\' \\ /\'/()\'---\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n______[_][__]______|_____________|___________________/______\\___|__\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __\n \\\\ | |// \\\\/{ } || //\\\\\n. \\\\ | // .-----\\/|_|------. ( O! .----\n\' =\\)==) \'- .-\' \\ /\'/()\'----\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n_____[_][__]______|_____________|___________________/______\\___|___\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __\n \\\\ | |// \\\\ | | || //\\\\\n \\\\ | // .-----\\\\|_|------. ( O! .-----\n =\\)==) \'- \\{} .-\' \\ /\'/()\'-----\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n____[_][__]______|_____________|___________________/______\\___|____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ =\n \\\\ | |// \\\\ | | || //\\\\ (\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ (|\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==/\n \\\\ | |// \\\\ | | || //\\\\ (|/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { }\n \\ / | |\n /-===-\\ _\\!^!/_ /\n // | |\\\\ ( === \\ __ ==//\n \\\\ | |// \\\\ | | || //\\\\ (|/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | | /\n /-===-\\ _\\!^!/_ //\n // | |\\\\ ( === \\ __ ==//\n \\\\ | |// \\\\ | | || //\\\\ (|/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_ /\n // | |\\\\ ( === \\ __ == //\n \\\\ | |// \\\\ | | || //\\\\ ||)/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ == /\n \\\\ | |// \\\\ | | || //\\\\ ||()/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ || ()\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ || (\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n4\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ ||\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n2\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ o/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n |oo ) ~~o o\n _\\=/_ _\\ o/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n5\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n6\n /~\\ ====\n |oo ) ~~o o\n _\\=/_ _\\ o/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n |oo ) ~~o o\n _\\=/_ _\\ -/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n5\n /~\\ ====\n |oo ) ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n8\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n6\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n ( oo| ~~o o Your droids!\n _\\=/_ _\\ -/_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n14\n /~\\ ====\n ( oo| ~~o o Your droids!\n _\\=/_ _\\ -/_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n11\n /~\\ ====\n ( oo| ~~o o Your droids!\n _\\=/_ _\\ -/_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n4\n /~\\ ====\n ( oo| o o~~ Your droids!\n _\\=/_ _\\- /_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n5\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n19\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n7\n /~\\ ...out by ====\n ( oo| the speeder. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n20\n /~\\ ...out by ====\n ( oo| the speeder. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ...out by ====\n ( oo| the speeder. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n16\n """" / \\ ====\n ( o,o) ( (O ~~~~\n _\\ =/_ ~# | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """"*******. ====\n No blasters! ( o,o)*******. (o o")\n No blasters! _\\ =/_*******. _\\- /_\n / \\--/ \\*******. / \\ / \\\n //| | |\\\\******. / \\/ \\\n-------------------\\\\| | |-\\\\****\\--/ /| | |\\ |------------------\n \\\\ | | \\o===\\\\// | | | ||\n )===== #\' (> | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """"*********. ====\n No blasters! ( O,O)********. (o o")\n No blasters! _\\ =/**********. _\\- /_\n / \\--***********. / \\ / \\\n //| | **********. / \\/ \\\n-------------------\\\\| | |**********/ /| | |\\ |------------------\n \\\\ | |``*****\\\\// | | | ||\n )===== ```` (> | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """"*******. ====\n No blasters! ( O,O)*******. (o o")\n No blasters! _\\ o/_*******. _\\- /_\n / \\--/()*******. / \\ / \\\n //| | | .******. / \\/ \\\n-------------------\\\\| | |-\\\\****\\--/ /| | |\\ |------------------\n \\\\ | | \\\\ \\\\// | | | ||\n )===== o=== (> | | | `)\n | || | #\' | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" `*. ====\n No blasters! ( O,O) `*. (o o")\n No blasters! _\\ o/_ `*. _\\- /_\n / \\--/() `*. / \\ / \\\n //| | | `*. / \\/ \\\n-------------------\\\\| | |-----`*\\--/ /| | |\\ |------------------\n \\\\ | | \\\\ \\\\// | | | ||\n )===== \\\\ (> | | | `)\n | || | o=== | | |\n | )| ) #\' | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n No blasters! ( O,O) (o o")\n No blasters! _\\ o/_ *. _\\- /_\n / \\--/() `*. / \\ / \\\n //| | | `*. / \\/ \\\n-------------------\\\\| | |-----`*\\--/ /| | |\\ |------------------\n \\\\ | | \\\\ \\\\// | | | ||\n )===== \\\\ (> | | | `)\n | || | o=== | | |\n | )| ) #\' | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n No blasters! ( O,O) (o o")\n No blasters! _\\ o/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | *. / \\/ \\\n-------------------\\\\| | |-----`*\\--/ /| | |\\ |------------------\n \\\\ | | \\\\// | | | ||\n )===== \\\\ (> | | | `)\n | || | o=== | | |\n | )| ) #\' | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n No blasters! ( o,o) (o o")\n No blasters! _\\ o/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |------o\\--/ /| | |\\ |------------------\n \\\\ | | \\\\// | | | ||\n )===== (> | | | `)\n | || | \\\\ | | |\n | )| ) o=== | |\\ |\n | || | #\' / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n ( o,o) (o o")\n _\\ o/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) \\\\ | |\\ |\n | || | o=== / || \\\n |_||_| #\' / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n ( o,o) (o o")\n _\\ =/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | \\\\ / || \\\n |_||_| o=== / ||_|\\\n_____________________[_][__\\__#\'_____/____|[_]_\\___________________\n1\n """" ====\n ( o,o) (o o")\n _\\ =/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| \\\\ / ||_|\\\n_____________________[_][__\\__#\'==___/____|[_]_\\___________________\n7\n """" ====\n ( o,o) (o o")\n _\\ =/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_=#\'==___/____|[_]_\\___________________\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== ==== ####\n ~~o o ("o o) {o o"}\n _\\ -/_ _\\ -/_ {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n10\n ==== ==== ####\n ~~o o ("o o) Chewbacca here {o o"}\n _\\ -/_ _\\ -/_ is first mate on {= }\n / \\ / \\ / \\ / \\ a ship... {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n23\n ==== ==== ####\n ~~o o ("o o) Chewbacca here {o o"}\n _\\ -/_ _\\ -/_ is first mate on {= }\n / \\ / \\ / \\ / \\ a ship... {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ \\ {} {// } {}\n \\\\ | // || | | | \\ \\ {} // } {}\n )====) (\' | | | `() {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n11\n ==== ==== ####\n ~~o o ("o o) ...that might {o o"}\n _\\ -/_ _\\ -/_ suit us. {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ \\ {} {// } {}\n \\\\ | // || | | | \\ \\ {} // } {}\n )====) (\' | | | `() {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n10\n ==== ==== ####\n ~~o o ("o o) ...that might {o o"}\n _\\ -/_ _\\ -/_ suit us. {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n6\n ==== ==== ####\n ~~o o ("o o) {o o"}\n _\\ -/_ _\\ -/_ {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n35\n Han Solo. I\'m captain\n of the Millennium Falcon.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n2\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n35\n Chewie here tells me\n you\'re looking for passage\n to the Alderaan system.\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n32\n Yes, indeed.\n If it\'s a fast ship.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n Yes, indeed.\n If it\'s a fast ship.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n12\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n4\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n13\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n2\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ -\\- /-\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n3\n She\'s fast enough for\n you, old man.\n\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ -\\- /-\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n2\n She\'s fast enough for\n you, old man.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ -\\- /-\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n27\n She\'s fast enough for\n you, old man.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n30\n Docking bay\n ninety-four.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n29\n\n This could really\n save my neck.\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n\n\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n10\n\n Get back to the ship\n and get her ready.\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n Get back to the ship\n and get her ready.\n ####\n {"o o} ===-\n { =} o o""\n {~~ //~} _\\- /_\n {{~{ //}~}} /| || |\\\n {} {// } {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n Get back to the ship\n #### and get her ready.\n {"o o}\n { =} ===-\n {~~ //~} o o""\n {{~{ //}~}} _\\- /_\n {} {// } {} /| || |\\\n {} // } {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n #### Get back to the ship\n {"o o} and get her ready.\n { =}\n {~~ //~} ===-\n {{~{ //}~}} o o""\n {} {// } {} _\\- /_\n {} // } {} /| || |\\\n {} H{{}}} {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n4\n ####\n {"o o} Get back to the ship\n { =} and get her ready.\n {~~ //~}\n {{~{ //}~}} ===-\n {{~{// } }} o o""\n {} // } {} _\\- /_\n {} H{{}}} {} /| || |\\\n {} H"||"} {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n3\n ####\n {"o o}\n { =}\n {~~ //~}\n {{~{ //}~}} ===-\n {{~{// } }} o o""\n {} // } {} _\\- /_\n {} H{{}}} {} /| || |\\\n {} H"||"} {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n31\n -=== `"\',\n ""o o O O|) Going somewhere,\n _\\ -/_ _\\o/ _ Solo?\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n30\n -=== `"\',\n Yes Greedo! ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n30\n -=== `"\',\n I was just ""o o O O|)\n going to see _\\ -/_ _\\o/ _\n your boss. /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n31\n -=== `"\',\n Tell Jabba ""o o O O|)\n I have his _\\ -/_ _\\o/ _\n money. /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n31\n -=== `"\',\n ""o o O O|) He may only take\n _\\ -/_ _\\o/ _ your ship.\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n32\n -=== `"\',\n Over my dead ""o o O O|)\n body! _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n30\n -=== `"\',\n ""o o O O|) I\'ve been looking\n _\\ -/_ _\\o/ _ forward to this\n /| || |\\ /|\\ / |\\ for a long time!\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n26\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n \\\\| || | \\\\ // | | | ||\n \\o===\\| \\\\ -==# | | | ||\n |#\'==| \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n || || |\\ /|\\ / |\\\n \\\\ || |\\\\ //| | |\\\\\n \\\\o=== \\\\ // | | | ||\n |\\(#\'| \\\\ -==# | | | ||\n |====| \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n || || |\\ /|\\ / |\\\n \\\\ || |\\\\ //| | |\\\\\n \\\\o===*** // | | | ||\n |\\(#\'| \\\\ -==# | | | ||\n |====| \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n || || |* /|\\ / |\\\n \\\\ || *** //| | |\\\\\n \\\\o=*********** // | | | ||\n |\\(#\'***\\\\ -==# | | | ||\n |====|* \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_* _\\o/ _\n || || *** /|\\ / |\\\n \\\\ ||***** //| | |\\\\\n \\\\o******************// | | | ||\n |\\(#*****\\ -==# | | | ||\n |====*** \') \'\\ |====| /#\n |/|| |* | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n || || |* /|\\ / |\\\n \\\\ || *** //| | |\\\\\n \\\\o=*********************** | ||\n |\\(#\'***\\\\ -==# | |" | ||\n |====|* \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\O/ _\n || || |\\ /|\\ / |\\\n \\\\ || |*\\ //| *. |\\\\\n \\\\o==*********************** | ||\n |\\(#\'|* \\\\ -==# |\'* \'| ||\n |====| \') \'\\ |====| /#\n |/|| | | ||"| "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\O/ _\n || || |\\ /|* / .\\\n \\\\ || |\\\\ //|*** |\\\\\n \\\\o=== \\\\ *****************| ||\n |\\(#\'| \\\\ -==# **** | ||\n |====| \') \'\\ .|====|\'/#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |"\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o X X|)\n _\\ -/_ _\\** _ \'\n || || |\\ /***** \\\n \\\\ || |\\\\ /*******\\\\\n \\\\o=== \\\\ ***********| ||\n |\\(#\'| \\\\ -==# ******* ||\n |====| \') \'\\ *****| /#\n |/|| | |*** | "\n ( )( ) \' | || | \'\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_"___________________\n1\n -=== `"\',\n ""o o ***** \'\n _\\ -/_ ********\n || || |\\ *********\n \\\\ || |\\\\ **********\n \\\\o=== \\\\ *********||\n |\\(#\'| \\\\ -==#*********||\n |====| \') \'\\ ********/#\n |/|| | |***** "\n ( )( ) | || |\n |-||-| \' | || | \'\n | || | | || | "\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `**,\n ""o o *****\n _\\ -/_ ******** \'\n || || |\\ *********\n \\\\ || |\\\\ **********\n \\\\o=== \\\\ ***********|\n |\\(#\'| \\\\ -==#**********|\n |====| \') \'\\ *********#\n |/|| | |****** "\n ( )( ) | |**|\n |-||-| | || |\n | || | \' | || | \'\n________________[_][__\\________________/__)(_)______"______________\n1\n -=== `**,\n ""o o *****\n _\\ -/_ ********\n || || |\\ *********\n \\\\ || |\\\\ ********** \'\n \\\\o=== \\\\ ***********|\n |\\(#\'| \\\\ -==#**********|\n |====| \') \'\\ *********#\n |/|| | |****** "\n ( )( ) | |**|\n |-||-| | || |\n | || | | || |\n________________[_][__\\_________\'______/__)(_)_______"\'____________\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | :/----I-----\n__\\|________\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|\\ \\ |-O-| | | |\n | || \\ | \\_/___|_________|__|\n | | \\ | :/----I-----\n__\\|________\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|+ \\ |-O-| | | |\n | ||+| \\ | \\_/___|_________|__|\n | | | \\ | :/----I-----\n__\\|________\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / + \\ |-O-| | | |\n | ||+|+\\ | \\_/___|_________|__|\n | | |+| \\ | :/----I-----\n__\\|__|_____\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / + \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | + + +\\ | :/----I-----\n__\\|_|_|_|__\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / + \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | + + + | :/----I-----\n__\\|__|_|_|_\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | + \\ | \\_/___|_________|__|\n | | ||+ +\\+ | :/----I-----\n__\\|___|_|_|\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + + + +| :/----I-----\n__\\|_||_|_|_||________________________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + +\\+ + :/----I-----\n__\\|__||_|_|_|________________________________________/_____===____\n1\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + +\\+ + :/----I-----\n__\\|__||_|_|_|________________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + + +|+ :/----I-----\n__\\|__|_|_|_|||_______________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | +\\+ + + :/----I-----\n__\\|___|_|_|_|_|______________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + +|+ + :/----I-----\n__\\|____|_|_|||_|_____________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\+ + + + :/----I-----\n__\\|_____|_|_|_|_|____________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ +|+ + + :/----I-----\n__\\|______|_|||_|_|___________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ + + + + :/----I-----\n__\\|_______|_|_|_|_|__________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ |+ + + + :/----I-----\n__\\|________|_|_|_|_|_________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ \' + + + + :/----I-----\n__\\|________\\|_|_|_|_|________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\||_|_|_|_|_______________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_|_|_|_|_|______________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|__|_|_|_|_|_____________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|___|_|_|_|_|____________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|____|_|_|_|_|___________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_____|_|_|_|_|__________________________/_____===____\n1\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|______|_|_|_|_|_________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + |/----I-----\n__\\|________\\|______|_|_|_|_|_________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + |/----I-----\n__\\|________\\|_______|_|_|_|_|________________________/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + |/----I-----\n__\\|________\\|_______|_|_|_|_|________________________/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|________|_|_|_|_|______________________|/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________|_|_|_|_|_____________________|/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________|_|_|_|_|____________________|_/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|__________|_|_|_|_|___________________|_/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|___________|_|_|_|_|_________________|__/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|____________|_|_|_|_|________________|__/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|____________|_|_|_|_|_______________|___/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_____________|_|_|_|_|______________|___/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________|_|_|_|_|____________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_______________|_|_|_|_|___________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|________________|_|_|_|_|__________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________________|_|_|_|_|_________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|__________________|_|_|_|_|________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|___________________|_|_|_|_|_______|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|____________________|_|_|_|_|______|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_____________________|_|_|_|_|_____|____/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________________|_|_|_|_|____|____/_____===____\n10\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________________|_|_|_|_|____|____/_____===____\n6\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________________|_|_|_|_|____|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_______________________|_|_|_|_|___|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|________________________|_|_|_|_|__|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________________________|_|_|_|_|_|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + ++ :/----I-----\n__\\|________\\|__________________________|_|_|_|_||____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|___________________________|_|_|_|_|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + +++ :/----I-----\n__\\|________\\|____________________________|_|_|_|||___/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_____________________________|_|_|_|_|__/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + +++ + :/----I-----\n__\\|________\\|______________________________|_|_|||_|_/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_______________________________|_|_|_|_|/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | +++ + |/----I-----\n__\\|________\\|________________________________|_|||_|_/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + :/----I-----\n__\\|________\\|_________________________________|_|_|_|/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | ++ + |/----I-----\n__\\|________\\|__________________________________|||_|_/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + :/----I-----\n__\\|________\\|___________________________________|_|_|/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + |/----I-----\n__\\|________\\|___________________________________||_|_/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + :/----I-----\n__\\|________\\|___________________________________|_|_|/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + |/----I-----\n__\\|________\\|___________________________________|__|_/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|___________________________________|___|/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|___________________________________|___|/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + |/----I-----\n__\\|________\\|___________________________________|____/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|____________________________________|___/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /__\\ /__\\ /~~\\\n |<><>| |<><>| (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\ |\n \\/][][\\/ // [][][] || // |\\ / | ||\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n20\n /__\\ /__\\ /~~\\\n |<><>| |<><>| Which way? (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\ |\n \\/][][\\/ // [][][] || // |\\ / | ||\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n12\n /__\\ /__\\ /~~\\\n |<><>| |<><>| Which way? (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\.\\\n \\/][][\\/ // [][][] || // |\\ / | \\\\\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n6\n /__\\ /__\\ /~~\\\n |<><>| |<><>| (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\.\\\n \\/][][\\/ // [][][] || // |\\ / | \\\\\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|\\ \\ |-O-| | | |\n | || \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|o \\ |-O-| | | |\n | ||o| \\ | \\_/___|_________|__|\n | | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / o \\ |-O-| | | |\n | ||o|o\\ | \\_/___|_________|__|\n | | |o| \\ | + :/----I-----\n__\\|__|_____\\|_____________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /oo \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | o o o\\ | + :/----I-----\n__\\|_|_|_|__\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /oo \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | o o o | + :/----I-----\n__\\|__|_|_|_\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | oo \\ | \\_/___|_________|__|\n | | ||o o\\o | + :/----I-----\n__\\|___|_|_|\\|_____________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | oo o o o| + :/----I-----\n__\\|_||_|_|_||_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | oo o\\o o + :/----I-----\n__\\|__||_|_|_|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o o o|o + :/----I-----\n__\\|__|_|_|_|||____________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o\\o o o + :/----I-----\n__\\|___|_|_|_|_|___________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o o|o o + :/----I-----\n__\\|____|_|_|||_|__________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o\\o o o o + :/----I-----\n__\\|_____|_|_|_|_|_________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o|o o o + :/----I-----\n__\\|______|_|||_|_|________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\o o o o o + :/----I-----\n__\\|_______|_|_|_|_|_______________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ o|o o o o + :/----I-----\n__\\|________|_|_|_|_|______________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ o o o o o + :/----I-----\n__\\|________\\|_|_|_|_|_____________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ o o o o o* + :/----I-----\n__\\|________\\|_|_|_|_|_____________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ |o o o o o --- + :/----I-----\n__\\|________\\||_|_|_|_|____________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- + :/----I-----\n__\\|________\\|_|_|_|_|_|__________________________*|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- --- + :/----I-----\n__\\|________\\|__|_|_|_|_|__________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- --- + :/----I-----\n__\\|________\\|__|_|_|_|_|__________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- * + :/----I-----\n__\\|________\\|___|_|_|_|_|_________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . \' \\_/___|_________|__|\n | | \\ | o o o o.*--- \'. \' + :/----I-----\n__\\|________\\|____|_|_|_|_|________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o.o . . .+ :/----I-----\n__\\|________\\|_____|_|_|o|_____________________.___|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o + :/----I-----\n__\\|________\\|_____|_|_|o|__.________________._____|._/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o* + :/----I-----\n__\\|________\\|______|_|_|_|________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o --- + :/----I-----\n__\\|________\\|_______|_|o|_|_______________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o --- + :/----I-----\n__\\|________\\|_______|_|o|_|______________________*|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o ---* + :/----I-----\n__\\|________\\|_______|_|o|_|_______________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o --- :. .+ :/----I-----\n__\\|________\\|_______|_|o|_|_______________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | .\\_/___|_________|__|\n | | \\ | o o o o --- . + :/----I-----\n__\\|________\\|_______|_|o|_|________________.__.__.|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . . . \\_/___|_________|__|\n | | \\ | o o o *-- + :/----I-----\n__\\|________\\|_______|_|o|_|______________.________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . \\_/___|_________|__|\n | | \\ | o o o * . + :/----I-----\n__\\|________\\|_______|_|o|_|_._____________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | .o o o + :/----I-----\n__\\|________\\|_______|_|o|_o__________.____________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o *+ :/----I-----\n__\\|________\\|_____._|_|o|_o________________________|_/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o --- + :/----I-----\n__\\|________\\|_______|_|o|_o_________________________|/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o* --- |/----I-----\n__\\|________\\|_______|_|o|_o__________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o --- --- :/----I-----\n__\\|________\\|_______|_|o|_o__________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o --- --- :/----I-----\n__\\|________\\|_______|_|o|_o__________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o *- --- ----I-----\n__\\|________\\|_______|_|o|_o________________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \' \\_/___|_________|__|\n | | \\ | o o * . --- ----I-----\n__\\|________\\|_______|_|o|_o________________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . \\_/___|_________|__|\n | | \\ | o o --*----I-----\n__\\|________\\|_______|_|oo_o_.______________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | . o o : ***---I-----\n__\\|________\\|_______|_|oo_o__________________________\'___"_===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o *---I-----\n__\\|________\\|____.__|_|oo_o_______________________"_.____._===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | . o o ----I-----\n__\\|________\\|_______|_|oo_o______________________._________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o . ----I-----\n__\\|________\\|__.____|_|oo_o________________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o ----I-----\n__\\|________\\|_._____|_|oo_o____________________.___________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o ----I-----\n__\\|________\\|_._____|_|oo_o___________________.____________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o ----I-----\n__\\|________\\|_._____|_|oo_o__________________._____________===____\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_____|_|_|_____________|__|__|____________________\n3\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\______|_|_|____________|__|__|____________________\n10\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n\n\n\n ___________-----_O________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n\n\n _ ____-----_O___\n ____(_)====[ ]======____\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n\n _ ____-----_O___\n (_)====[ ]======\n _______~~~~-----~~~~~_____\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ________^____^____^_______\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n ^ ^ ^\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n6\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| . .\n . . : : : : : : :\n . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n. . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| . .\n . . : : : : : : :\n . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| .\n . . : : : : : : :\n. . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| .\n . . : : : : : : :\n . . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| .\n . . : : : : : : :\n . . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . .\n. / :| () |: : :\\\n8 . :....\\__/...........: .\n8 . . |___________________|\n\' |...................| .\n . . : : : : : : :\n . . \\................./ .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n. -..___..- .\n2\n . . __---__ .\n. . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . .\n8. / :| () |: : :\\\n88 . :....\\__/...........: .\n88 . . |___________________|\n8\' |...................| .\n . . : : : : : : :\n . . \\................./ .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n. . . . /. / \\.........\\ . .\n88. / :| () |: : :\\\n888 . :....\\__/...........: .\n888 . . |___________________|\n88\' |...................| .\n\' . . : : : : : : :\n . . \\................./ .\n. . \\ . . : . . / .\n . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n.. . . . /. / \\.........\\ . .\n888. / :| () |: : :\\\n8888 . :....\\__/...........: .\n8888 . . |___________________|\n888\' |...................|\n\'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n .. . . . /. / \\.........\\ . .\n8888. / :| () |: : :\\\n88888 . :....\\__/...........: .\n88888 . . |___________________|\n8888\' |...................|\n \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n. . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n. . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n .. . . . /. / \\.........\\ . .\n.8888. / :| () |: : :\\\n888888 . :....\\__/...........: .\n888888 . . |___________________|\n\'8888\' |...................|\n \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........: .\n 888888 . . |___________________|\n \'8888\' |...................|\n \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n. .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........: .\n 888888 . . |___________________|\n \'8888\' |...................|\n. \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n. . -..___..- .\n2\n . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........: .\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . . -..___..-\n2\n. . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........:\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n. . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . . -..___..-\n2\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n. 888888 . :....\\__/...........:\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n. . . . . \\._........._./ .\n . . -..___..-\n1\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n . 888888 . :....\\__/...........:\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n . . . . . \\._........._./ .\n . . -..___..-\n1\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n . 888888 . :....\\__/...........:\n 888888 . . |___________________|\n. \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n . . . . . \\._........._./ .\n . . -..___..-\n7\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n. . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n . 888888 . :....\\__/...........:\n 888888 . . |___________________|\n . \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n . . . . . \\._........._./ .\n . . -..___..-\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n4\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n20\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n6\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n23\n I grow tired /~~\\\n ==== of asking this ===, |<><>|\n | o o so it will @o o@) /_/\\_\\\n _\\ -/_ be the last time. \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n12\n I grow tired /~~\\\n ==== of asking this ===, |<><>|\n | o o so it will @o o@) /_/\\_\\\n _\\ -/_ be the last time. \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| |// /_/\\ /\\_| \\\\ | |//\n \\(| )/ || \\\\ // || \\#|====#/\n |-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| |// /_/\\ /\\_| \\\\ | |//\n \\(| )/ || \\\\ // || \\#|====#/\n |-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n22\n Where is the /~~\\\n ==== Rebel Base? ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| |// /_/\\ /\\_| \\\\ | |//\n \\(| )/ || \\\\ // || \\#|====#/\n |-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n8\n Where is the /~~\\\n ==== Rebel Base? ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n11\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n30\n /~~\\\n ==== Dantooine. ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n4\n /~~\\\n ==== They\'re on ===, |<><>|\n | o o Dantooine. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n28\n /~~\\\n ==== They\'re on ===, |<><>|\n | o o Dantooine. @- -@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n4\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n4\n You see, Lord /~~\\\n ==== Vader, she can ===, |<><>|\n | o o be reasonable. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n7\n You see, Lord /~~\\\n ==== Vader, she can ===, |<><>|\n | o o be reasonable. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n22\n You see, Lord /~~\\\n ==== Vader, she can ===, |<><>|\n | o o be reasonable. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n2\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n28\n Proceed with /~~\\\n ==== the ===, |<><>|\n | o o demonstration! @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n Proceed with /~~\\\n ==== the ===, |<><>|\n | o o demonstration! @O O@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n Proceed with /~~\\\n ==== the ===, |<><>|\n | o o demonstration! @O O@) /_/\\_\\\n _\\ -/_ \\o / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n3\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\o / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n33\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n You | |\n may fire | .@@. |\nwhen ready.| @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n31\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | | What!\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_, q q | / \\ |\n_[__|__|__ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n2\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_, q q | / \\ |\n_[_|__|___ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n3\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_,q q | / \\ |\n_[|__|____ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | | ......\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | | ............\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | ..................\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | ........................\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ...........................***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | .....................***...***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ...............***...***...***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | .........***...***...****..***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ...***...***...****..*****.***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | | **\n | | | ***|..***...****..*****..*****\n | | | | | **\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | | ******\n | | | **...****..*****..************\n | | | | | ******\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | ****** *******\n | | | *..*****..********************\n | | | | ****** *******\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | |****** ****************\n | | | .*****************************\n | | | |****** ****************\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | |****************\n | | | ******************************\n | | | |****************\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | ******** |\n | | | ******************************\n | | | ******** |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n2\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ******************************\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | ..|.........|................\n | | | ******************************\n | | | \'\'|\'\'\'\'\'\'\'\'\'|\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\..........|..............\n_[|__|____ | | ****************************\n | | | ******************************\n | | | ****************************\n | | \\.___./\'\'\'\'\'\'\'\'\'\'|\'\'\'\'\'\'\'\'\'\'\'\'\'\'\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / ***************************\n_[|__|____ | | *****************************\n | | | ******************************\n | | | *****************************\n | | \\.___.***************************\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. ***************************\n_.q q | / ****************************\n_[|__|____ | | *****************************\n | | | ******************************\n | | | *****************************\n | | \\.___.****************************\n | | / ***************************\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / *************************\n_[|__|____ | | *****************************\n | | | ******************************\n | | | *****************************\n | | \\.___.*************************\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\..........|......\n_[|__|____ | | **********************\n | | | ******************************\n | | | **********************\n | | \\.___./\'\'\'\'\'\'\'\'\'\'|\'\'\'\'\'\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ******************************\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n5\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ ----|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ --------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ ------------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ ----------------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @**--------------------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n4\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .**. |\n | ****-------------------|\n | `**\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .**. |\n | ****--------------- |\n | `**\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .**. |\n | ****----------- |\n | `**\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | ** |\n | **** |\n | ******------ |\n | **** |\n | ** |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | \' ** \' |\n | \' *****# |\n | :******** " |\n | **#******* |\n | ******** |\n | \' ****#* \' |\n `-_____ " ** _____-\'\n ----____ \' " ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | \' |\n | " ** \'# |\n | \' \' ****** \' |\n | ******** \' |\n | \' #********** |\n | ******** |\n | \' : ****** \' |\n `-_____ " ** " _____-\'\n ----____ \' # ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | \' " # |\n | " \' ** |\n | ****** \' |\n | ******** \' |\n | \' # **** **** |\n | ******** |\n | \' ****** |\n `-_____ : " ** \' _____-\'\n ----____ \' : " ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | \' * * |\n | " * ** * \' |\n | * ****** * |\n | * ** ** * \' |\n | \' # * ** ** * |\n | * ** ** * |\n | * ****** * |\n `-_____: " * ** * \' _____-\'\n ----____ * * " ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | " * * |\n | * * |\n | * **** * |\n | * ** ** * \' |\n |\' # * ** ** * |\n | * ** ** * |\n | * **** * |\n `-_____" * * _____-\'\n ----____ * * ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | * * |\n | * ** * |\n | * **** * \'|\n | # * ** ** * |\n | * **** * |\n | * ** * |\n `-_____ * * _____-\'\n ----____ ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | * * |\n | * \' " * |\n | * ** * |\n | * **** * |\n | * ** * |\n | * " * |\n `-_____ : _____-\'\n ----____ ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | . . |\n | |\n | |\n | |\n | ** |\n | |\n | |\n `-_____ . _____-\'\n ----____ : ____----\n ----_____-----\n9\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | |\n | |\n | |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----_____-----\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n3\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n2\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n3\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n3\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ .....\\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ ..... \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ /0 / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ ..... \\_/ _\\- /_\n / \\ / \\ . / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ /*\' / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o . /o\\ (o o")\n _\\ -/_ ..... .*\' \\_/ _\\- /_\n / \\ / \\ .*\' / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ /*\' / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== .* _ ====\n ~~O O .*\' /o\\ (o o")\n _\\ o/_. .*\' \\_/ _\\- /_\n / \\ / \\ .*\' / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ /*\' / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ o/_ .* \\_/ _\\- /_\n / \\ / \\ .*\' / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ .*\' / /| | |\\ |\n || | | | \\\\ /*\' || | | | ||\n (\' |====| /)/ (` | | | `)\n | || | <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n14\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( /> <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n10\n ####\n I told you {o o"}\n I\'d outrun {= }\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( /> <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( /> <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n3\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {{{@ /> <\\ ) | | === | |\n {} H{{}}} \\___________/ |_| O |_|\n @ H"||"} \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {{{@ >\\ <\\ ) | | === | |\n {} H{{}}} \\___________/ |_| O |_|\n @ H"||"} \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n14\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | |-=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | --=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) |---=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) ----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) -----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ )------=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o__O____ /() \\\n {} {// } {} / =- >\\ \\ _|_____|_\n {} // } {} ( >\\ /\\ )------=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ___o__O____ /() \\\n {} {// } {} / =- >\\ \\ _|_____|_\n {} // } {} ( >\\ /\\ ) -----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ___o_O_____ /() \\\n {} {// } {} / =--> \\ _|_____|_\n {} // } {} ( >\\/< ) ----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ____oO_____ /() \\\n {} {// } {} / -/=> \\ _|_____|_\n {} // } {} ( />/\\ ) |---=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} o ___\n {{~{ //}~}} ___/\\O_____ /() \\\n {} {// } {} / /> > \\ _|_____|_\n {} // } {} ( /\\ ) | --=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} \\--o ___\n {{~{ //}~}} __/_\\O_____ /() \\\n {} {// } {} / | \\ _|_____|_\n {} // } {} ( / \\ ) | |-=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =} ,\n {~~ //~} \\--o ___\n {{~{ //}~}} ___>\\O/____ /() \\\n {} {// } {} / | \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"O O}\n { =} ,\n {~~ //~} \\--o ___\n {{~{ //}~}} ___>\\O/____ /() \\\n {} {// } {} / | \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ____\\O/____ /() \\\n {} {// } {} / >-|o \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>-\\o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~-~o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>~\\~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~-~o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>~\\~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~-~o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>~\\~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~~~~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n _-=-. ====\n ((___) (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ _ / \\ / \\\n //| | |\\\\ /o\\ / \\/ \\\n || | | | \\\\ \\_/ / /| | |\\ |\n || | | | \\\\ /o || | | | ||\n (\' |====| /)/ (` | | | `)\n | || | =<| .\n .| . . .\n | .\n | .\n | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . . .\n | . . .\n | .\n|>=<| .\n . | . . .\n | .\n | .\n .| .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . . .\n | . . .\n\\ | .\n-|>=<| .\n/ . | . . .\n | .\n | .\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . . .\n_ | . . .\n\'\\ | .\nO-|>=<| .\n_/. | . . .\n | .\n | .\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . |. . .\n _ | . . .\n/\'\\ | .\n-O-|>=<| .\n\\_/ | . . .\n | .\n | .\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . .\n _ | . . .\n /\'\\ | .\n|-O-|>=<| .\n \\_/ | . . .\n | .\n |.\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . .| . .\n _ | . . .\n /\'\\ | .\n<|-O-|>=<| .\n \\_/ | . . .\n | .\n |\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . . | . .\n _ | . . .\n /\'\\ | .\n=<|-O-|>=<| .\n .\\_/ | . . .\n | .\n .|\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . . | . .\n _ | . . .\n /\'\\ | .\n>=<|-O-|>=<| .\n . \\_/ | . . .\n | .\n . |\n . | .\n . . . .\n1\n . . . .\n. .\n .\n| | . O\n| . . | . .\n| _ | . . .\n| /\'\\ | .\n|>=<|-O-|>=<| .\n| . \\_/ | . . .\n| | .\n| . |\n| . | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n |. . | . .\n | _ | . . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n |. \\_/ | . . .\n | | .\n | . |\n | . | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n | . | . .\n | _ |. . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n | \\_/ | . . .\n | |.\n | . |\n |. | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n .| . | . .\n | _ | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n .| \\_/ | . . .\n | |\n | . |\n | | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . | . | . .\n | _ .| . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | .|\n | . |\n .| | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . | . | . .\n | _ . | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | . |\n | . |\n . | | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . | . | . .\n | _ . | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | . |\n | . |\n . | | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . |. | . .\n | _ . | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | . |\n | . |\n . | | .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n | . | . .\n | | .\n |=()=| .\n . | | . . .\n | . |\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n | . | . .\n | | .\n |=()=| .\n . | | . . .\n | . |\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n |. | . .\n | | .\n |=()=| .\n . | | . . .\n |. |\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | | .\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | |.\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | |\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | .|\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n . .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n . .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n . .\n . . . .\n .\n .\n . .\n . . . .\n10\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n .\n . . . .\n .\n .\n . .\n . . . .\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n11\n ==== #### He\'s heading for ===- ====\n ~~o o {"o o} that small moon! o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n19\n ==== #### He\'s heading for ===- ====\n ~~o o {"o o} that small moon! o o"" (- -")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n6\n ==== #### ===- ====\n ~~o o {"o o} o o"" (- -")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### That\'s no moon. ===- ====\n ~~o o {"o o} o o"" (- -")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### That\'s no moon. ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n23\n ==== #### That\'s no moon. -=== ====\n ~~o o {"o o} ""o o (o o")\n _\\ -/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n1\n ==== #### -=== ====\n ~~o o {"o o} ""o o (o o")\n _\\ -/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n24\n ==== #### It\'s a -=== ====\n ~~o o {"o o} space station! ""o o (o o")\n _\\ -/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n7\n ==== #### It\'s a -=== ====\n ~~O O {"o o} space station! ""o o (o o")\n _\\ o/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n1\n ==== #### It\'s a ===- ====\n ~~O O {"o o} space station! o o"" (o o")\n _\\ o/_ { =} _\\o /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### It\'s a ===- ====\n ~~o o {"o o} space station! o o"" (o o")\n _\\ o/_ { =} _\\o /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ o/_ { =} _\\o /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### ===- ====\n o o~~ {"o o} o o"" (o o")\n _\\- /_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n15\n ==== #### ===- ====\n o o~~ {o o"} o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n14\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| . .\n . . : : : : : : :\n . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== #### ===- ====\n o o~~ {o o"} o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n22\n ==== #### I have a very ===- ====\n o o~~ {o o"} bad feeling o o"" (o o")\n _\\- /_ {= } about this! _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### ===- ====\n o o~~ {o o"} o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n11\n ==== #### Turn the ship ===- ====\n o o~~ {o o"} around. o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n12\n ==== #### Turn the ship ===- ====\n ~~o o {o o"} around. o o"" (o o")\n _\\ -/_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### ===- ====\n ~~o o {o o"} o o"" (o o")\n _\\ -/_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n10\n ==== #### I think you\'re ===- ====\n ~~o o {o o"} right. o o"" (o o")\n _\\ -/_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} Full reverse! /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n12\n ==== #### I think you\'re ===- ====\n ~~o o {"o o} right. o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} Full reverse! /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n1\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n9\n ==== #### Chewie, lock in ===- ====\n ~~o o {"o o} the auxiliary o o"" (o o")\n _\\ -/_ { =} power! _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n11\n ==== #### Chewie, lock in ===- ====\n o o~~ {"o o} the auxiliary o o"" (o o")\n _\\- /_ { =} power! _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n6\n ==== #### ===- ====\n o o~~ {"o o} o o"" (o o")\n _\\- /_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### Why are we still ===- ====\n o o~~ {"o o} moving towards o o"" (o o")\n _\\- /_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### Why are we still ===- ====\n o o~~ {"o o} moving towards o o"" (o o")\n _\\o /_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### Why are we still ===- ====\n ~~o o {"o o} moving towards o o"" (o o")\n _\\ o/_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n16\n ==== #### Why are we still ===- ====\n ~~o o {"o o} moving towards o o"" (o o")\n _\\ -/_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n24\n ==== #### We\'re caught in ===- ====\n ~~o o {"o o} a tractor beam! o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n20\n ==== #### I\'m going to have ===- ====\n ~~o o {"o o} to shut down. o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n6\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n25\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ==== Yes?\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n5\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n36\n /~~\\ We\'ve captured a\n |<><>| freighter entering\n /_/\\_\\ the remains of the\n /\\___/\\ ==== Alderaan system.\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n40\n /~~\\ Its markings\n |<><>| match those of a\n /_/\\_\\ ship that blasted\n /\\___/\\ ==== its way out of\n // [ ]|\\\\ | o o Mos Eisley!\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\ They must be\n |<><>| trying to return\n /_/\\_\\ the stolen plans\n /\\___/\\ to the Princess. ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n33\n /~~\\ They must be\n |<><>| trying to return\n /_/\\_\\ the stolen plans\n /\\___/\\ to the Princess. ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n6\n /~~\\ She may yet\n |<><>| be of some use\n /_/\\_\\ to us.\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n14\n /~~\\ She may yet\n |<><>| be of some use\n /_/\\_\\ to us.\n /\\___/\\ # ====\n // [ ]|\\\\// o o |\n //| [_]| \\/ _\\- /_\n \\\\| | /"\'==\'"\\\n #|====| | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\ She may yet\n |<><>| be of some use\n /_/\\_\\ to us.\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | \\\\ /"\'==\'"\\\n #|====| # | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | \\\\ /"\'==\'"\\\n #|====| # | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ __|_|___________/_____===____\n | |\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ __|_|___________/_____===____\n | |\n | oooo |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ __|_|___________/_____===____\n | oooo |\n | |||| |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ oooo __|_|___________/_____===____\n | |||| |\n |------------|\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___________ |||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___________ |||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||__________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_______|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||______||||_ __|_|___________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_____||||__ __|_|___________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_____||||__ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||____||||___ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n There\'s no one _\n on board sir. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___||||____ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n There\'s no one _\n on board sir. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||__||||_____ __|__|__________/_____===____\n |------------|\n | |\n17\n\n\n\n There\'s no one _\n on board sir. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n25\n\n\n\n It must be a _\n decoy. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n26\n\n Did you find\n any droids?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n20\n\n\n\n No sir. _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|_|___________/_____===____\n |------------|\n | |\n34\n\n Send a scanning\n crew aboard.\n _\n I want every part ________|_\n of this ship _ ___ -------------\n checked. / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|_|___________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n19\n\n I sense something...\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n30\n\n ...A presence I\'ve\n not felt since...\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / \\ |---|\n | | / \\ | |\n ________|---|/ \\|---|___________\n / \\\n / \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / \\ \\|---|___________\n / / \\ \\\n / /____________________________________\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / \\ \\|---|___________\n / / \\ \\\n / /_________________________===-_______\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / \\ \\|---|___________\n / / ===- \\ \\\n / /_________________________o o""______\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / ===- \\ \\|---|___________\n / / o o"" \\ \\\n / /_________________________\\- /_______\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ===- \\ \\ | |\n ________|---|/ / o o"" \\ \\|---|___________\n / / _\\- /_ \\ \\\n / /_________====__________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ===- \\ \\ | |\n ________|---|/ / o o"" \\ \\|---|___________\n / / ==== _\\- /_ \\ \\\n / /________~~o o__________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ===- \\ \\ | |\n ________|---|/ / ==== o o"" \\ \\|---|___________\n / / ~~o o _\\- /_ \\ \\\n / /_________\\ -/__________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n4\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== -=== \\ \\ | |\n ________|---|/ / ~~o o ""o o \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n4\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n2\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== -=== \\ \\ | |\n ________|---|/ / ~~o o ""o o \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n4\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n34\n \\ __\\ It\'s lucky you had /__ /\n | | these compartments. | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n29\n \\ __\\ I use them for /__ /\n | | smuggling. | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n30\n \\ __\\ I never thought /__ /\n | | I\'d be smuggling | |\n |---| myself. |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n2\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n31\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\__====__/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ ==== _\\- /_ \\ \\\n / /_______/__\\ /_\\_("o o)_/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ==== o o"" \\ \\|---|___________\n / / _\\ -/_ ("o o) _\\- /_ \\ \\\n / /_______/__\\ /_\\__\\_-/__/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n5\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n25\n \\ __\\ /__ /\n | | Leave that | |\n |---| to me! |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n3\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n35\n \\ __\\ Damn fool! /__ /\n | | I knew that you | |\n |---| were going to |---|\n | | say that. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n6\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n21\n \\ __\\ /__ /\n | | Who is more foolish? | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n3\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n30\n \\ __\\ /__ /\n | | The fool or the fool | |\n |---| who follows him? |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n6\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n25\n\n\n The ship\'s\n all yours. _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n6\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n36\n\n\n If the scanners detect\n anything report it _\n immediately. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ ___|==|____|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ ____|==|___|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ _____|==|__|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ ______|==|_|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + +o o :/----I-----\n________________________ _______|==||__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o :/----I-----\n________________________ ________|==|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + o+ o :/----I-----\n________________________ _________|==|_|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n +o +o :/----I-----\n________________________ __________|==||_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + o :/----I-----\n________________________ ___________|==|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o+ o+ :/----I-----\n________________________ ___________||=||/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o +o +:/----I-----\n________________________ ___________|_||=/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ___________|__|=/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o+=:/----I-----\n________________________ ___________|__||/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o |:/----I-----\n________________________ ___________|__|_/_____===____\n |------------|\n | |\n18\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ___________|__|_/_____===____\n |------------|\n | |\n15\n\n Hey down there!\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ___________|__|_/_____===____\n |------------|\n | |\n17\n\n Hey down there!\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|_|_/_____===____\n |------------|\n | |\n3\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|_|_/_____===____\n |------------|\n | |\n20\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|_|_/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|__|/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o |:/----I-----\n________________________ _____________|__/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o :/----I-----\n________________________ ______________|_/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o :/----I-----\n________________________ _______________|/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n |:/----I-----\n________________________ ________________/_____===____\n |------------|\n | |\n5\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n :/----I-----\n________________________ ________________/_____===____\n |------------|\n | |\n10\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n :/----I-----\n________________________ ________________/_____===____\n |------------|\n | |\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n31\n ==== _________________________\n TK-421. | o o |\\ _____________________ /|\n Why aren\'t you _\\ -/_ | | | |\n at your post? / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n3\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n /__\\\n |<><>|\n (_/\\_)\n / \\\n //| __ |\\\\\n // |/ \\| \\\\\n // [][][] ||\n |\' |\\ /| \'|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n17\n /__\\\n |<><>|\n |, (_/\\_) ,|\n \\\\ / \\ //\n \\\\//| __ |\\\\//\n \\/ |/ \\| \\/\n [][][]\n |\\ /|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n4\n /__\\\n |<><>|\n (_/\\_)\n / \\\n //| __ |\\\\\n // |/ \\| \\\\\n || [][][] ||\n |\' |\\ /| \'|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n4\n /__\\\n |<><>|\n (_/\\_)\n / \\\n //| __ |\\\\\n // |/ \\| \\\\\n || [][][] \\\\\n |\' |\\ /| \'|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n6\n ==== _________________________\n Take over. | o o |\\ _____________________ /|\n We\'ve got a bad _\\ -/_ | | | |\n transmitter. / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n16\n ==== _________________________\n Take over. o o | |\\ _____________________ /|\n We\'ve got a bad _\\- /_ | | | |\n transmitter. / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n7\n ==== _________________________\n Take over. | o o |\\ _____________________ /|\n We\'ve got a bad _\\ -/_ | | | |\n transmitter. / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n6\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n32\n ==== _________________________\n I\'ll see | o o |\\ _____________________ /|\n what I can do. _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n5\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n8\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""||| __ | |\n |||| ||| |o=|| |\n |||| ||| |__|| |\n ()|-==-|() | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|*=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|*=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|\\__________________________/|________________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| |\\__________________________/|\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | |\\__________________________/|\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | |\\__________________________/|\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| |\\__________________________/|\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| |\\__________________________/|\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_||\\__________________________/|\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=||\\__________________________/|\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ |\\__________________________/|\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ |\\__________________________/|\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ |\\__________________________/|\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o |\\__________________________/|\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== |\\__________________________/|\n | o o | {o o"} |><> | |\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n2\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n2\n ==== | #### /__\\ |\n | O O | {o o"} |><> | |\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n3\n ==== | #### /__\\ |\n | O O | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n -=== | _______\n | o o | "" / \\ o*oo\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n2\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | |-----\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | ----- o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## |----- | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ----- | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ -----## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ ----- | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ ----- | ## | | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ ----- | ## | | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\----- | ## | | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | *---\\ | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | O O | "" / \\ oo*o\n _\\ */_ | :. | | o**o\n / /* \\ | | | *oo*\n // *****\\\\ | ## | | o**o\n // || * | \\\\ | ## \\_______/\n // || * | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | O*O | "" / \\ oo*o\n . _\\***_. | :. | | o**o\n /.*****\\ | | | *oo*\n //*******\\ | ## | | o**o\n //.|*****.\\\\ | ## \\_______/\n // ||***|.=]==- |______________________\n () |-=*-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=*= | _______\n |.***. . | "" / \\ oo*o\n . ._***** | :. | | o**o\n /******* | | | *oo*\n /*********. | ## | | o*oo\n // *******\\\\ | ## \\_______/\n //. .***** =]==- |______________________\n () |-***|. #) /\n |--*-| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n . -=== | _______\n . | X*X | "" / \\ oo*o\n _\\***_ . | :. | | o**o\n . / *****\\ | | | *oo*\n //*******\\ | ## | | o*oo\n // |***** \\\\ . | ## \\_______/\n // ||***| =]==- |______________________\n () |-=*-| #) /\n . |----| |------------------------\n | || | . | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n . | X X | "" / \\ oo*o\n . _\\ * _ | :. | | o**o\n / ***\\\\ . | | | *oo*\n //|*****\\\\ | ## | | o*oo\n . // ||*** \\\\ | ## \\_______/\n // || * | =]==- |______________________\n () |-==-| #) . /\n |----| |------------------------\n | || | | (*)\n . | || | |\n |_||_| . |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n . | X X | "" / \\ oo*o\n _\\ - _ | :. | | o**o\n / /* \\\\ | | | *oo*\n //||*** \\\\ | ## | | o**o\n // || * | \\\\ | ## \\_______/\n // || # | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | . |\n . |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n . | X X | "" / \\ oo*o\n _\\ - _ | :. | | o**o\n / /# \\\\ | | | *oo*\n //||### \\\\ | ## | | o**o\n // ||###| \\\\ | ## \\_______/\n // || # | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | . |\n . |_||_| |\n______________[_][__\\_____________________|________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n ===- | #### ==== |\n o o"" | {o o"} o o~~ |\n _\\- /_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n4\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n3\n ===- | #### ==== |\n o o"" | {o o"} o o~~ |\n _\\- /_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n1\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n8\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | Between his\n _\\ -/_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n9\n ===- | #### ==== |\n o o"" | {o o"} o o~~ | Between his\n _\\- /_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n7\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | Between his\n _\\ -/_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n7\n ===- | #### ==== |\n o o"" | {o o"} o o~~ | Between his\n _\\- /_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n1\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n14\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | ...it\'s a\n _\\ -/_ | {= } _\\- /_ | wonder the\n / \\ | {~~ //~} / \\ | whole station\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | doesn\'t know\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | we\'re here!\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n12\n -=== | #### ==== |\n ""o o | {"o o} o o~~ | ...it\'s a\n _\\ -/_ | { =} _\\- /_ | wonder the\n / \\ | {~~ //~} / \\ | whole station\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | doesn\'t know\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | we\'re here!\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n4\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | ...it\'s a\n _\\ -/_ | {= } _\\- /_ | wonder the\n / \\ | {~~ //~} / \\ | whole station\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | doesn\'t know\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | we\'re here!\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n1\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n2\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\\________\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\\________\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\\________\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\\________\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\\________\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\\________\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\\________\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\\________\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\\________\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\\________\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\\________\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\\________\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|\\________\n13\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / # /\\ \\ *ooo\n _\\=/_ found the main | :. | # / O| | o**o\n / \\ controls to ___ | |###======| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | #____| | o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / ||OO \\ ooo*\n _\\=/_ found the main | :. | ||OO__| o**o\n / \\ controls to ___ | | // ____| o*o*\n //|/.\\|\\\\ the power beam / ()\\ | ## | //##.. | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / ||OO \\ ooo*\n _\\=/_ found the main | :. | ||OO__| o**o\n / \\ controls to ___ | | // ____| o*o*\n //|/.\\|\\\\ the power beam / ()\\ | ## | //##.. | o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | o*o*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" /< \\\\ \\ ooo*\n _\\=/_ found the main | :. | < || | o*o*\n / \\ controls to ___ | |=========| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | OOO> \\\\| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" /< \\\\ \\ ooo*\n _\\=/_ found the main | :. | < || | o*o*\n / \\ controls to ___ | |=========| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | OOO> \\\\| o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found the main | :. | | o*o*\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / | | \\ oo*o\n _\\=/_ found the main | :. |== ====| o*o*\n / \\ controls to ___ | | | |#<> | *o*o\n //|/.\\|\\\\ the power beam / ()\\ | ## |_/ \\___| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o*o*\n / \\ controls to ___ | | | *o*o\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" /_______\\ *o*o\n _\\=/_ found the main | :. |[][][]===| o**o\n / \\ controls to ___ | |_________| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |[][][]===| ***o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" /_______\\ *o*o\n _\\=/_ found the main | :. |[][][]===| o**o\n / \\ controls to ___ | |_________| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |[][][]===| **oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ *o*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | **oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" /--\\ .\\ oo*o\n _\\=/_ found the main | :. | |..\\ . | o**o\n / \\ controls to ___ | | |:: | . | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |=====|. .| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" /--\\ .\\ oo*o\n _\\=/_ found the main | :. | |..\\ . | o**o\n / \\ controls to ___ | | |:: | . | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |=====|. .| o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / || || \\ oo*o\n _\\=/_ found the main | :. |__OO_OO__| o**o\n / \\ controls to ___ | |__ _ __| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | OO OO | oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / .o. \\ oo*o\n _\\=/_ found the main | :. | o|||o | oooo\n / \\ controls to ___ | | o | o | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |/__/_\\__\\| oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | oooo\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .o. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .*. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .o. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .*. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n I don\'t think ("o o) o o~~ |\n you boys can help. _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n19\n ==== ==== |\n I don\'t think (o o") o o~~ |\n you boys can help. _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n8\n ==== ==== |\n I must go alone. (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n15\n ==== ==== |\n I must go alone. ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n25\n ==== I want to ==== |\n ("o o) go with you! o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n4\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n30\n ==== ==== |\n Be patient, Luke. ("o o) o o~~ |\n Stay and watch _\\ -/_ _\\- /_ |\n over the droids. / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n20\n ==== But he can... ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n29\n ==== ==== |\n Your destiny ("o o) o o~~ |\n lies along a _\\ -/_ _\\- /_ |\n different path to / \\ / \\ / \\ |\n mine. / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n2\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n21\n ==== ==== |\n The Force will ("o o) o o~~ |\n be with you... _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n20\n ==== ==== |\n ("o o) o o~~ |\n ...always! _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n17\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n4\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n38\n -=== ####\n Where did ""o o {o o"}\n you dig up _\\ -/_ {= }\n that old / \\ {~~ //~}\n fossil! //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== |\n ~~o o |\n _\\ -/_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n_____________________________________[_][__\\_______|_______________\n3\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n_____________________________________[_][__\\_______|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][__\\_______|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][__\\_______|_______________\n19\n ==== |\n Ben is o o~~ |\n a great man! _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][__\\_______|_______________\n13\n ==== |\n Ben is o o~~ |\n a great man! _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ /() \\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\o /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n18\n ==== |\n o o~~ |\n What is it? _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n ==== |\n o o~~ |\n What is it? _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n6\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found her... | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n18\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found her... | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n10\n /~\\ | _______\n ( oo| And keeps repeating | "" / \\ ooo*\n _\\=/_ she\'s here. | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n5\n /~\\ | _______\n ( oo| And keeps repeating | "" / \\ ooo*\n _\\=/_ she\'s here. | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n8\n /~\\ | _______\n ( oo| And keeps repeating | "" / \\ ooo*\n _\\=/_ she\'s here. | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n22\n ==== |\n o o~~ |\n Well who... _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n19\n ==== |\n o o~~ |\n who has he found? _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n16\n /~\\ | _______\n ( oo| Princess Leia. | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n4\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n ==== |\n O O~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n3\n ==== |\n O O~~ |\n _\\o /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n11\n ==== |\n o o~~ |\n The princess? _\\- /_ |\n / \\ |\n She\'s here? //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n13\n ==== |\n o o~~ |\n The princess? _\\- /_ |\n / \\ |\n She\'s here? //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n9\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n11\n -=== ####\n ""o o {o o"}\n Princess? _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n10\n -=== ####\n ""o o {"o o}\n Princess? _\\ -/_ { =}\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n5\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ # AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ # AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ # AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ # termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n9\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n5\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n9\n -=== ####\n What are you ""o o {o o"}\n talking _\\ -/_ {= }\n about? # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n9\n -=== ####\n What are you ""o o {"o o}\n talking _\\ -/_ { =}\n about? # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n What are you ""o o {"o o}\n talking _\\ -/_ { =}\n about? / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n |\' [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n5\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n |\' [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n29\n ==== |\n o o~~ |\n She\'s the one _\\- /_ |\n in the message. / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n16\n ==== |\n o o~~ |\n We\'ve got to _\\- /_ |\n help her! / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n17\n ==== |\n o o~~ |\n We\'ve got to _\\- /_ |\n help her! / \\ |\n //| __ |\\\\ __ |\n // |/ \\|// |o=||\n /\' [][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\|// |o=||\n /\' [][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n8\n -=== ####\n I\'m not ""o o {o o"}\n going anywhere. _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n I\'m not ""o o {"o o}\n going anywhere. _\\ -/_ { =}\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n17\n -=== ####\n I\'m not ""o o {"o o}\n going anywhere. _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n19\n ==== |\n ~~o o |\n _\\ -/_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n11\n ==== |\n o o~~ |\n She\'s rich... _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n11\n ==== |\n o o~~ |\n She\'s rich... _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n14\n -=== ####\n Rich? ""o o {o o"}\n _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n -=== ####\n Rich? ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n -=== ####\n Rich? ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n5\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n What\'s ""o o {o o"}\n your plan? _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n What\'s ""o o {o o"}\n your plan? _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n14\n -=== ####\n What\'s ""o o {"o o}\n your plan? _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n -=== #### ====\n ""o o {"o o} o o~~\n _\\ -/_ { =} _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n11\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { =} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o {"O O} I\'m going o o~~\n _\\ -/_ { -} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n2\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { -} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n1\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { O} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n2\n -=== #### ====\n ""o o {"o o} I\'m going O O~~\n _\\ -/_ { O} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n3\n -=== #### ====\n ""o o {"o o} I\'m going O O~~\n _\\ -/_ { O} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\|//\n #[][][]# {} // } {} # [][][]#\n |\\ /| {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n1\n -=== #### ====\n ""o o {"o o} I\'m going O O~~\n _\\ -/_ { =} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n5\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { =} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o {"o o} o o~~\n _\\ -/_ { =} _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n10\n -=== #### ====\n ""o o Don\'t worry {"o o} o o~~\n _\\ -/_ Chewie... { =} _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n7\n -=== #### ====\n ""o o Don\'t worry {o o"} o o~~\n _\\ -/_ Chewie... {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n16\n -=== #### ====\n ""o o Don\'t worry {o o"} o o~~\n _\\ -/_ Chewie... {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n2\n -=== #### ====\n ""o o {o o"} o o~~\n _\\ -/_ {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n19\n -=== #### ====\n ""o o I think I {o o"} o o~~\n _\\ -/_ know what {= } _\\- /_\n / \\ he has in {~~ //~} / \\\n //| __ |\\\\ mind. {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n9\n -=== #### ====\n ""o o I think I {o o"} o o~~\n _\\ -/_ know what {= } _\\- /_\n / \\ he has in {~~ //~} / \\\n //| __ |\\\\ mind. {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| \\\\ {} {// } {} // |/ \\| \\\\\n #[][][] # {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o I think I {o o"} o o~~\n _\\ -/_ know what {= } _\\- /_\n / \\ he has in {~~ //~} / \\\n //| __ |\\\\ mind. {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| \\\\ {} {// } {} // |/ \\|//\n #[][][] # {} // } {} # [][][]#\n |\\ /| {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o {o o"} o o~~\n _\\ -/_ {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| \\\\ {} {// } {} // |/ \\|//\n #[][][] # {} // } {} # [][][]#\n |\\ /| {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n19\n /~\\ | _______\n ( oo| What should R2 and | "" / \\ ooo*\n _\\=/_ I do if we\'re | :. |__[]_[]__| o*o*\n / \\ discovered ___ | |__ _ __| *oo*\n //|/.\\|\\\\ here? / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n9\n /~\\ | _______\n ( oo| What should R2 and | "" / \\ ooo*\n _\\=/_ I do if we\'re | :. |__[]_[]__| o*o*\n / \\ discovered ___ | |__ _ __| *oo*\n //|/.\\|\\\\ here? / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ===- ==== |\n o o"" o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n20\n ===- ==== |\n o o"" Lock the o o~~ |\n _\\- /_ door. _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n7\n ===- ==== |\n o o"" Lock the o o~~ |\n _\\- /_ door. _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // // |/ \\|// |o=||\n # [][][]# # [][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n2\n ===- ==== |\n o o"" o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // // |/ \\|// |o=||\n # [][][]# # [][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n2\n ===- ==== |\n o o"" o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n16\n ===- ==== |\n And hope o o"" o o~~ |\n they don\'t _\\- /_ _\\- /_ |\n have / \\ / \\ |\n blasters. //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n3\n ===- ==== |\n And hope o o"" o o~~ |\n they don\'t _\\- /_ _\\- /_ |\n have / \\ / \\ |\n blasters. //| __ |\\\\ //| __ |\\\\ __ |\n \\\\|/ \\ // \\\\|/ \\|// |o=||\n #[][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n10\n ===- ==== |\n And hope o o"" ~~o o |\n they don\'t _\\- /_ _\\ -/_ |\n have / \\ / \\ |\n blasters. //| __ |\\\\ //| __ |\\\\ __ |\n \\\\|/ \\ // \\\\|/ \\|// |o=||\n #[][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]_____________________[_][_]________|_________\n5\n ===- ==== |\n o o"" ~~o o |\n _\\- /_ _\\ -/_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n \\\\|/ \\ // \\\\|/ \\|// |o=||\n #[][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]_____________________[_][_]________|_________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~\\\n ( oo|\n _\\=/_\n / \\ ___\n //|/.\\|\\\\ / ()\\\n || \\_/ || _|_____|_\n || |\\ /| || | | === | |\n # \\_ _/ # |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n15\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ ___\n //|/.\\|\\\\ / ()\\\n || \\_/ || _|_____|_\n || |\\ /| || | | === | |\n # \\_ _/ # |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n3\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ # ___\n //|/.\\|\\\\// / ()\\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n8\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ # ___\n //|/.\\|\\\\// /() \\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n11\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ # ___\n //|/.\\|\\\\// / ()\\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n7\n /~\\\n ( oo|\n _\\=/_\n / \\ # ___\n //|/.\\|\\\\// / ()\\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | {"||"} \' | | || |\n |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]_______________[_][_]____________\n2\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | {"||"} \' | | || |\n) |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n- | || | {"||"} \' | | || |\n_) |_||_| {"||"} [_| |_||_|\nO________[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n-- | || | {"||"} \' | | || |\n__) |_||_| {"||"} [_| |_||_|\n_O_______[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n--- | || | {"||"} \' | | || |\n___) |_||_| {"||"} [_| |_||_|\n__O______[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n---- | || | {"||"} \' | | || |\n____) |_||_| {"||"} [_| |_||_|\nO__O_____[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n[____) |_||_| {"||"} [_| |_||_|\n_O__O____[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n [____) |_||_| {"||"} [_| |_||_|\n__O__O___[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n [____) |_||_| {"||"} [_| |_||_|\n___O__O__[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n [____)|_||_| {"||"} [_| |_||_|\n____O__O_[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----| || | {"||"} \' | | || |\n [____)_||_| {"||"} [_| |_||_|\n_____O__O__][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- || | {"||"} \' | | || |\n [____)||_| {"||"} [_| |_||_|\n______O__O_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----|| | {"||"} \' | | || |\n [____)|_| {"||"} [_| |_||_|\n_______O__O][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----| | {"||"} \' | | || |\n [____)_| {"||"} [_| |_||_|\n________O__O[_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | {"||"} \' | | || |\n [____)| {"||"} [_| |_||_|\n_________O__O_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |----| {"||"} \' | | || |\n [____) {"||"} [_| |_||_|\n_________[O__O]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | ---- {"||"} \' | | || |\n |[____) {"||"} [_| |_||_|\n_________[_O__O_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | |---- {"||"} \' | | || |\n | [____) {"||"} [_| |_||_|\n_________[_]O__O____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | ||---- {"||"} \' | | || |\n | |[____) {"||"} [_| |_||_|\n_________[_]_O__O___________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || ---- {"||"} \' | | || |\n | ||[____) {"||"} [_| |_||_|\n_________[_][_O__O__________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || |---- {"||"} \' | | || |\n | || [____) {"||"} [_| |_||_|\n_________[_][_]O__O_________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || |[____) {"||"} [_| |_||_|\n_________[_][_]_O__O________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]__O__O_______[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]___O__O______[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n2\n /__\\ #### /__\\\n | <><| {O O"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n14\n /__\\ #### /__\\\n | <><| Grrrrrr! {O O"} . |><> |\n (__/\\) {0 } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n4\n /__\\ #### /__\\\n | <><| Grrrrrr! {o o"} . |><> |\n (__/\\) {0 } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]______O__O___[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]_______O__O__[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | (____] {"||"} [_| |_||_|\n_________[_][_]_______O__O__[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | (____] {"||"} [_| |_||_|\n_________[_][_]_____O__O____[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) { -} | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | (____] {"||"} [_| |_||_|\n_________[_][_]___O__O______[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) --{ -}-- | (/\\__)\n / \\ { // } I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || |(____] {"||"} [_| |_||_|\n_________[_][_]_O__O________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) --{ -}-- | (/\\__)\n / \\ { // } I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || ---- {"||"} \' | | || |\n | ||(____] {"||"} [_| |_||_|\n_________[_][_O__O__________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) --{ -}-- | (/\\__)\n / \\ { // } I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | |---- {"||"} \' | | || |\n | (____] {"||"} [_| |_||_|\n_________[_]O__O____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) { -} | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |----| {"||"} \' | | || |\n (____] {"||"} [_| |_||_|\n_________[O__O]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----| | {"||"} \' | | || |\n (____]_| {"||"} [_| |_||_|\n________O__O[_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----_|| | {"||"} \' | | || |\n (____]||_| {"||"} [_| |_||_|\n______O__O_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- |_|| | {"||"} \' | | || |\n (____]|_||_| {"||"} [_| |_||_|\n____O__O_[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- |_|| | {"||"} \' | | || |\n (____] |_||_| {"||"} [_| |_||_|\n__O__O___[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n---- |_|| | {"||"} \' | | || |\n____] |_||_| {"||"} [_| |_||_|\nO__O_____[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n-- |_|| | {"||"} \' | | || |\n__] |_||_| {"||"} [_| |_||_|\n_O_______[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |_|| | {"||"} \' | | || |\n] |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]______________/__][_]____________\n4\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |_|| | {"||"} \' | | || |\n |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]______________/__][_]____________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n9\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) {= } . (/\\__) |\n | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n11\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {o o"} |><> | |\n thing in this | (__/\\) {= } . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n6\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} |><> | |\n thing in this | (__/\\) { =} . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n3\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} | <><| |\n thing in this | (__/\\) { =} . (__/\\) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n14\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} | <><| |\n thing in this | (__/\\) { =} . (__/\\) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][__\\__|______________\n9\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} |><> | |\n thing in this | (__/\\) { =} . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n6\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} |><> | |\n thing in this | (__/\\) { =} . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]___|______________\n7\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {o o"} |><> | |\n thing in this | (__/\\) {= } . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]___|______________\n6\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) {= } . (/\\__) |\n | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]___|______________\n1\n | /__\\ #### /__\\ ||\n | | <><| {o o"} |><> | ||\n | (__/\\) {= } . (/\\__) ||\n | / \\ {~~ //~} | / \\ ||\n | ||/(===o {}{ //}{} I || __ |\\\\||\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \'||\n | |_||_| H"||"} [] |_||_| ||\n | [ ][ ] {"||"} [] [ ][ ] ||\n | | || | {"||"} /| | || | ||\n | |_||_| {"||"} \' | |_||_| ||\n________________|__[_][_]_____[_][_]__[_|_/__][_]__||______________\n1\n | /__\\ #### /__\\ | |\n | | <><| {o o"} |><> | | |\n | (__/\\) {= } . (/\\__) | |\n | / \\ {~~ //~} | / \\| |\n | ||/(===o {}{ //}{} I || __ |\\| |\n | | / \\ | {}{// {} I// / \\| | |\n | \\/][][\\/ {}/ {} (I/ [][][] | |\n | |\\ /| {}@@{} ,] |\\ /| | |\n | |_||_| H"||"} [] |_||_| | |\n | [ ][ ] {"||"} [] [ ][ ] | |\n | | || | {"||"} /| | || | | |\n | |_||_| {"||"} \' | |_||_| | |\n________________|__[_][_]_____[_][_]__[_|_/__][_]_|_|______________\n1\n | /__\\ #### /__\\ | |\n | | <><| {o o"} |><> || |\n | (__/\\) {= } . (/\\__)| |\n | / \\ {~~ //~} | / | |\n | ||/(===o {}{ //}{} I || __ || |\n | | / \\ | {}{// {} I// / \\|| |\n | \\/][][\\/ {}/ {} (I/ [][][]| |\n | |\\ /| {}@@{} ,] |\\ /|| |\n | |_||_| H"||"} [] |_||_|| |\n | [ ][ ] {"||"} [] [ ][ ]| |\n | | || | {"||"} /| | || || |\n | |_||_| {"||"} \' | |_||_|| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]|__|______________\n1\n | /__\\ #### /__\\| |\n | | <><| {o o"} |><> | |\n | (__/\\) {= } . (/\\__| |\n | / \\ {~~ //~} | / | |\n | ||/(===o {}{ //}{} I || __ | |\n | | / \\ | {}{// {} I// / \\| |\n | \\/][][\\/ {}/ {} (I/ [][][| |\n | |\\ /| {}@@{} ,] |\\ /| |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ | |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_|___|______________\n1\n | /__\\ #### /__| |\n | | <><| {o o"} |><>| ||\n | (__/\\) {= } . (/\\_| ||\n | / \\ {~~ //~} | / | ||\n | ||/(===o {}{ //}{} I || __| ||\n | | / \\ | {}{// {} I// / | ||\n | \\/][][\\/ {}/ {} (I/ [][]| |\n | |\\ /| {}@@{} ,] |\\ | ||\n | |_||_| H"||"} [] |_||| ||\n | [ ][ ] {"||"} [] [ ][| ||\n | | || | {"||"} /| | ||| ||\n | |_||_| {"||"} \' | |_||| ||\n________________|__[_][_]_____[_][_]__[_|_/__][|____|______________\n1\n | /__\\ #### /_| _|\n | | <><| {o o"} |><| | |\n | (__/\\) {= } . (/\\| | |\n | / \\ {~~ //~} | / | | |\n | ||/(===o {}{ //}{} I || _| | |\n | | / \\ | {}{// {} I// / | |_|\n | \\/][][\\/ {}/ {} (I/ [][| _|\n | |\\ /| {}@@{} ,] |\\ | | |\n | |_||_| H"||"} [] |_|| | |\n | [ ][ ] {"||"} [] [ ]| | |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_|| |_|\n________________|__[_][_]_____[_][_]__[_|_/__]|_____|______________\n1\n | /__\\ #### /| _ |\n | |><> | {o o"} |>| | ||\n | (/\\__) {= } . (/| | ||\n | / \\ {~~ //~} | / | | ||\n | ||/(===o {}{ //}{} I || | | ||\n | | / \\ | {}{// {} I// /| |_||\n | \\/][][\\/ {}/ {} (I/ []| _ |\n | |\\ /| {}@@{} ,] |\\| | ||\n | |_||_| H"||"} [] |_| | ||\n | [ ][ ] {"||"} [] [ | | ||\n | | || | {"||"} /| | | | ||\n | |_||_| {"||"} \' | |_| |_||\n________________|__[_][_]_____[_][_]__[_|_/__|______|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} || | | |\n | (/\\__) {= } . (| | | |\n | / \\ {~~ //~} | / | | | |\n | ||/(===o {}{ //}{} I ||| | | |\n | | / \\ | {}{// {} I// | |_| |\n | \\/][][\\/ {}/ {} (I/ [| _ |\n | |\\ /| {}@@{} ,] || | | |\n | |_||_| H"||"} [] || | | |\n | [ ][ ] {"||"} [] [| | | |\n | | || | {"||"} /| || | | |\n | |_||_| {"||"} \' | || |_| |\n________________|__[_][_]_____[_][_]__[_|_/_|_______|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } . | | | |\n | / \\ {~~ //~} | /| | | |\n | ||/(===o {}{ //}{} I || | | |\n | | / \\ | {}{// {} I//| |_| |\n | \\/][][\\/ {}/ {} (I/ | _ |\n | |\\ /| {}@@{} ,] | | | |\n | |_||_| H"||"} [] | | | |\n | [ ][ ] {"||"} [] | | | |\n | | || | {"||"} /| | | | |\n | |_||_| {"||"} \' | | |_| |\n________________|__[_][_]_____[_][_]__[_|_/|________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } . | | | |\n | / \\ {~~ //~} | | | | |\n | ||/(===o {}{ //}{} I | | | |\n | | / \\ | {}{// {} I/| |_| |\n | \\/][][\\/ {}/ {} (I/| _ |\n | |\\ /| {}@@{} ,] | | | |\n | |_||_| H"||"} [] | | | |\n | [ ][ ] {"||"} [] | | | |\n | | || | {"||"} /| | | | |\n | |_||_| {"||"} \' | | |_| |\n________________|__[_][_]_____[_][_]__[_|_|_________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } .| | | |\n | / \\ {~~ //~} || | | |\n | ||/(===o {}{ //}{} I| | | |\n | | / \\ | {}{// {} I| |_| |\n | \\/][][\\/ {}/ {} (I| _ |\n | |\\ /| {}@@{} ,]| | | |\n | |_||_| H"||"} []| | | |\n | [ ][ ] {"||"} []| | | |\n | | || | {"||"} /|| | | |\n | |_||_| {"||"} \' || |_| |\n________________|__[_][_]_____[_][_]__[_||__________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } | | | |\n | / \\ {~~ //~} | | | |\n | ||/(===o {}{ //}{} | | | |\n | | / \\ | {}{// {} | |_| |\n | \\/][][\\/ {}/ {} (| _ |\n | |\\ /| {}@@{} ,| | | |\n | |_||_| H"||"} [| | | |\n | [ ][ ] {"||"} [| | | |\n | | || | {"||"} /| | | |\n | |_||_| {"||"} \' | |_| |\n________________|__[_][_]_____[_][_]__[_|___________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } | | | |\n | / \\ {~~ //~} | | | |\n | ||/(===o {}{ //}{} | | | |\n | | / \\ | {}{// {} | |_| |\n | \\/][][\\/ {}/ {} | _ |\n | |\\ /| {}@@{} | | | |\n | |_||_| H"||"} | | | |\n | [ ][ ] {"||"} | | | |\n | | || | {"||"} | | | |\n | |_||_| {"||"} \'| |_| |\n________________|__[_][_]_____[_][_]__[|____________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } | | | |\n | / \\ {~~ //~}| | | |\n | ||/(===o {}{ //}{}| | | |\n | | / \\ | {}{// {}| |_| |\n | \\/][][\\/ {}/ {} | _ |\n | |\\ /| {}@@{} | | | |\n | |_||_| H"||"} | | | |\n | [ ][ ] {"||"} | | | |\n | | || | {"||"} | | | |\n | |_||_| {"||"} | |_| |\n________________|__[_][_]_____[_][_]__|_____________|______________\n1\n | /__\\ #### | _ |\n | |><> | {"o o} | | | |\n | (/\\__) { =} | | | |\n | / \\ {~~ //~| | | |\n | ||/(===o {}{ //}{| | | |\n | | / \\ | {}{// {| |_| |\n | \\/][][\\/ {}/ {}| _ |\n | |\\ /| {}@@{} | | | |\n | |_||_| H"||"} | | | |\n | [ ][ ] {"||"} | | | |\n | | || | {"||"} | | | |\n | |_||_| {"||"} | |_| |\n________________|__[_][_]_____[_][_]_|______________|______________\n1\n | /__\\ #### | _ |\n | |><> | {"o o}| | | |\n | (/\\__) { =} | | | |\n | / \\ {~~ //| | | |\n | ||/(===o {}{ //}| | | |\n | | / \\ | {}{// | |_| |\n | \\/][][\\/ {}/ {| _ |\n | |\\ /| {}@@{}| | | |\n | |_||_| H"||"}| | | |\n | [ ][ ] {"||"}| | | |\n | | || | {"||"}| | | |\n | |_||_| {"||"}| |_| |\n________________|__[_][_]_____[_][_]|_______________|______________\n1\n | /__\\ ####| _ |\n | |><> | {"o o| | | |\n | (/\\__) { =}| | | |\n | / \\ {~~ /| | | |\n | ||/(===o {}{ //| | | |\n | | / \\ | {}{// | |_| |\n | \\/][][\\/ {}/ | _ |\n | |\\ /| {}@@{| | | |\n | |_||_| H"||"| | | |\n | [ ][ ] {"||"| | | |\n | | || | {"||"| | | |\n | |_||_| {"||"| |_| |\n________________|__[_][_]_____[_][_|________________|______________\n1\n | /__\\ ###| _ |\n | |><> | {o o| | | |\n | (/\\__) {= | | | |\n | / \\ {~~ | | | |\n | ||/(===o {}{ /| | | |\n | | / \\ | {}{// | |_| |\n | \\/][][\\/ {}/ | _ |\n | |\\ /| {}@@| | | |\n | |_||_| H"||| | | |\n | [ ][ ] {"||| | | |\n | | || | {"||| | | |\n | |_||_| {"||| |_| |\n________________|__[_][_]_____[_][|_________________|______________\n1\n | /__\\ ##| _ |\n | |><> | {o | | | |\n | (/\\__) {=| | | |\n | / \\ {~~ | | | |\n | ||/(===o {}{ | | | |\n | | / \\ | {}{//| |_| |\n | \\/][][\\/ {}/ | _ |\n | |\\ /| {}@| | | |\n | |_||_| H"|| | | |\n | [ ][ ] {"|| | | |\n | | || | {"|| | | |\n | |_||_| {"|| |_| |\n________________|__[_][_]_____[_]|__________________|______________\n1\n | /__\\ #| _ |\n | |><> | {o| | | |\n | (/\\__) {| | | |\n | / \\ {~~ | | | |\n | ||/(===o {}{ | | | |\n | | / \\ | {}{/| |_| |\n | \\/][][\\/ {}/| _ |\n | |\\ /| {}| | | |\n | |_||_| H"| | | |\n | [ ][ ] {"| | | |\n | | || | {"| | | |\n | |_||_| {"| |_| |\n________________|__[_][_]_____[_|___________________|______________\n1\n | /__\\ | _ |\n | |><> | {| | | |\n | (/\\__) | | | |\n | / \\ {~~| | | |\n | ||/(===o {}{| | | |\n | | / \\ | {}{| |_| |\n | \\/][][\\/ {}| _ |\n | |\\ /| {| | | |\n | |_||_| H| | | |\n | [ ][ ] {| | | |\n | | || | {| | | |\n | |_||_| {| |_| |\n________________|__[_][_]_____[|____________________|______________\n1\n | /__\\ | _ |\n | |><> | | | | |\n | (/\\__) | | | |\n | / \\ {~| | | |\n | ||/(===o {}| | | |\n | | / \\ | {}| |_| |\n | \\/][][\\/ {| _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]_____|_____________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\ {| | | |\n | ||/(===o {| | | |\n | | / \\ | {| |_| |\n | \\/][][\\/ | _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]____|______________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\ | | | |\n | ||/(===o | | | |\n | | / \\ | | |_| |\n | \\/][][\\/ | _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]___|_______________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\ | | | |\n | ||/(===o | | | |\n | | / \\ | | |_| |\n | \\/][][\\/ | _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]__|________________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\| | | |\n | ||/(===o| | | |\n | | / \\ || |_| |\n | \\/][][\\/| _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]_|_________________________|______________\n1\n | /__\\ | _ |\n | | <><|| | | |\n | (__/\\)| | | |\n | / | | | |\n | ||/(===| | | |\n | | / \\ | |_| |\n | \\/][][\\| _ |\n | |\\ /|| | | |\n | |_||_|| | | |\n | [ ][ ]| | | |\n | | || || | | |\n | |_||_|| |_| |\n________________|__[_][_]|__________________________|______________\n1\n | /__\\| _ |\n | | <><| | | |\n | (__/\\| | | |\n | / | | | |\n | ||/(==| | | |\n | | / \\| |_| |\n | \\/][][| _ |\n | |\\ /| | | |\n | |_||_| | | |\n | [ ][ | | | |\n | | || | | | |\n | |_||_| |_| |\n________________|__[_][_|___________________________|______________\n1\n | /__| _ |\n | | <>| | | |\n | (__/| | | |\n | / | | | |\n | ||/(=| | | |\n | | / | |_| |\n | \\/][]| _ |\n | |\\ | | | |\n | |_||| | | |\n | [ ][| | | |\n | | ||| | | |\n | |_||| |_| |\n________________|__[_][|____________________________|______________\n1\n | /_| _ |\n | | <| | | |\n | (__| | | |\n | / | | | |\n | ||/(| | | |\n | | / | |_| |\n | \\/][| _ |\n | |\\ | | | |\n | |_|| | | |\n | [ ]| | | |\n | | || | | |\n | |_|| |_| |\n________________|__[_]|_____________________________|______________\n1\n | /| _ |\n | | | | | |\n | (_| | | |\n | / | | | |\n | ||/| | | |\n | | /| |_| |\n | \\/]| _ |\n | |\\| | | |\n | |_| | | |\n | [ | | | |\n | | | | | |\n | |_| |_| |\n________________|__[_|______________________________|______________\n1\n | | _ |\n | || | | |\n | (| | | |\n | / | | | |\n | ||| | | |\n | | | |_| |\n | \\/| _ |\n | || | | |\n | || | | |\n | [| | | |\n | || | | |\n | || |_| |\n________________|__[|_______________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | /| | | |\n | || | | |\n | || |_| |\n | \\| _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|__|________________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|_|_________________________________|______________\n1\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n________________||__________________________________|______________\n1\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n________________|___________________________________|______________\n2\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n________________|___________________________________|______________\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n________________|___________________________________|______________\n1\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n________________||__________________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|_|_________________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | /| | | |\n | || | | |\n | || |_| |\n | \\| _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|__|________________________________|______________\n1\n | | _ |\n | || | | |\n | (| | | |\n | / | | | |\n | ||| | | |\n | ||| |_| |\n | \\[| _ |\n | || | | |\n | || | | |\n | [| | | |\n | || | | |\n | || |_| |\n________________|__[|_______________________________|______________\n1\n | /| _ |\n | | | | | |\n | (_| | | |\n | / -| | | |\n | ||O| | | |\n | ||-| |_| |\n | \\[(| _ |\n | |\\| | | |\n | | | | | |\n | [ | | | |\n | | | | | |\n | | | |_| |\n________________|__[_|______________________________|______________\n1\n | /_| _ |\n | | | | | |\n | (__| | | |\n | / --| | | |\n | ||O!| | | |\n | ||--| |_| |\n | \\[(_| _ |\n | |\\ | | | |\n | | || | | |\n | [ ]| | | |\n | | || | | |\n | | || |_| |\n________________|__[_]|_____________________________|______________\n1\n | /__| _ |\n | | | | | |\n | (___| | | |\n | / ---| | | |\n | ||O!L| | | |\n | ||---| |_| |\n | \\[(_(| _ |\n | |\\ | | | |\n | | ||| | | |\n | [ ][| | | |\n | | ||| | | |\n | | ||| |_| |\n________________|__[_][|____________________________|______________\n1\n | /__\\| _ |\n | | | | | |\n | (____| | | |\n | / ----| | | |\n | ||O!L|| | | |\n | ||----| |_| |\n | \\[(_()| _ |\n | |\\ /| | | |\n | | || | | | |\n | [ ][ | | | |\n | | || | | | |\n | | || | |_| |\n________________|__[_][_|___________________________|______________\n1\n | /__\\ | _ |\n | | || | | |\n | (____)| | | |\n | / ---- | | | |\n | ||O!L||| | | |\n | ||----|| |_| |\n | \\[(_()]| _ |\n | |\\ /|| | | |\n | | || || | | |\n | [ ][ ]| | | |\n | | || || | | |\n | | || || |_| |\n________________|__[_][__|__________________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) | | | |\n | / ---- \\| | | |\n | ||O!L|||| | | |\n | ||----|\\| |_| |\n | \\[(_()] | _ |\n | |\\ /| | | | |\n | | || | | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | | || | | |_| |\n________________|__[_][__\\|_________________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) | | | |\n | / ---- \\ | | | |\n | ||O!L||| | | | |\n | ||----|\\\\| |_| |\n | \\[(_()] \\| _ |\n | |\\ /| | | | |\n | | || | | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | | || | | |_| |\n________________|__[_][__\\_|________________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) .| | | |\n | / ---- \\ || | | |\n | ||O!L||| I| | | |\n | ||----|\\\\I| |_| |\n | \\[(_()] \\I| _ |\n | |\\ /| [| | | |\n | | || | [| | | |\n | [ ][ ] [| | | |\n | | || | || | | |\n | | || | || |_| |\n________________|__[_][__\\_||_______________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | | | | |\n | ||O!L||| I | | | |\n | ||----|\\\\I | |_| |\n | \\[(_()] \\I)| _ |\n | |\\ /| [,| | | |\n | | || | []| | | |\n | [ ][ ] []| | | |\n | | || | |\\| | | |\n | | || | | | |_| |\n________________|__[_][__\\_|_|______________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | | | | |\n | ||O!L||| I | | | |\n | ||----|\\\\I | |_| |\n | \\[(_()] \\I) | _ |\n | |\\ /| [, | | | |\n | | || | [] | | | |\n | [ ][ ] [] | | | |\n | | || | |\\ | | | |\n | | || | | \'| |_| |\n________________|__[_][__\\_|_]|_____________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | {| | | |\n | ||O!L||| I {| | | |\n | ||----|\\\\I {| |_| |\n | \\[(_()] \\I) | _ |\n | |\\ /| [, | | | |\n | | || | [] | | | |\n | [ ][ ] [] | | | |\n | | || | |\\ | | | |\n | | || | | \' | |_| |\n________________|__[_][__\\_|_]_|____________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | {~| | | |\n | ||O!L||| I {}| | | |\n | ||----|\\\\I {}| |_| |\n | \\[(_()] \\I) {| _ |\n | |\\ /| [, | | | |\n | | || | [] | | | |\n | [ ][ ] [] | | | |\n | | || | |\\ | | | |\n | | || | | \' | |_| |\n________________|__[_][__\\_|_]__|___________________|______________\n1\n | /__\\ | _ |\n | | | {| | | |\n | (____) . | | | |\n | / ---- \\ | {~\\| | | |\n | ||O!L||| I {}{| | | |\n | ||----|\\\\I {}{| |_| |\n | \\[(_()] \\I) {}| _ |\n | |\\ /| [, {| | | |\n | | || | [] {| | | |\n | [ ][ ] [] {| | | |\n | | || | |\\ {| | | |\n | | || | | \' {| |_| |\n________________|__[_][__\\_|_]__[|__________________|______________\n1\n | /__\\ #| _ |\n | | | {"| | | |\n | (____) . {| | | |\n | / ---- \\ | {~\\\\| | | |\n | ||O!L||| I {}{\\| | | |\n | ||----|\\\\I {}{~| |_| |\n | \\[(_()] \\I) {}~| _ |\n | |\\ /| [, {~| | | |\n | | || | [] {"| | | |\n | [ ][ ] [] {"| | | |\n | | || | |\\ {"| | | |\n | | || | | \' {"| |_| |\n________________|__[_][__\\_|_]__[_|_________________|______________\n1\n | /__\\ ##| _ |\n | | | {""| | | |\n | (____) . {"| | | |\n | / ---- \\ | {~\\\\~| | | |\n | ||O!L||| I {}{\\\\| | | |\n | ||----|\\\\I {}{~\\| |_| |\n | \\[(_()] \\I) {}~~| _ |\n | |\\ /| [, {~~| | | |\n | | || | [] {"|| | | |\n | [ ][ ] [] {"|| | | |\n | | || | |\\ {"|| | | |\n | | || | | \' {"|| |_| |\n________________|__[_][__\\_|_]__[_]|________________|______________\n1\n | /__\\ ###| _ |\n | | | {"""| | | |\n | (____) . {""| | | |\n | / ---- \\ | {~\\\\~~| | | |\n | ||O!L||| I {}{\\\\~| | | |\n | ||----|\\\\I {}{~\\\\| |_| |\n | \\[(_()] \\I) {}~~\\| _ |\n | |\\ /| [, {~~~| | | |\n | | || | [] {"||| | | |\n | [ ][ ] [] {"||| | | |\n | | || | |\\ {"||| | | |\n | | || | | \' {"||| |_| |\n________________|__[_][__\\_|_]__[_][|_______________|______________\n1\n | /__\\ ####| _ |\n | | | {""""| | | |\n | (____) . {""}| | | |\n | / ---- \\ | {~\\\\~~~| | | |\n | ||O!L||| I {}{\\\\~~| | | |\n | ||----|\\\\I {}{~\\\\~| |_| |\n | \\[(_()] \\I) {}~~\\\\| _ |\n | |\\ /| [, {~~~\\| | | |\n | | || | [] {"||"| | | |\n | [ ][ ] [] {"||"| | | |\n | | || | |\\ {"||"| | | |\n | | || | | \' {"||"| |_| |\n________________|__[_][__\\_|_]__[_][_|______________|______________\n1\n | /__\\ #### | _ |\n | | | {""""}| | | |\n | (____) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~| | | |\n | ||O!L||| I {}{\\\\~~~| | | |\n | ||----|\\\\I {}{~\\\\~~| |_| |\n | \\[(_()] \\I) {}~~\\\\{| _ |\n | |\\ /| [, {~~~\\}| | | |\n | | || | [] {"||"}| | | |\n | [ ][ ] [] {"||"}| | | |\n | | || | |\\ {"||"}| | | |\n | | || | | \' {"||"}| |_| |\n________________|__[_][__\\_|_]__[_][_]|_____________|______________\n1\n | /__\\ #### | _ |\n | | | {""""} | | | |\n | (____) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~| | | |\n | ||O!L||| I {}{\\\\~~~{| | | |\n | ||----|\\\\I {}{~\\\\~~{| |_| |\n | \\[(_()] \\I) {}~~\\\\{}| _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]_|____________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~}| | | |\n | ||O!L||| I {}{\\\\~~~{}| | | |\n | ||----|\\\\I {}{~\\\\~~{}| |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]__|___________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} | | | |\n | ||O!L||| I {}{\\\\~~~{} | | | |\n | ||----|\\\\I {}{~\\\\~~{} | |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]___|__________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} | | | |\n | ||O!L||| I {}{\\\\~~~{} | | | |\n | ||----|\\\\I {}{~\\\\~~{} | |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]____|_________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} | | | |\n | ||O!L||| I {}{\\\\~~~{} /| | | |\n | ||----|\\\\I {}{~\\\\~~{} \\| |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]_____|________|______________\n1\n | /__\\ #### | _ |\n | | | {""""} | | | |\n | (____) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} /| | | |\n | ||O!L||| I {}{\\\\~~~{} / | | | |\n | ||----|\\\\I {}{~\\\\~~{} \\\\| |_| |\n | \\[(_()] \\I) {}~~\\\\{} \\| _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]______|_______|______________\n1\n | /__\\ #### | _ |\n | | | {""""} || | | |\n | (____) . {""} (| | | |\n | / ---- \\ | {~\\\\~~~~~} / | | | |\n | ||O!L||| I {}{\\\\~~~{} / || | | |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|| |_| |\n | \\[(_()] \\I) {}~~\\\\{} \\[| _ |\n | |\\ /| [, {~~~\\} || | | |\n | | || | [] {"||"} || | | |\n | [ ][ ] [] {"||"} [| | | |\n | | || | |\\ {"||"} || | | |\n | | || | | \' {"||"} || |_| |\n________________|__[_][__\\_|_]__[_][_]______[|______|______________\n1\n | /__\\ #### /| _ |\n | | | {""""} | | | ||\n | (____) . {""} (_| | ||\n | / ---- \\ | {~\\\\~~~~~} / -| | ||\n | ||O!L||| I {}{\\\\~~~{} / |O| | ||\n | ||----|\\\\I {}{~\\\\~~{} \\\\|-| |_||\n | \\[(_()] \\I) {}~~\\\\{} \\[(| _ |\n | |\\ /| [, {~~~\\} |\\| | ||\n | | || | [] {"||"} | | | ||\n | [ ][ ] [] {"||"} [ | | ||\n | | || | |\\ {"||"} | | | ||\n | | || | | \' {"||"} | | |_||\n________________|__[_][__\\_|_]__[_][_]______[_|_____|______________\n1\n | /__\\ #### /_| _|\n | | | {""""} | | | |\n | (____) . {""} (__| | |\n | / ---- \\ | {~\\\\~~~~~} / --| | |\n | ||O!L||| I {}{\\\\~~~{} / |O!| | |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|--| |_|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_| _|\n | |\\ /| [, {~~~\\} |\\ | | |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ]| | |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || |_|\n________________|__[_][__\\_|_]__[_][_]______[_]|____|______________\n1\n | /__\\ #### /__| |\n | | | {""""} | | ||\n | (____) . {""} (___| ||\n | / ---- \\ | {~\\\\~~~~~} / ---| ||\n | ||O!L||| I {}{\\\\~~~{} / |O!L| ||\n | ||----|\\\\I {}{~\\\\~~{} \\\\|---| ||\n | \\[(_()] \\I) {}~~\\\\{} \\[(_(| |\n | |\\ /| [, {~~~\\} |\\ | ||\n | | || | [] {"||"} | ||| ||\n | [ ][ ] [] {"||"} [ ][| ||\n | | || | |\\ {"||"} | ||| ||\n | | || | | \' {"||"} | ||| ||\n________________|__[_][__\\_|_]__[_][_]______[_][|___|______________\n1\n | /__\\ #### /__\\| |\n | | | {""""} | | |\n | (____) . {""} (____| |\n | / ---- \\ | {~\\\\~~~~~} / ----| |\n | ||O!L||| I {}{\\\\~~~{} / |O!L|| |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----| |\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()| |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ | |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_|__|______________\n1\n | /__\\ #### /__\\ | |\n | | | {""""} | || |\n | (____) . {""} (____)| |\n | / ---- \\ | {~\\\\~~~~~} / ---- | |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||| |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|| |\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]| |\n | |\\ /| [, {~~~\\} |\\ /|| |\n | | || | [] {"||"} | || || |\n | [ ][ ] [] {"||"} [ ][ ]| |\n | | || | |\\ {"||"} | || || |\n | | || | | \' {"||"} | || || |\n________________|__[_][__\\_|_]__[_][_]______[_][_]|_|______________\n1\n | /__\\ #### /__\\ ||\n | | | {""""} | | ||\n | (____) . {""} (____) ||\n | / ---- \\ | {~\\\\~~~~~} / ---- \\||\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\||\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|/||\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/||\n | |\\ /| [, {~~~\\} |\\ /| ||\n | | || | [] {"||"} | || | ||\n | [ ][ ] [] {"||"} [ ][ ] ||\n | | || | |\\ {"||"} | || | ||\n | | || | | \' {"||"} | || | ||\n________________|__[_][__\\_|_]__[_][_]______[_][_]_||______________\n1\n | /__\\ #### /__\\ |\n | | | {""""} | | |\n | (____) . {""} (____) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n2\n | /__\\ #### /__\\ |\n | | <><| {""""} | | |\n | (__/\\) . {""} (____) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n1\n | /__\\ #### /__\\ |\n | | <><| {o o"} | | |\n | (__/\\) . {= } (____) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n4\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) . {= } (/\\__) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n4\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) . {= } (/\\__) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} //|O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} || |----|//|\n | \\[(_()] \\I) {}~~\\\\{} # [(_()]/ |\n | |\\ /| [, {~~~\\} [ |\\ /| |\n | | || | [] {"||"} [ | || | |\n | [ ][ ] [] {"||"} \' [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) @@@ [....] [|\n [)______________________[___|||__\\__/___[|\n6\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) @ @@ [....] [|\n [)______________________[__|_||__\\__/___[|\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n | /__\\ #### /__\\ |\n | | <><| {"o o} | <><| |\n | . (__/\\) { =} (__/\\) |\n | | / \\ {~~ //~} / \\ |\n | I | __ | {}{ //}{} ||/(===o |\n | I// / \\ | {}{// {} | / \\|| |\n |(I/ /][][\\| {}/ {} \\[][][] |\n |,] |\\ /|# {}@@{} |\\ /| |\n |[] |_||_| H"||"} |_||_| |\n |[] [ ][ ] {"||"} [ ][ ] |\n |/| | || | {"||"} | || | |\n | | |_||_| {"||"} |_||_| |\n________________|_|__[_][_]_____[_][_]______[_][_]__|______________\n3\n | /__\\ #### /__\\ |\n | | <><| {o o"} | <><| |\n | . (__/\\) {= } (__/\\) |\n | | / \\ {~~ //~} / \\ |\n | I | __ | {}{ //}{} ||/(===o |\n | I// / \\ | {}{// {} | / \\|| |\n |(I/ /][][\\| {}/ {} \\[][][] |\n |,] |\\ /|# {}@@{} |\\ /| |\n |[] |_||_| H"||"} |_||_| |\n |[] [ ][ ] {"||"} [ ][ ] |\n |/| | || | {"||"} | || | |\n | | |_||_| {"||"} |_||_| |\n________________|_|__[_][_]_____[_][_]______[_][_]__|______________\n13\n | /__\\ #### /__\\ |\n | | <><| {"o o} | <><| |\n | . (__/\\) { =} (__/\\) |\n | | / \\ {~~ //~} / \\ |\n | I | __ | {}{ //}{} ||/(===o |\n | I// / \\ | {}{// {} | / \\|| |\n |(I/ /][][\\| {}/ {} \\[][][] |\n |,] |\\ /|# {}@@{} |\\ /| |\n |[] |_||_| H"||"} |_||_| |\n |[] [ ][ ] {"||"} [ ][ ] |\n |/| | || | {"||"} | || | |\n | | |_||_| {"||"} |_||_| |\n________________|_|__[_][_]_____[_][_]______[_][_]__|______________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) @ @@ [....] [|\n [)______________________[__|_||__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)o @ @@ [....] [|\n [)|_____________________[__|_||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o @ @@ [....] [|\n [)_|____________________[__|_||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)# o @ @@ [....] [|\n [)|_|___________________[__|_||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o @ @@ [....] [|\n [)_|_|__________________[__|_||__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)o # o @ @@ [....] [|\n [)|_|_|_________________[__|_||__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)o # o @ @@ [....] [|\n [)|_|_|_________________[_|__||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)_|_|_|________________[_|__||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)__|_|_|_______________[_|__||__\\__/___[|\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n30\n\n\n Where are you taking\n this... thing?\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n32\n\n\n Prisoner transfer from\n cell block 1138.\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n12\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n4\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|______________[_|_|_|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @@ @ [....] [|\n [)___|_|_|______________[_||__|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ [....] [|\n [)___|_|_|______________[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @@ @ [....] [|\n [)___|_|_|______________[||___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|______________[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|_____________|[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|____________|_[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|___________|__[_|___|__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|__________|___[_|___|__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|_________|____[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|________|_____[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|________|_____[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|_______|______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o #o @ @ @ [....] [|\n [)___|__||_______|______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o #o @ @ @ [....] [|\n [)___|__||______|_______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # @ @ @ [....] [|\n [)___|___|______|_______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # @ @ @ [....] [|\n [)___|___|_____|________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o# @ @ @ [....] [|\n [)___|___||____|________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o# @ @ @ [....] [|\n [)___|___||___|_________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)___|___|_|__|_________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)___|___|_|_|__________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)____|__|_|_|__________[_|___|__\\__/___[|\n3\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o #@ @ @ [....] [|\n [)____|__|_||___________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o #@ @ @ [....] [|\n [)____|__|_|/___________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)____|__|_|/___________[_|___|__\\__/___[|\n2\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ [....] [|\n [)____|__|_|/-@_________[_|___|__\\__/___[|\n5\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)_____|_|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)_____|_|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) oo # - @ @ [....] [|\n [)______||_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) -oo # - @ @ [....] [|\n [)______||_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - o # - @ @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - o # - @ @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - oo# - @ @ [....] [|\n [)_______|||--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - oo# -@ @ [....] [|\n [)_______|||--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)- o # * @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [* o # * @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [). / \\ [|\n [), o #o @ @ [....] [|\n [)_______|_||-@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) . / \\ [|\n [) o #o @ @ [....] [|\n [)_,_____|_||-@_________[_/___|__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ [....] [|\n [)_______|_|-|@_________[_/-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o-# o @ [....] [|\n [)_______|_|--|_________[_/-@|___\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ [....] [|\n [)_______|_|--|_________[_/-@|___\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o #- o @ [....] [|\n [)_______|_|--@|________[_/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # - o @ [....] [|\n [)_______|_|--@|________[_/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # - o @ [....] [|\n [)_______|_|--@_|_______[_/|@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # -o @ [....] [|\n [)_______|_|--@_|_______[_/|@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o- @ [....] [|\n [)_______|_|--@_|_______[_|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - @ [....] [|\n [)_______|_|--@_|_______[_|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - .@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - @ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - .@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - @ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o -.@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o -@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o .* [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o * [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o .@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ [....] [|\n [)_______|_|--@_|_______[//-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . @ [....] [|\n [)_______|_|--@_|_______[//-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)_______|_|--@_|_______[/@-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)_______|_|--@_|_______[/@-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)_______|_|--@_|_______[/@-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)_______|__|-@__|______[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)________|_|-@__|______[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)________|_-|@___|_____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)_________|-|@___|_____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)_________|--|____|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________|-|____|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)__________|-@|____|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________-|@|____|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)__________-|@_|____|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--|_|____|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)__________--|__|____|_[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@|_|____|_[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o. [....] [|\n [)__________--@|__|____|[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@_|_|____|[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@_|__|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@__|_|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # .o [....] [|\n [)__________--@__|__|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@___|_|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # . o [....] [|\n [)__________--@___|__|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@____|_|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # . o [....] [|\n [)__________--@____|_|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o# o [....] [|\n [)__________--@_____||__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o# . o [....] [|\n [)__________--@_____||__[/@/@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o [....] [|\n [)__________--@______|__[/@/@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #o o [....] [|\n [)__________--@______||_[/|-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #o . o [....] [|\n [)__________--@______||_[/|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@______|_|[/|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o. o [....] [|\n [)__________--@______|_|[/|-@____\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # .oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@_______|_[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o o [....] [|\n [)__________--@_______|_[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@________|[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #. o o [....] [|\n [)__________--@________|[/|-@_|__\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o[....] [|\n [)__________--@_________[/|-@__|_\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #o o[....] [|\n [)__________--@_________[/|-@__|_\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) .#o o....] [|\n [)__________--@_________[/|-@___|\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o....] [|\n [)__________--@_________[/|-@___|\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o [o...] [|\n [)__________--@_________[/|-@____|__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o# [o...] [|\n [)__________--@_________[/|-@____|__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o# [.o..] [|\n [)__________--@_________[/|-@____\\|_/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [.o..] [|\n [)__________--@_________[/|-@____\\|_/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / o\\ [|\n [) . o # [..|.] [|\n [)__________--@_________[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / o\\ [|\n [) o # [..|.] [|\n [)__________--@_________[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n ===- ####\n o o" {o o"}\n _\\- /_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n ===- Everything is under ####\n o o"" control. Situation {o o"}\n _\\- /_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n4\n ===- ####\n o o"" {o o"}\n _\\- /_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n ===- ####\n o o"" What\'s your operating {o o"}\n _\\- /_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n ===- Who is this? ####\n o o"" What\'s your operating {o o"}\n _\\- /_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ * / | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ \\\\| __ |-\\\\ * / | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\- * / | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ __*___ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ ***/ | {} {// } {}I\n | \\ [(_()] #) */ | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ * {~~ //~} |\n _______//|O!L||\\\\ _***__ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ **** | {} {// } {}I\n | \\ [(_()] #)*** | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ , **" {~~ //~} |\n _______//|O!L||\\\\ _****_. {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ *****| {} {// } {}I\n | \\ [(_()] #)****.| {} // } {}I\n \\ \\_____|\\__/|_____*` / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ , " {= } .\n / __ \\ .***. {~~ //~} |\n _______//|O!L||\\\\ ****** {{~{ //}~~ I\n | \\ \\\\| __ | \\\\******| {} {// } {}I\n | \\ [(_()] #)*****| {} // } {}I\n \\ \\_____|\\__/|____*** /. {} H{{}}} ,I}\n | | | || | | |, @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ " {= } .\n / __ \\. * . {~~ //~} |\n _______//|O!L||\\\\__****_ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ **** | {} {// } {}I\n | \\ [(_()] #) ** | {} // } {}I\n \\ \\_____|\\__/|____ * / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | . {"||"} []\n | | | || | | |, {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ " {= } .\n / __ \\ . {~~ //~} |\n _______//|O!L||\\\\___**__ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ %**/ | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|____ / / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | . {"||"} | |\n_______\\_|____[_][__\\___|_/__,_____________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ " {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | . @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,_____._______________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | . @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | . {"||"} | |\n_______\\_|____[_][__\\___|_/__,_____________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / " {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | . {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,________.____________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | " {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,_________.___________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | " {"||"} | |\n_______\\_|____[_][__\\___|_/__,__________.__________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,__________"._________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | " {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | " {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.__"_____[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.___,____[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.____,___[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n3\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n19\n -=== ####\n ""o o Boring conversation {o o"}\n _\\ -/_ anyway! {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n8\n -=== ####\n ""o o Boring conversation {"o o}\n _\\ -/_ anyway! { =} .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n1\n -=== ####\n ""o o Boring conversation {o o"}\n _\\ -/_ anyway! {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n1\n\n\n\n\n\n\n\n\n\n\n\n\n* *\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n / /__\\ \\\n / | <><| \\\n / (__/\\) \\\n | / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n11\n / /__\\ \\\n / Luke! We\'re | <><| \\\n / going to have (__/\\) \\\n | company! / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n18\n / /__\\ \\\n / Luke! We\'re |><> | \\\n / going to have (/\\__) \\\n | company! / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n5\n / /__\\ \\\n / |><> | \\\n / (/\\__) \\\n | / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n / \\ ===,\n | | @- -@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n______|_____________|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @- -@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n______|\\___________/|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @- -@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n |\\___________/| ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n |\\___________/| / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n |\\___________/| | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n |\\___________/| | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n |\\___________/| @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n |\\___________/| \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n |\\___________/| /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n |\\___________/| / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n |\\___________/| /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n |\\___________/| \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n |\\___________/| @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n /___________\\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n7\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n11\n / / \\ \\ ===,\n | | <><| | Aren\'t you a little @o o@)\n | (__/\\) | short for a \\- /\n | / \\ | Stormtrooper? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n15\n / / \\ \\ ===,\n | | <><| | Aren\'t you a little @o o@)\n | (__/\\) | short for a \\- /\n | / \\ | Stormtrooper? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @| | |@\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | | <><| | Aren\'t you a little @o o@)\n | (__/\\) | short for a \\- /\n | / \\ | Stormtrooper? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n17\n / / \\ \\ ===,\n | | <><| | Oh, the uniform. @o o@)\n | (__/\\) | \\- /\n | / \\ | I\'m Luke Skywalker. /~~ ~~\\\n | ||/(===o | I\'m here to / ( ) \\\n | | / \\ | | rescue you! /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n15\n / / \\ \\ ===,\n | | <><| | Oh, the uniform. @o o@)\n | (__/\\) | \\- /\n | / \\ | I\'m Luke Skywalker. /~~ ~~\\\n | ||/(===o | I\'m here to / ( ) \\\n | | / \\ | | rescue you! /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n2\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n24\n / / \\ \\ ===,\n | | <><| | You\'re who? @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n2\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n16\n / / \\ \\ ===,\n | | <><| | I\'m with Ben Kenobi! @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n5\n / / \\ \\ ===,\n | |><> | | I\'m with Ben Kenobi! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | |><> | | I\'m with Ben Kenobi! @O O@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | |><> | | @O O@)\n | (/\\__) | \\O /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | |><> | | Ben Kenobi! @o o@)\n | (/\\__) | \\- /\n | / \\ | Where is he? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n23\n / / \\ \\ ===,\n | | <><| | Ben Kenobi! @o o@)\n | (__/\\) | \\- /\n | / \\ | Where is he? /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n9\n / / \\ \\ ===,\n | | <><| | Come on! @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n2\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][_]___|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | || \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][_]___|___________________________/__)(_)____________\n8\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | || \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|___/__][_]___|___________________________/__)(_)____________\n6\n / / \\ \\ ===,\n | |><> | | @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | || \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|___/__][_]___|___________________________/__)(_)____________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n4\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ 0/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\- /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n 0 0\')\n __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n3\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\o /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n5\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n6\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n _\\o /__ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n (\'0 0\n __\\ -/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n10\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n7\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n5\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n4\n """"\n Never gonna to 0 0\')\n make you cry... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n9\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n4\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n8\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n11\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__]_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n3\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ 0/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\- /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n 0 0\')\n __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n3\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\o /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n5\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n6\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n _\\o /__ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n (\'0 0\n __\\ -/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n10\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n7\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n5\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n4\n """"\n Never gonna to 0 0\')\n make you cry... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n9\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n4\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n8\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n11\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__]_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n3\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n48\n\n\n\n\n To be continued.\n\n Simon Jansen (C) 1997 - 2008\n\n www.asciimation.co.nz\n\n\n\n\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n˙\n' - -local function iterator() - return coroutine.wrap( function() - for line in string.gmatch( filmText, "([^\n]*)\n") do - coroutine.yield(line) - end - return false - end ) -end - -term.clear() -local it = iterator() - -local bFinished = false -while not bFinished do - -- Read the frame header - local holdLine = it() - if not holdLine then - bFinished = true - break - end - - -- Get this every frame incase the monitor resizes - local w,h = term.getSize() - local startX = math.floor( (w - 65) / 2 ) - local startY = math.floor( (h - 14) / 2 ) - - -- Print the frame - term.clear() - for n=1,13 do - local line = it() - if line then - term.setCursorPos(startX, startY + n) - term.write( line ) - else - bFinished = true - break - end - end - - -- Hold the frame - local hold = tonumber(holdLine) or 1 - local delay = (hold * 0.05) - 0.01 - sleep( delay ) -end diff --git a/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua b/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua deleted file mode 100644 index c43fd6d4a..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/deprecated/GopherAtl/talk/talk.lua +++ /dev/null @@ -1 +0,0 @@ -print( "\"talk\" was removed in ComputerCraft 1.6, use the builtin \"chat\" program instead!" ) diff --git a/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua b/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua deleted file mode 100644 index bd88cee1d..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/fredthead/protector/protector.lua +++ /dev/null @@ -1,1311 +0,0 @@ -function initVariables() - w,h =term.getSize() -- 51, 19 - shipYPos = 10 - shipXPos = 24 - shipFacingRight=true - pressedKey=0 - killedState = false - lives=3 - score =0 - aliens=10 - killedDelay=0 - running=true - moveLeft=false - moveRight=true - moveUp=false - moveDown=false - human1x = 3 - human1y = 18 - human2x = 15 - human2y = 18 - human3x = 40 - human3y = 18 - human4x = 60 - human4y = 18 - human5x = 70 - human5y = 18 - human6x = 85 - human6y = 18 - human1 = true - human2 = true - human3 = true - human4 = true - human5 = true - human6 = true - human1Abducted=false - human2Abducted=false - human3Abducted=false - human4Abducted=false - human5Abducted=false - human6Abducted=false - humansLeft=6 - bulletXPos=0 - bulletYPos=0 - bulletState=false - bulletGoingRight=true - alien1 = false - alien1y = 2 - alien1x =84 - alien1Abduct=false - alien1Carry=false - alien1Step=2 - stepValue=0.1 --0.1 -end - -function clear() - term.clear() - term.setCursorPos(1,1) - term.setBackgroundColour(colours.black) - term.setTextColour(colours.white) -end - -function drawGrass() - term.setCursorPos(1,h) - term.setBackgroundColour(colours.green) - write(string.rep(" ",w)) - term.setCursorPos(1,1) - term.setBackgroundColour(colours.black) -end - -function drawShip(yPos) - if shipFacingRight==true then - term.setCursorPos(24,yPos) - term.setBackgroundColour(colours.orange) - print(" ") - term.setCursorPos(25,yPos) - term.setBackgroundColour(colours.white) - print(" ") - else - term.setCursorPos(26,yPos) - term.setBackgroundColour(colours.orange) - print(" ") - term.setCursorPos(24,yPos) - term.setBackgroundColour(colours.white) - print(" ") - end - term.setBackgroundColour(colours.black) -end - -function delShip(yPos) - term.setCursorPos(24,yPos) - term.setBackgroundColour(colours.black) - print(" ") -end - -function drawAliens() - term.setBackgroundColour(colours.cyan) - if alien1==true then - term.setCursorPos(alien1x,alien1y) - write(" ") - end - term.setBackgroundColour(colours.black) -end - -function delAliens() - term.setBackgroundColour(colours.black) - if alien1==true then - term.setCursorPos(alien1x,alien1y) - write(" ") - end -end - -function drawHumans() - term.setBackgroundColour(colours.pink) - if human1==true then - term.setCursorPos(human1x,human1y) - write(" ") - end - if human2==true then - term.setCursorPos(human2x,human2y) - write(" ") - end - if human3==true then - term.setCursorPos(human3x,human3y) - write(" ") - end - if human4==true then - term.setCursorPos(human4x,human4y) - write(" ") - end - if human5==true then - term.setCursorPos(human5x,human5y) - write(" ") - end - if human6==true then - term.setCursorPos(human6x,human6y) - write(" ") - end - term.setBackgroundColour(colours.green) - term.setCursorPos(1,19) - write(" ") - term.setBackgroundColour(colours.black) -end - -function delHumans() - term.setBackgroundColour(colours.black) - if human1==true then - term.setCursorPos(human1x,human1y) - write(" ") - end - if human2==true then - term.setCursorPos(human2x,human2y) - write(" ") - end - if human3==true then - term.setCursorPos(human3x,human3y) - write(" ") - end - if human4==true then - term.setCursorPos(human4x,human4y) - write(" ") - end - if human5==true then - term.setCursorPos(human5x,human5y) - write(" ") - end - if human6==true then - term.setCursorPos(human6x,human6y) - write(" ") - end -end - -function drawBullet() - term.setBackgroundColour(colours.yellow) - term.setCursorPos(bulletXPos,bulletYPos) - write(" ") - term.setBackgroundColour(colours.black) -end - -function delBullet() - term.setBackgroundColour(colours.black) - term.setCursorPos(bulletXPos,bulletYPos) - write(" ") -end - -function newHighScoreTable() - name1="Dan" score1=1000 - name2="Fred" score2=800 - name3="Fred" score3=600 - name4="Fred" score4=400 - name5="Fred" score5=200 - local highScoreTable = {{name1, score1}, {name2,score2}, {name3,score3}, {name4,score4}, {name5,score5}} - local newHighScoreStr = textutils.serialize(highScoreTable) - --print("new table "..newHighScoreStr)-- debug - fs.makeDir("protectordata") - local handle = fs.open("protectordata/pdata","w") - handle.write(newHighScoreStr) - handle.close() -end - -function printCent(xpos,text) - local ypos = w/2 - (string.len(text)/2) - term.setCursorPos(ypos,xpos) - write(text) -end - -function introHighScoreTable() - term.clear() - term.setCursorPos(35,1) write("SPACE WHEN READY") - if fs.exists("protectordata")==false then - newHighScoreTable() - end - local handle = fs.open("protectordata/pdata","r") - local dataStr = handle.readAll() - handle.close() - --print("dataStr "..dataStr) - highScoreData = textutils.unserialize(dataStr) - --print(highScoreData[2]) - name1 = highScoreData[1][1] score1 = highScoreData[1][2] - name2 = highScoreData[2][1] score2 = highScoreData[2][2] - name3 = highScoreData[3][1] score3 = highScoreData[3][2] - name4 = highScoreData[4][1] score4 = highScoreData[4][2] - name5 = highScoreData[5][1] score5 = highScoreData[5][2] - term.setTextColour(colours.yellow) - printCent(5,"HIGH SCORES") - term.setTextColour(colours.white) - printCent(7,name1.." "..score1) - printCent(8,name2.." "..score2) - printCent(9,name3.." "..score3) - printCent(10,name4.." "..score4) - printCent(11,name5.." "..score5) -end - - -function printScore() - term.clear() - term.setTextColour(colours.yellow) - printCent(3,"HIGH SCORES") - term.setTextColour(colours.white) - printCent(5,name1.." "..score1) - printCent(6,name2.." "..score2) - printCent(7,name3.." "..score3) - printCent(8,name4.." "..score4) - printCent(9,name5.." "..score5) - playAgain() -end - -function rewriteScores() - if newScore > score1 then - name5=name4 score5=score4 - name4=name3 score4=score3 - name3=name2 score3=score2 - name2=name1 score2=score1 - name1= newName score1=newScore - elseif newScore > score2 then - name5=name4 score5=score4 - name4=name3 score4=score3 - name3=name2 score3=score2 - name2=newName score2=newScore - elseif newScore > score3 then - name5=name4 score5=score4 - name4=name3 score4=score3 - name3=newName score3=newScore - elseif newScore > score4 then - name5=name4 score5=score4 - name4=newName score4=newScore - elseif newScore > score5 then - name5=newName score5=newScore - end - local highScoreTable = {{name1, score1}, {name2,score2}, {name3,score3}, {name4,score4}, {name5,score5}} - local newHighScoreStr = textutils.serialize(highScoreTable) - local handle = fs.open("protectordata/pdata","w") - handle.write(newHighScoreStr) - handle.close() -end - -function newHighScoreObtained() - clear() - term.setTextColour(colours.yellow) - printCent(8,"CONGRATULATIONS") - term.setTextColour(colours.white) - printCent(10,"You have a new high score!") - printCent(12,"Enter your name: ") - printCent(14," ") - local newNameStr = "" - local newNameStrLen = 0 - while true do - local event,p1,p2,p3 = os.pullEvent() - if event=="char" and newNameStrLen < 9 then - newNameStr=newNameStr..p1 - newNameStrLen=newNameStrLen+1 - printCent(14,newNameStr.." ") - - elseif event=="key" and p1 == 14 and newNameStrLen>0 then - newNameStr=string.sub(newNameStr,1,string.len(newNameStr)-1) - newNameStrLen=newNameStrLen-1 - term.setCursorPos(1,14) - write(string.rep(" ",w)) - printCent(14,newNameStr.." ") - elseif event=="key" and p1== 28 then - newName = newNameStr - newScore = score - rewriteScores() - printScore() - end - end - - - -end - -function highScore() - if fs.exists("protectordata")==false then - newHighScoreTable() - end - local handle = fs.open("protectordata/pdata","r") - local dataStr = handle.readAll() - handle.close() - --print("dataStr "..dataStr) - highScoreData = textutils.unserialize(dataStr) - --print(highScoreData[2]) - name1 = highScoreData[1][1] score1 = highScoreData[1][2] - name2 = highScoreData[2][1] score2 = highScoreData[2][2] - name3 = highScoreData[3][1] score3 = highScoreData[3][2] - name4 = highScoreData[4][1] score4 = highScoreData[4][2] - name5 = highScoreData[5][1] score5 = highScoreData[5][2] - if score>score5 then - newHighScoreObtained() - end - printScore() - - -end - - - - -function gameOver(gameOverMsg) - clear() - delShip(shipYPos) - term.setCursorPos(40,1) - write("Lives: "..lives.." ") - term.setCursorPos(5,1) - if score<0 then score=0 end - write("Score: "..score.." ") - term.setTextColour(colours.red) - term.setCursorPos( (w/2)-5 , h/2 -1) - print("GAME OVER") - term.setCursorPos( (w/2)-(string.len(gameOverMsg)/2) , (h/2)+1) - print(gameOverMsg) - term.setTextColour(colours.white) - running=false - sleep(1.5) - highScore()-- new - --playAgain -end - -function playAgain() - sleep(1) - printCent(12,"Play again (Y or N)") - - while true do - local event,p1,p2,p3 = os.pullEvent() - if event=="char" then - if string.lower(p1)=="y" then - runGame() - elseif string.lower(p1)=="n" then - os.shutdown() - end - end - end - -end - -function killPlayer() - moveLeft=false - moveRight=false - moveUp=false - moveDown=false - delShip(shipYPos) - lives=lives-1 - if lives==0 then - gameOver("OUT OF LIVES") - end - killedState=true - --killedStr="true" -end - -function left() - delHumans() - delAliens() - human1x=human1x+1 - human2x=human2x+1 - human3x=human3x+1 - human4x=human4x+1 - human5x=human5x+1 - human6x=human6x+1 - alien1x=alien1x+1 - if human1x>100 then human1x=0 end - if human2x>100 then human2x=0 end - if human3x>100 then human3x=0 end - if human4x>100 then human4x=0 end - if human5x>100 then human5x=0 end - if human6x>100 then human6x=0 end - if alien1x>100 then alien1x=0 end - shipFacingRight=false - checkShipCollision() - drawShip(shipYPos) - drawHumans() - drawAliens() - drawBorder() - moveRight=false -end - -function right() - delHumans() - delAliens() - human1x=human1x-1 - human2x=human2x-1 - human3x=human3x-1 - human4x=human4x-1 - human5x=human5x-1 - human6x=human6x-1 - alien1x=alien1x-1 - if human1x<1 then human1x=100 end - if human2x<1 then human2x=100 end - if human3x<1 then human3x=100 end - if human4x<1 then human4x=100 end - if human5x<1 then human5x=100 end - if human6x<1 then human6x=100 end - if alien1x<1 then alien1x=100 end - shipFacingRight=true - checkShipCollision() - drawShip(shipYPos) - drawHumans() - drawAliens() - drawBorder() - moveLeft=false -end - -function up() - if shipYPos > 2 then - delShip(shipYPos) - shipYPos=shipYPos-1 - checkShipCollision() - drawShip(shipYPos) - end - moveUp=false - moveDown=false -end - -function down() - if shipYPos<17 then - delShip(shipYPos) - shipYPos=shipYPos+1 - checkShipCollision() - drawShip(shipYPos) - end - moveDown=false - moveUp=false -end - -function checkShipCollision() - if killedState==false then - if shipYPos == alien1y and alien1== true then - if alien1x >= 22 and alien1x <= 26 then - alien1Hit() - killPlayer() - end - elseif human1==true and human1y==shipYPos then - if human1x >=24 and human1x <= 26 then - human1=false - humanHitRoutine() - end - elseif human2==true and human2y==shipYPos then - if human2x >=24 and human2x <= 26 then - human2=false - humanHitRoutine() - end - elseif human3==true and human3y==shipYPos then - if human3x >=24 and human3x <= 26 then - human3=false - humanHitRoutine() - end - elseif human4==true and human4y==shipYPos then - if human4x >=24 and human4x <= 26 then - human4=false - humanHitRoutine() - end - elseif human5==true and human5y==shipYPos then - if human5x >=24 and human5x <= 26 then - human5=false - humanHitRoutine() - end - elseif human6==true and human6y==shipYPos then - if human6x >=24 and human6x <= 26 then - human6=false - humanHitRoutine() - end - end - end -end - -function alienGen() - if alien1==false then - local alienChance= math.random(1,10) - if alienChance==1 then - if human1==true then - alien1 = true - alien1y = 2 - alien1x = human1x - 1 - end - elseif alienChance == 2 then - if human2==true then - alien1 = true - alien1y=2 - alien1x = human2x-1 - end - elseif alienChance == 3 then - if human3==true then - alien1 = true - alien1y=2 - alien1x = human3x-1 - end - elseif alienChance == 4 then - if human4==true then - alien1 = true - alien1y=2 - alien1x = human4x-1 - end - elseif alienChance == 5 then - if human5==true then - alien1 = true - alien1y=2 - alien1x = human5x-1 - end - elseif alienChance == 6 then - if human6==true then - alien1 = true - alien1y=2 - alien1x = human6x-1 - end - end - end -end - -function alienDown() - if alien1==true and alien1Abduct==false and alien1y<19 then - alien1Step=alien1Step+stepValue - alien1y=math.floor(alien1Step) - if alien1==true and alien1Abduct==false and alien1y==17 then - alien1Abduct=true - alien1Carry=true - alien1Step=17 - end - end -end - -function alienRoutine() - alien1=false - alien1Step=2 - if alien1Carry==true then - score= score -50 - humansLeft=humansLeft-1 - end - alien1Abduct=false - alien1Carry=false - if humansLeft==0 then - gameOver("NO HUMANS LEFT") - end - -end - -function alienUp() - if alien1==true and alien1Abduct==true then - if alien1x+1 == human1x then - human1Abducted=true - alien1Step=alien1Step-stepValue - alien1y=math.floor(alien1Step) - human1y=math.floor(alien1Step)+1 - human1x=alien1x+1 - if human1y<=2 then - alienRoutine() - human1=false - end - elseif alien1x+1 == human2x then - human2Abducted=true - alien1Step=alien1Step-stepValue - alien1y=math.floor(alien1Step) - human2y=math.floor(alien1Step)+1 - human2x=alien1x+1 - if human2y<=2 then - alienRoutine() - human2=false - end - elseif alien1x+1 == human3x then - human3Abducted=true - alien1Step=alien1Step-stepValue - alien1y=math.floor(alien1Step) - human3y=math.floor(alien1Step)+1 - human3x=alien1x+1 - if human3y<=2 then - alienRoutine() - human3=false - end - elseif alien1x+1 == human4x then - human4Abducted=true - alien1Step=alien1Step-stepValue - alien1y=math.floor(alien1Step) - human4y=math.floor(alien1Step)+1 - human4x=alien1x+1 - if human4y<=2 then - alienRoutine() - human4=false - end - elseif alien1x+1 == human5x then - human5Abducted=true - alien1Step=alien1Step-stepValue - alien1y=math.floor(alien1Step) - human5y=math.floor(alien1Step)+1 - human5x=alien1x+1 - if human5y<=2 then - alienRoutine() - human5=false - end - elseif alien1x+1 == human6x then - human6Abducted=true - alien1Step=alien1Step-stepValue - alien1y=math.floor(alien1Step) - human6y=math.floor(alien1Step)+1 - human6x=alien1x+1 - if human6y<=2 then - alienRoutine() - human6=false - end - end - end - if alien1==false then alienGen() end -end - -function keyPress() -- 200 UP, 208 DOWN, 203 LEFT, 205 RIGHT, 57 SPACE, 16 Q - if pressedKey==200 or pressedKey == 17 then -- up - moveUp=true - moveDown=false - elseif pressedKey==208 or pressedKey == 31 then -- DOWN - moveDown=true - moveUp=false - elseif pressedKey==203 or pressedKey == 30 then -- left - moveLeft=true - moveRight=false - elseif pressedKey==205 or pressedKey == 32 then -- right - moveRight=true - moveLeft=false - elseif pressedKey==57 then -- space - if bulletState==false then - bulletYPos=shipYPos - bulletState=true - if shipFacingRight==true then - bulletXPos=shipXPos+3 - bulletGoingRight=true - else - bulletXPos=shipXPos-1 - bulletGoingRight=false - end - end - elseif pressedKey==25 then -- q (use 25 if p for quit) - gameOver("YOU QUIT") - end - - --term.setCursorPos(30,1) - --write(pressedKey.." ") -end - -function removeBullet() - if bulletGoingRight==true then - bulletXPos = 60 - else - bulletXPos = -10 - end -end - -function alien1Hit() - delAliens() - alien1=false - score=score+20 - alien1Step=2 - alien1Abduct=false - removeBullet() - drawAliens() -end - -function humanHitRoutine() - score=score-50 - humansLeft=humansLeft-1 - if humansLeft==0 then - gameOver("NO HUMANS LEFT") - end - if alien1Carry==true then alien1Carry=false end -end - - -function checkBulletCollision() - if alien1 == true and bulletYPos == alien1y then - if bulletXPos >= alien1x and bulletXPos <= alien1x + 3 then - alien1Hit() - end - end - if human1 == true and bulletYPos == human1y and bulletXPos == human1x then human1=false humanHitRoutine() end - if human2 == true and bulletYPos == human2y and bulletXPos == human2x then human2=false humanHitRoutine() end - if human3 == true and bulletYPos == human3y and bulletXPos == human3x then human3=false humanHitRoutine() end - if human4 == true and bulletYPos == human4y and bulletXPos == human4x then human4=false humanHitRoutine() end - if human5 == true and bulletYPos == human5y and bulletXPos == human5x then human5=false humanHitRoutine() end - if human6 == true and bulletYPos == human6y and bulletXPos == human6x then human6=false humanHitRoutine() end -end - -function drawBorder() - term.setBackgroundColour(colours.black) - for i=1,h-2 do - term.setCursorPos(1,i+1) - write(" ") - term.setCursorPos(w,i+1) - write(" ") - end -end - -function dropHumans() - if alien1Abduct==false then - if human1y<18 then human1y = human1y+1 end - if human2y<18 then human2y = human2y+1 end - if human3y<18 then human3y = human3y+1 end - if human4y<18 then human4y = human4y+1 end - if human5y<18 then human5y = human5y+1 end - if human6y<18 then human6y = human6y+1 end - end -end - - -function gameControl() - - gameTimer=os.startTimer(0.1) - - while running do - local event,p1,p2,p3 = os.pullEvent() - if score<0 then score=0 end - term.setCursorPos(1,1) - term.setBackgroundColour(colours.yellow) - write(string.rep(" ",w)) - - - term.setTextColour(colours.red) - term.setCursorPos(5,1) - write("Score: "..score.." ") - term.setCursorPos(20,1) - write("Humans Left: "..humansLeft.." ") - term.setCursorPos(40,1) - write("Lives: "..lives.." ") - - term.setBackgroundColour(colours.black) - term.setTextColour(colours.white) - - local newStepValue = (score+0.1)/1000 - if newStepValue > stepValue then stepValue= newStepValue end - if stepValue>0.4 then stepValue=0.4 end - - - --[[DEBUG - term.setCursorPos(2,2) - write("human1x "..human1x.." ") - term.setCursorPos(2,3) - write("human2x "..human2x.." ") - term.setCursorPos(2,4) - write("human3x "..human3x.." ") - term.setCursorPos(2,5) - write("human4x "..human4x.." ") - term.setCursorPos(2,6) - write("human5x "..human5x.." ") - term.setCursorPos(2,7) - write("human6x "..human6x.." ") - ]]-- - - - if event=="timer" and gameTimer == p1 then - if killedState==true then - delShip(shipYPos) - delHumans() - dropHumans() - drawHumans() - killedDelay = killedDelay + 1 - if killedDelay>20 then - shipYPos = 10 - killedState = false - term.setBackgroundColour(colours.black) - for i = 2, h-2 do - term.setCursorPos(1,i) - write(string.rep(" ",w)) - end - drawGrass() - if shipFacingRight==true then - moveRight=true - moveLeft=false - else - moveLeft=true - moveRight=false - end - killedDelay=0 - end - else - - --alienGen() - drawShip(shipYPos) - delAliens() - - delHumans() - dropHumans() - alienDown() - alienUp() - drawAliens() - drawHumans() - drawBorder() - end - - if bulletState==true then - if bulletGoingRight==true then - delBullet() - bulletXPos=bulletXPos+1 - checkBulletCollision() - if bulletXPos>45 then - bulletState=false - else - if killedState==false then drawBullet() end - end - else - delBullet() - bulletXPos=bulletXPos-1 - checkBulletCollision() - if bulletXPos<6 then - bulletState=false - else - if killedState==false then drawBullet() end - end - end - end - - if moveLeft==true then - left() - end - if moveRight==true then - right() - end - if moveUp==true then - up() - end - if moveDown==true then - down() - end - - gameTimer=os.startTimer(0.1) - - elseif event=="key" and killedState==false then - pressedKey=p1 - keyPress() - end - - end - -end - -function runGame() - initVariables() - clear() - drawGrass() - drawHumans() - alienGen() - gameControl() -end - - -function pix(xCo,yCo,text,col) - if col== nil then term.setBackgroundColour(colours.black) - elseif col =="white" then term.setBackgroundColour(colours.white) - elseif col =="green" then term.setBackgroundColour(colours.green) - elseif col =="pink" then term.setBackgroundColour(colours.pink) - elseif col =="orange" then term.setBackgroundColour(colours.orange) - elseif col =="cyan" then term.setBackgroundColour(colours.cyan) - elseif col =="yellow" then term.setBackgroundColour(colours.yellow) - end - term.setCursorPos(xCo,yCo) - write(text) -end - -function drawHumanPix() - drawGrass() - pix(23,humanPixY," ","pink") - pix(27,humanPixY," ","pink") - pix(24,humanPixY-1," ","pink") - pix(26,humanPixY-1," ","pink") - pix(25,humanPixY-2," ","pink") - pix(23,humanPixY-3," ","pink") - pix(25,humanPixY-4," ","pink") - pix(24,humanPixY-5," ","pink") - pix(24,humanPixY-6," ","pink") -end - -function delHumanPix() - pix(23,humanPixY," ") - pix(27,humanPixY," ") - pix(24,humanPixY-1," ") - pix(26,humanPixY-1," ") - pix(25,humanPixY-2," ") - pix(23,humanPixY-3," ") - pix(25,humanPixY-4," ") - pix(24,humanPixY-5," ") - pix(24,humanPixY-6," ") -end - -function drawAlienPix() - pix(19,alienPixY," ","cyan") - pix(17,alienPixY+1," ","cyan") - pix(19,alienPixY+2," ","cyan") -end - -function delAlienPix() - pix(19,alienPixY," ") - pix(17,alienPixY+1," ") - pix(19,alienPixY+2," ") -end - -function drawShipPix() - pix(shipPixX+3,3," ","white") - pix(shipPixX+3,4," ","white") - pix(shipPixX+3,5," ","white") - pix(shipPixX+3,6," ","white") - pix(shipPixX+3,7," ","white") - pix(shipPixX+2,5," ","orange") - pix(shipPixX+2,6," ","yellow") - pix(shipPixX+2,7," ","orange") - pix(shipPixX,6," ","orange") - pix(shipPixX+14,5," ","cyan") -end - -function delShipPix() - pix(shipPixX+3,3," ") - pix(shipPixX+3,4," ") - pix(shipPixX+3,5," ") - pix(shipPixX+3,6," ") - pix(shipPixX+3,7," ") - pix(shipPixX+2,5," ") - pix(shipPixX+2,6," ") - pix(shipPixX+2,7," ") - pix(shipPixX,6," ") - pix(shipPixX+14,5," ") -end - -function line1() - pix(8,4," ","white") - pix(12,4," ","white") - pix(16,4," ","white") - pix(20,4," ","white") - pix(24,4," ","white") - pix(28,4," ","white") - pix(32,4," ","white") - pix(36,4," ","white") - pix(40,4," ","white") -end - -function line2() - pix(8,5," ","white") - pix(10,5," ","white") - pix(12,5," ","white") - pix(14,5," ","white") - pix(16,5," ","white") - pix(18,5," ","white") - pix(21,5," ","white") - pix(24,5," ","white") - pix(28,5," ","white") - pix(33,5," ","white") - pix(36,5," ","white") - pix(38,5," ","white") - pix(40,5," ","white") - pix(42,5," ","white") - -end - -function line3() - pix(8,6," ","white") - pix(12,6," ","white") - pix(16,6," ","white") - pix(18,6," ","white") - pix(21,6," ","white") - pix(24,6," ","white") - pix(28,6," ","white") - pix(33,6," ","white") - pix(36,6," ","white") - pix(38,6," ","white") - pix(40,6," ","white") -end - -function line4() - pix(8,7," ","white") - pix(12,7," ","white") - pix(16,7," ","white") - pix(18,7," ","white") - pix(21,7," ","white") - pix(24,7," ","white") - pix(28,7," ","white") - pix(33,7," ","white") - pix(36,7," ","white") - pix(38,7," ","white") - pix(40,7," ","white") -end - -function line5() - pix(8,8," ","white") - pix(12,8," ","white") - pix(14,8," ","white") - pix(16,8," ","white") - pix(21,8," ","white") - pix(24,8," ","white") - pix(28,8," ","white") - pix(33,8," ","white") - pix(36,8," ","white") - pix(40,8," ","white") - pix(42,8," ","white") -end - - -function startScreen() - - clear() - term.setBackgroundColour(colours.green) - term.setCursorPos(1,h) - write(string.rep(" ",w)) - local screenStage=0 - - screenTimer=os.startTimer(0.1) - while true do - local event,p1,p2,p3=os.pullEvent() - if event=="key"and p1==57 then - term.setBackgroundColour(colours.black) - clear() - runGame() - elseif event=="timer" and screenTimer == p1 then - - --term.setCursorPos(1,1) write("screenStage: "..screenStage.." ") - - term.setBackgroundColour(colours.black) - term.setCursorPos(35,1) write("SPACE WHEN READY") - - if screenStage>0 and screenStage<0.5 then - humanPixY = 18 - drawHumanPix() - elseif screenStage>2 and screenStage<2.9 then - alienPixY = -2 - drawAlienPix() - elseif screenStage>3 and screenStage<3.9 then - alienPixY = -2 - delAlienPix() - alienPixY = -1 - drawAlienPix() - elseif screenStage>4 and screenStage<4.9 then - alienPixY = -1 - delAlienPix() - alienPixY = 0 - drawAlienPix() - elseif screenStage>5 and screenStage<5.9 then - alienPixY = 0 - delAlienPix() - alienPixY = 1 - drawAlienPix() - elseif screenStage>6 and screenStage<6.9 then - alienPixY = 1 - delAlienPix() - alienPixY = 2 - drawAlienPix() - elseif screenStage>7 and screenStage<7.9 then - alienPixY = 2 - delAlienPix() - alienPixY = 3 - drawAlienPix() - elseif screenStage>8 and screenStage<8.9 then - alienPixY = 3 - delAlienPix() - alienPixY = 4 - drawAlienPix() - elseif screenStage>8 and screenStage<9.9 then - alienPixY = 4 - delAlienPix() - alienPixY = 5 - drawAlienPix() - elseif screenStage>10 and screenStage<10.4 then - pix(25,8," ","yellow") - pix(25,9," ","yellow") - pix(25,10," ","yellow") - pix(25,11," ","yellow") - pix(25,17," ","yellow") - pix(25,18," ","yellow") - elseif screenStage>10.4 and screenStage<10.6 then - pix(25,8," ","yellow") - pix(25,9," ","yellow") - pix(25,10," ","yellow") - pix(24,11," ","yellow") - pix(24,12," ","yellow") - pix(24,13," ","yellow") - pix(24,14," ","yellow") - pix(23,15," ","yellow") - pix(23,16," ","yellow") - pix(23,17," ","yellow") - pix(23,18," ","yellow") - humanPixY = 18 - drawHumanPix() - elseif screenStage>10.6 and screenStage<10.8 then - pix(25,8," ","yellow") - pix(25,9," ","yellow") - pix(24,10," ","yellow") - pix(24,11," ","yellow") - pix(24,12," ","yellow") - pix(23,13," ","yellow") - pix(23,14," ","yellow") - pix(23,15," ","yellow") - pix(22,16," ","yellow") - pix(22,17," ","yellow") - pix(22,18," ","yellow") - humanPixY = 18 - drawHumanPix() - elseif screenStage>10.8 and screenStage<11 then - pix(25,8," ","yellow") - pix(24,9," ","yellow") - pix(24,10," ","yellow") - pix(23,11," ","yellow") - pix(23,12," ","yellow") - pix(22,13," ","yellow") - pix(22,14," ","yellow") - pix(21,15," ","yellow") - pix(21,16," ","yellow") - pix(20,17," ","yellow") - pix(20,18," ","yellow") - humanPixY = 18 - drawHumanPix() - elseif screenStage>11.9 and screenStage<12 then - pix(1,6," ","yellow") - elseif screenStage>12 and screenStage<12.1 then - pix(1,6," ") - pix(3,6," ","yellow") - elseif screenStage>12.1 and screenStage<12.2 then - pix(3,6," ") - pix(5,6," ","yellow") - elseif screenStage>12.2 and screenStage<12.3 then - pix(5,6," ") - pix(7,6," ","yellow") - elseif screenStage>12.3 and screenStage<12.4 then - pix(7,6," ") - pix(9,6," ","yellow") - elseif screenStage>12.4 and screenStage<12.5 then - pix(9,6," ") - pix(11,6," ","yellow") - elseif screenStage>12.5 and screenStage<12.6 then - pix(11,6," ") - pix(13,6," ","yellow") - elseif screenStage>12.6 and screenStage<12.7 then - pix(13,6," ") - pix(15,6," ","yellow") - elseif screenStage>12.7 and screenStage<12.8 then - term.setBackgroundColour(colours.black) - for i= 5, h-1 do - term.setCursorPos(15,i) - write(" ") - end - humanPixY=18 - drawHumanPix() - elseif screenStage>13 and screenStage<13.1 then - shipPixX= -16 - drawShipPix() - elseif screenStage>13 and screenStage<13.1 then - delShipPix() - shipPixX= -15 - drawShipPix() - elseif screenStage>13.1 and screenStage<13.2 then - delShipPix() - shipPixX= -12 - drawShipPix() - elseif screenStage>13.2 and screenStage<13.3 then - delShipPix() - shipPixX= -9 - drawShipPix() - elseif screenStage>13.2 and screenStage<13.3 then - delShipPix() - shipPixX= -6 - drawShipPix() - elseif screenStage>13.3 and screenStage<13.4 then - delShipPix() - shipPixX= -3 - drawShipPix() - elseif screenStage>13.4 and screenStage<13.5 then - delShipPix() - shipPixX= 0 - drawShipPix() - elseif screenStage>13.6 and screenStage<13.7 then - delShipPix() - shipPixX= 3 - drawShipPix() - elseif screenStage>13.8 and screenStage<13.9 then - delShipPix() - shipPixX= 6 - drawShipPix() - elseif screenStage>13.9 and screenStage<14 then - delShipPix() - shipPixX= 9 - drawShipPix() - elseif screenStage>14.1 and screenStage<14.2 then - delShipPix() - shipPixX= 12 - drawShipPix() - elseif screenStage>14.2 and screenStage<14.3 then - delShipPix() - shipPixX= 15 - drawShipPix() - elseif screenStage>14.3 and screenStage<14.4 then - delShipPix() - shipPixX= 18 - drawShipPix() - elseif screenStage>14.4 and screenStage<14.5 then - delShipPix() - shipPixX= 21 - drawShipPix() - elseif screenStage>14.5 and screenStage<14.6 then - delShipPix() - shipPixX= 24 - drawShipPix() - elseif screenStage>14.6 and screenStage<14.7 then - delShipPix() - shipPixX= 27 - drawShipPix() - elseif screenStage>14.7 and screenStage<14.8 then - delShipPix() - shipPixX= 30 - drawShipPix() - elseif screenStage>14.8 and screenStage<14.9 then - delShipPix() - shipPixX= 33 - drawShipPix() - elseif screenStage>14.9 and screenStage<15 then - delShipPix() - shipPixX= 36 - drawShipPix() - elseif screenStage>15 and screenStage<15.1 then - delShipPix() - shipPixX= 39 - drawShipPix() - elseif screenStage>15.1 and screenStage<15.2 then - delShipPix() - shipPixX= 41 - drawShipPix() - elseif screenStage>15.2 and screenStage<15.3 then - delShipPix() - shipPixX= 44 - drawShipPix() - elseif screenStage>15.3 and screenStage<15.4 then - delShipPix() - shipPixX= 47 - drawShipPix() - elseif screenStage>15.4 and screenStage<15.5 then - delShipPix() - shipPixX= 50 - drawShipPix() - elseif screenStage>15.5 and screenStage<15.6 then - delShipPix() - elseif screenStage>16 and screenStage<16.9 then - humanPixY=18 - delHumanPix() - line1() - line2() - line3() - line4() - line5() - elseif screenStage>17 and screenStage<22 then - term.setCursorPos((w/2)-6,10) - write("by FredTHead") - term.setCursorPos((w/2)-13,12) - write("WSAD or arrow keys to move") - term.setCursorPos((w/2)-6,13) - write("SPACE to fire") - term.setCursorPos((w/2)-4,14) - write("P to quit") - term.setCursorPos((w/2)-8,16) - write("Fire when ready") - elseif screenStage>22.1 and screenStage <27 then - introHighScoreTable() - elseif screenStage>27 then - term.setBackgroundColour(colours.black) - for i = 2,h-1 do - term.setCursorPos(1,i) - write(string.rep(" ",w-1)) - end - screenStage=0 - end - - screenStage=screenStage+0.1 - screenTimer=os.startTimer(0.025) - end - end -end - -w,h =term.getSize() -if term.isColour() and w==51 then - initVariables() - startScreen() -else - term.clear() - term.setCursorPos(1,1) - print("I'm sorry, Protector requires an Advanced Computer to run") - print(" ") -end diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua deleted file mode 100644 index b75a5ca79..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/goldrunner.lua +++ /dev/null @@ -1,1314 +0,0 @@ ---[[ - Gold Runner - Inspired by the game by Doug Smith - - Written by: Nitrogen Fingers -]]-- - -w,h = term.getSize() -if not term.isColour() then - printError("Requires an Advanced Computer") - return -end - - -running = true -started = false -nextLevel = false - -inLevelSelect = false -inLevelEditor = false -local levelEditName = nil -local hexnums = { [10] = "a", [11] = "b", [12] = "c", [13] = "d", [14] = "e" , [15] = "f" } - -titleLoaded = false -local menSel = "none" -local titleOptions = { "New Game", "Select Level", "Create Level", "Quit" } -local inGameOptions = { "Restart", "Edit Level", "Back to Title", "Quit" } -local levelEditOptions = { "Save", "Play Level", "Save and Exit", "Discard and Exit" } -local menIndex = 1 - -local maxnamelen = 14 - -local drawOffsetX = 1 -local drawOffsetY = 0 - -local map = {} -local goldMap = {} -local blockTimers = {} -local blockIntv = 5 - -local monks = {} -local monkTimer = -1 -local monkSpawnIntv = 3 -local monkTrapIntv = blockIntv/2 - -local goldCount = 0 -local maxGoldCount = 0 -local playerLives = 3 -local playerScore = 0 -local plspawnX = 0 -local plspawnY = 0 - -local plX = 0 -local plY = 0 -local pfalling = false -local moveTimer = -1 -local shootTimer = -1 -local spawnTimer = -1 -local moveIntv = 0.15 - -local exX = 0 -local exY = 0 - -local levelList = {} -local currentLevel = 1 -local levelLot = 1 - -local titleLevel = { - " "; - " dddddddddddc "; - " 4 c "; - " 4 4 c "; - " bbbbbbc bcbbbb "; - " b 4 b c c "; - " bbbbb c 4 dd 0 4 c 4 "; - " bbcb bbb bbbbc "; - " c c "; - " c ddd c eb"; - " dddddc bcb cbbbbb"; - " c c c bbbb"; - "b4 c 4c bb44b"; - "bbb c 4 e bbbcbbbbbbbbbbbbb"; - "bbbbbbbbbbbbbbc 4 cbbbbb 4 bbbb"; - "bbbbbbfff44fbbc 4 cbbbbbbb cbbbbbbb bbbbb"; - "bbbbffffbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 4 bbbbbbb"; - "bbbffbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb5 bbbbbbbbb"; -} - -local function parseValue(x, y, lchar) -if tonumber(lchar, 16) then - lchar = math.pow(2, tonumber(lchar,16)) - - if lchar == colours.blue then - map[y][x] = 0 - elseif lchar == colours.brown then - map[y][x] = 'H' - elseif lchar == colours.yellow then - goldMap[y][x] = 1 - goldCount = goldCount + 1 - elseif lchar == colours.orange then - map[y][x] = 'V' - elseif lchar == colours.green then - map[y][x] = '-' - elseif lchar == colours.lightGrey then - map[y][x] = 'h' - elseif lchar == colours.grey then - map[y][x] = '#' - elseif lchar == colours.white then - plX = x - plspawnX = x - plY = y - plspawnY = y - elseif lchar == colours.lime then - exX = x - exY = y - elseif lchar == colours.red then - table.insert(monks, { - --X and Y, clear enough - x = x, y = y; - --Where they spawn when they die - spawnX = x, spawnY = y; - -- Any gold they're carring- it's a 1 in 5 - gold = false; - -- Whether or not they're falling - falling = false; - -- Timer if they're dead to respawn - dead = nil; - --Whether or not the monk has just spawned - justSpawned = true; - --Whether or not the monk has just escaped - justEscaped = false; - -- Current aim- it's "up", "down", "across" or "none" - behaviour = "none"; - -- The desired x position to travel to, when one is necessary. - desX = nil; - -- The escape timer - trapped = nil; - }) - end - end -end - -local function loadMap(_sPath) - if not fs.exists(_sPath) then return false end - map = {} - goldMap = {} - monks = {} - goldCount = 0 - - local file = fs.open(_sPath, "r") - local line = file:readLine() - while line do - goldMap[#map+1] = {} - map[#map+1] = {} - for i=1,math.min(#line,49) do - local lchar = string.sub(line,i,i) - parseValue(i, #map, lchar) - end - if #map == 18 then break end - line = file:readLine() - end - file:close() - maxGoldCount = goldCount - titleLoaded = false - return true -end - ---When something moves or something needs to be drawn, we ---just change the appropriate tile with this method. -local function updateMap(x,y) - term.setCursorPos(x + drawOffsetX, y + drawOffsetY) - term.setBackgroundColour(colours.black) - if plX == x and plY == y and map[y][x] ~= 0 then - term.setTextColour(colours.white) - if map[y][x] == 1 then term.setBackgroundColour(colours.lightBlue) - elseif map[y][x] == "V" then term.setBackgroundColour(colours.blue) end - term.write("&") - elseif map[y][x] == 'H' then - term.setTextColour(colours.brown) - term.write("H") - --Level Editor stuff - elseif map[y][x] == 'h' and (goldCount == 0 or inLevelEditor) then - if inLevelEditor then term.setTextColour(colours.lightGrey) - else term.setTextColour(colours.brown) end - term.write("H") - elseif map[y][x] == '&' and inLevelEditor then - term.setTextColour(colours.pink) - term.write('&') - elseif map[y][x] == 'V' then - term.setBackgroundColour(colours.blue) - if inLevelEditor then - term.setTextColour(colours.orange) - term.write("V") - else - term.write(" ") - end - elseif map[y][x] == '-' then - term.setTextColour(colours.brown) - term.write(map[y][x]) - elseif map[y][x] == '#' then - term.setBackgroundColour(colours.grey) - term.write(" ") - elseif type(map[y][x]) == "number" then - local uchar = ' ' - if map[y][x] == 3 then - term.setBackgroundColour(colours.lightBlue) - elseif map[y][x] == 2 and goldMap[y][x] == 1 then - term.setTextColour(colours.yellow) - uchar = '$' - elseif map[y][x] == 1 then - term.setBackgroundColour(colours.lightBlue) - elseif map[y][x] == 0 then - term.setBackgroundColour(colours.blue) - end - term.write(uchar) - elseif goldMap[y][x] == 1 then - term.setTextColour(colours.yellow) - term.write("$") - elseif exX == x and exY == y and (goldCount == 0 or inLevelEditor) then - term.setTextColour(colours.lime) - term.write("@") - else - term.write(" ") - end -end - ---It's silly to iterate through all monks when drawing tiles, so ---we do it separately. -local function drawMonk(monk) - term.setCursorPos(monk.x + drawOffsetX, monk.y + drawOffsetY) - if monk.justSpawned then term.setTextColour(colours.pink) - else term.setTextColour(colours.red) end - if map[monk.y][monk.x] == 1 then term.setBackgroundColour(colours.lightBlue) - elseif map[monk.y][monk.x] == "V" then term.setBackgroundColour(colours.blue) - else term.setBackgroundColour(colours.black) end - term.write("&") -end - ---Draws the map for the first time. It barely changes, so we really ---only call this the once. -local function drawMap() - term.setBackgroundColour(colours.black) - term.clear() - for y=1,#map do - for x=1,49 do - updateMap(x,y) - end - end - for _,monk in pairs(monks) do drawMonk(monk)end -end - ---When all coins have been collected, we add in invisble ladders and ---the end game portal. -local function drawEndgameMap() - for y=1,#map do - for x=1,49 do - if map[y][x] == 'h' or (exX == x and exY == y) then - updateMap(x,y) - end - end - end -end - ---Sets the map back to defaults, so we can start afresh -local function resetMap() - goldCount = maxGoldCount - for i=1,#goldMap do - for j=1,49 do - if goldMap[i][j] == 0 then goldMap[i][j] = 1 end - end - end - for _,monk in pairs(monks) do - monk.justSpawned = true - monk.dead = nil - monk.trapped = nil - monk.justEscaped = false - monk.falling = false - monk.behaviour = "none" - monk.x = monk.spawnX - monk.y = monk.spawnY - end - - for _,timer in pairs(blockTimers) do - map[timer.y][timer.x] = 0 - end - blockTimers = {} - plX = plspawnX - plY = plspawnY - - moveTimer = -1 - shootTimer = -1 - spawnTimer = -1 - monkTimer = -1 - pfalling = false -end - ---Draws the HUD. This also rarely changes, so we update it when something happens. -local function drawHUD() - term.setCursorPos(2,19) - term.setBackgroundColour(colours.black) - term.clearLine() - term.setTextColour(colours.blue) - term.write("Score: ") - term.setTextColour(colours.yellow) - term.write(string.rep("0", 5-math.floor(math.log(playerScore + 1,10))) - ..playerScore) - term.setTextColour(colours.yellow) - term.setCursorPos(25 - #levelList[currentLevel]/2, 19) - term.write(levelList[currentLevel]) - local lstr = "Men: " - term.setCursorPos(50 - #lstr - math.floor(math.log(playerLives,10)), 19) - term.setTextColour(colours.blue) - term.write(lstr) - term.setTextColour(colours.yellow) - term.write(playerLives.."") -end - ---Draws the list of levels known, with respect to screen ---real estate -local function drawLevelList() - local minLev = ((levelLot-1) * 10 + 1) - local maxLev = minLev + math.min(10, #levelList - (levelLot-1) * 10) - 1 - - term.setCursorPos(7, 2) - term.setBackgroundColour(colours.black) - term.clearLine() - for j = 1,49 do updateMap(j,2) end - - term.setBackgroundColour(colours.black) - term.setTextColour(colours.white) - term.setCursorPos(7, 2) - local msg = "Levels "..minLev.." to "..maxLev.." of "..#levelList - term.write(msg) - - term.setTextColour(colours.yellow) - term.setCursorPos(4, 2) - if levelLot > 1 then term.write("<-") - else term.write(" ") end - - term.setCursorPos(8 + #msg, 2) - if maxLev < #levelList then term.write("->") - else term.write(" ") end - - for i = 1,10 do - term.setCursorPos(1, 3+i) - for j = 1,49 do updateMap(j,3+i) end - term.setTextColour(colours.white) - term.setBackgroundColour(colours.black) - term.setCursorPos(17, 3+i) - if i + (levelLot-1)*10 - 1 < maxLev then - term.write(levelList[10 * (levelLot-1) + i]) - end - end -end - ---Loads up and draws up the title screen, for a nice ---intro to Gold Runner -local function loadTitleScreen() - map = {} - goldMap = {} - monks = {} - goldCount = 0 - for i=1,#titleLevel do - local line = titleLevel[i] - goldMap[#map+1] = {} - map[#map+1] = {} - for i=1,math.min(#line,49) do - local lchar = string.sub(line,i,i) - parseValue(i, #map, lchar) - end - if #map == 18 then break end - end - maxGoldCount = goldCount - - drawMap() - term.setCursorPos(1,19) - term.setBackgroundColour(colours.blue) - term.clearLine() - - menIndex = 1 - titleLoaded = true -end - ---Opens an in-game menu to display a series of options. -local function inGameMenu(menuList) - menIndex = 1 - - local squareTop,squareBottom = 4,6 + #menuList * 2 - local squareSize = 0 - for i=1,#menuList do squareSize = math.max(squareSize, #menuList[i] + 6) end - - for y=squareTop,squareBottom do - term.setCursorPos(w/2 - squareSize/2, y) - term.setBackgroundColour(colours.lightBlue) - term.write(string.rep(" ", squareSize)) - - if y ~= squareTop and y ~= squareBottom then - term.setCursorPos(w/2 - squareSize/2 + 1, y) - term.setBackgroundColour(colours.black) - term.write(string.rep(" ", squareSize - 2)) - end - - if y ~= squareTop and y ~= squareBottom and y % 2 == 0 then - local opt = menuList[(y - squareTop) / 2] - term.setCursorPos(w/2 - #opt/2, y) - term.setTextColour(colours.white) - term.write(opt) - end - end - - local p1 = nil - repeat - for i=1,#menuList do - term.setBackgroundColour(colours.black) - term.setTextColour(colours.yellow) - if i == menIndex then - term.setCursorPos(w/2 - squareSize/2 + 1, squareTop + i * 2) - term.write(">") - term.setCursorPos(w/2 + squareSize/2 - 2, squareTop + i * 2) - term.write("<") - else - term.setCursorPos(w/2 - squareSize/2 + 1, squareTop + i * 2) - term.write(" ") - term.setCursorPos(w/2 + squareSize/2 - 2, squareTop + i * 2) - term.write(" ") - end - end - _,p1 = os.pullEvent("key") - - if p1 == keys.up and menIndex > 1 then menIndex = menIndex - 1 - elseif p1 == keys.down and menIndex < #menuList then menIndex = menIndex + 1 end - until p1 == keys.enter - - return menuList[menIndex] -end - ---Checks to see if any given desired move is legal. Monks and players both use this. -local function isLegalMove(initX,initY,finX,finY) - if finY < 1 or finY > #map or finX < 1 or finX > 49 then - return false - end - - if map[finY][finX] ~= 0 and map[finY][finX] ~= '#' then - --This reports 'self moves' as being illegal, but that's fine - for _,monk in pairs(monks) do - if monk.x == finX and monk.y == finY then return false end - end - - if finY == initY-1 and (map[initY][initX] == "H" or (map[initY][initX] == "h" and goldCount == 0)) - then return true - elseif finY == initY+1 and (map[finY][finX] == "H" or (map[finY][finX] == "h" and goldCount == 0) - or (type(map[finY][finX]) == "number" and map[finY][finX] > 0) or map[finY][finX] == nil or - map[finY][finX] == "V" or map[finY][finX] == "-" or (map[finY][finX] == 'h' and goldCount ~= 0)) - then return true - elseif finX == initX-1 or finX == initX+1 then - return true - end - end -end - ---Moves the player to a given step. -local function movePlayer(x,y,ignoreLegal) - if not ignoreLegal and not isLegalMove(plX,plY,x,y) then return false end - - local ox = plX - local oy = plY - plX = x - plY = y - - updateMap(ox,oy) - updateMap(x,y) - if goldMap[y][x] == 1 then - goldMap[y][x] = 0 - goldCount = goldCount - 1 - playerScore = playerScore + 5 - if started then drawHUD() end - if (goldCount == 0) then - drawEndgameMap() - end - elseif exX == plX and exY == plY and goldCount == 0 then - started = false - nextLevel = true - end - - pfalling = (y < #map and map[y][x] ~= '-' and map[y][x] ~= 'H' and not (map[y][x] == 'h' and goldCount == 0) - and (map[y+1][x] == nil or map[y+1][x] == "V" or map[y+1][x] == 2 or map[y+1][x] == '-')) - if (y < #map and map[y+1][x] == 'h' and goldCount ~= 0) then pfalling = true end - for _,monk in pairs(monks) do - if monk.x == plX and monk.y == plY + 1 then pfalling = false break end - end - - return true -end - -local function updateMonks() - for _,monk in pairs(monks) do - --Absolute first step- if he's trapped or dead, he's going nowhere - if monk.trapped or monk.dead then - --If he's just spawned he takes a second to orient himself - elseif monk.justSpawned then - monk.justSpawned = false - --We evaluate their falling behaviour here (as freed monks CAN stand on air) - monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not - (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or - map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) - for _,omonk in pairs(monks) do - if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end - end - if monk.x == plX and monk.y == plY + 1 then monk.falling = false end - --Then we consider if he's just gotten out of a hole - elseif monk.justEscaped then - monk.justEscaped = false - --He tries the player side first - local playerSide = (plX-monk.x) / math.abs(plX-monk.x) - if isLegalMove(monk.x, monk.y, monk.x + playerSide, monk.y) then - monk.x = monk.x + playerSide - updateMap(monk.x - playerSide, monk.y) - elseif isLegalMove(monk.x, monk.y, monk.x - playerSide, monk.y) then - monk.x = monk.x - playerSide - updateMap(monk.x + playerSide, monk.y) - end - drawMonk(monk) - --Then we evaluate falling - elseif monk.falling then - monk.behaviour = "none" - monk.y = monk.y + 1 - updateMap(monk.x, monk.y-1) - drawMonk(monk) - monk.desX = nil - if type(map[monk.y][monk.x]) == "number" then - monk.trapped = os.startTimer(monkTrapIntv) - monk.falling = false - else - monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not - (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or - map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) - for _,omonk in pairs(monks) do - if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end - end - if monk.x == plX and monk.y == plY + 1 then monk.falling = false end - if monk.justEscaped then monk.falling = false end - end - --If he's on his feet and not trapped, he's allowed to think about where to move - elseif monk.y == plY then - --Is the monk on the same level as the player? How lucky! They'll just walk towards him - monk.desX = plX - monk.behaviour = "across" - --Y difference takes precedence over X (as in the original, makes them a bit smarter) - elseif monk.y < plY then - --If they can move up, they will - if isLegalMove(monk.x,monk.y,monk.x,monk.y+1) and not monk.justEscaped then - monk.y = monk.y+1 - updateMap(monk.x, monk.y-1) - drawMonk(monk) - monk.desX = nil - --A down move can lead to a fall, so we check if they're now falling. - monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not - (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or - map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) - for _,omonk in pairs(monks) do - if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end - end - if monk.x == plX and monk.y == plY + 1 then monk.falling = false end - --Otherwise, it's off to the nearest ladder, monkey bars or perilous ledge to jump off - --assuming they haven't found one already - elseif monk.desX == nil then - if monk.behaviour ~= "down" then monk.desX = nil end - monk.behaviour = "down" - monk.desX = nil - local cmLeft = true - local cmRight = true - --We try to find the nearest by searching alternate left and right at variable distance - for i=1,math.max(monk.x - 1, 49 - monk.x) do - if monk.x-i > 0 and cmLeft then - --If a wall blocks the monks path, they can't keep going left or right - cmLeft = map[monk.y][monk.x-i] ~= 0 - --But if it's all clear, they look for something to climb/jump down - if cmLeft and (map[monk.y+1][monk.x-i] == "H" or (map[monk.y+1][monk.x-i] == 'h' and goldCount == 0) - or map[monk.y+1][monk.x-i] == nil or map[monk.y][monk.x-i] == '-') then - monk.desX = monk.x-i - break - end - end - if monk.x+i < 50 and cmRight then - --If a wall blocks the monks path, they can't keep going left or right - cmRight = map[monk.y][monk.x+i] ~= 0 - --But if it's all clear, they look for something to climb/jump down - if cmRight and (map[monk.y+1][monk.x+i] == "H" or (map[monk.y+1][monk.x+i] == 'h' and goldCount == 0) - or map[monk.y+1][monk.x+i] == nil or map[monk.y][monk.x+i] == '-') then - monk.desX = monk.x+i - break - end - end - end - end - elseif monk.y > plY then - if monk.behaviour ~= "up" then monk.desX = nil end - monk.behaviour = "up" - --Same deal again- try moving up first - if isLegalMove(monk.x,monk.y,monk.x,monk.y-1) then - monk.y = monk.y-1 - updateMap(monk.x, monk.y+1) - drawMonk(monk) - monk.desX = nil - --You can never move up and start falling, so we don't bother to check - --Otherwise they need ladders to climb up - elseif monk.desX == nil then - monk.behaviour = "up" - monk.desX = nil - local cmLeft = true - local cmRight = true - --We try to find the nearest by searching alternate left and right at variable distance - for i=1,math.max(monk.x - 1, 49 - monk.x) do - if monk.x-i > 0 and cmLeft then - --If a wall blocks the monks path or a pit is in the way, they can't keep going left or right - cmLeft = map[monk.y][monk.x-i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x-i] ~= nil - or map[monk.y][monk.x-i] == '-' or map[monk.y][monk.x-i] == "H" or (map[monk.y][monk.x-i] == "h" - and goldCount == 0)) - --But if it's all clear, they look for a ladder - if cmLeft and (map[monk.y][monk.x-i] == "H" or (map[monk.y][monk.x-i] == 'h' and goldCount == 0)) then - monk.desX = monk.x-i - break - end - end - if monk.x+i < 50 and cmRight then - cmRight = map[monk.y][monk.x+i] ~= 0 and (monk.y == #map or map[monk.y+1][monk.x+i] ~= nil - or map[monk.y][monk.x+i] == '-' or map[monk.y][monk.x+i] == "H" or (map[monk.y][monk.x+i] == "h" - and goldCount == 0)) - if cmRight and (map[monk.y][monk.x+i] == "H" or (map[monk.y][monk.x+i] == 'h' and goldCount == 0)) then - monk.desX = monk.x+i - break - end - end - end - end - end - - if not (monk.trapped or monk.dead) then - --Has the monk decided on moving left or right? If so we try to move him - if monk.desX and not monk.falling then - local mdir = monk.desX - monk.x - local mdir = mdir / math.abs(mdir) - if isLegalMove(monk.x,monk.y,monk.x+mdir,monk.y) then - monk.x = monk.x + mdir - updateMap(monk.x - mdir, monk.y) - drawMonk(monk) - else - --This allows re-evaluations if they get stuck- not ideal but good enough - monk.desX = nil - end - end - monk.falling = (monk.y < #map and map[monk.y][monk.x] ~= '-' and map[monk.y][monk.x] ~= "H" and not - (map[monk.y][monk.x] == 'h' and goldCount == 0) and (map[monk.y+1][monk.x] == nil or map[monk.y+1][monk.x] == "V" or - map[monk.y+1][monk.x] == 2 or map[monk.y+1][monk.x] == '-') and type(map[monk.y][monk.x] ~= "number")) - for _,omonk in pairs(monks) do - if omonk.x == monk.x and omonk.y == monk.y + 1 then monk.falling = false break end - end - if monk.x == plX and monk.y == plY + 1 then monk.falling = false end - --We have caught and killed the player - if monk.x == plX and monk.y == plY and spawnTimer == -1 then - spawnTimer = os.startTimer(2) - end - end - end -end - -local function updateBlockTimer(tid) - local remAt = nil - for i,v in ipairs(blockTimers) do - if v.timer == tid then - if map[v.y][v.x] == 3 then - for _,monk in pairs(monks) do - if monk.x == v.x and monk.y == v.y-1 then - map[v.y][v.x] = 0 - remAt = i - break - end - end - if not remAt then - map[v.y][v.x] = 2 - v.timer = os.startTimer(blockIntv) - end - elseif map[v.y][v.x] == 2 then - map[v.y][v.x] = 1 - v.timer = os.startTimer(0.1) - elseif map[v.y][v.x] == 1 then - map[v.y][v.x] = 0 - --If the player is caught in a block, he dies - if v.y == plY and v.x == plX then - spawnTimer = os.startTimer(2) - end - for _,monk in pairs(monks) do - if monk.x == v.x and monk.y == v.y then - monk.dead = os.startTimer(monkSpawnIntv) - --Easiest way to get them out of the way rather than evaluation - monk.x = -1 - monk.y = -1 - monk.trapped = nil - end - end - remAt = i - end - updateMap(v.x,v.y) - break - end - end - if remAt then table.remove(blockTimers,remAt) end -end - -local function shootBlock(x,y) - if y <= #map and map[y][x] == 0 and (map[y-1][x] == nil - or map[y-1][x] == 2 or (map[y-1][x] == 'h' and goldCount > 0)) then - map[y][x] = 3 - table.insert(blockTimers, {x = x; y = y; timer = os.startTimer(0.1);} ) - updateMap(x,y) - end -end - -local function handleEvents() - local id,p1,p2,p3 = os.pullEvent() - - if id == "key" then - --Menu Handling - if p1 == keys.up then - if menIndex > 1 then menIndex = menIndex - 1 end - elseif p1 == keys.down then - if inLevelSelect then - if menIndex < math.min(10, #levelList - (levelLot-1)*10) then - menIndex = menIndex + 1 - end - elseif menIndex < #titleOptions then menIndex = menIndex + 1 end - elseif p1 == keys.left and inLevelSelect and levelLot > 1 then - levelLot = levelLot - 1 - drawLevelList() - elseif p1 == keys.right and inLevelSelect and levelLot * 10 < #levelList then - levelLot = levelLot + 1 - drawLevelList() - end - - --Game Handling - if p1 == keys.a and moveTimer == -1 and spawnTimer == -1 then - movePlayer(plX-1,plY) - moveTimer = os.startTimer(moveIntv) - elseif p1 == keys.d and moveTimer == -1 and spawnTimer == -1 then - movePlayer(plX+1,plY) - moveTimer = os.startTimer(moveIntv) - elseif p1 == keys.w and moveTimer == -1 and spawnTimer == -1 then - movePlayer(plX,plY-1) - moveTimer = os.startTimer(moveIntv) - elseif p1 == keys.s and moveTimer == -1 and spawnTimer == -1 then - movePlayer(plX,plY+1) - moveTimer = os.startTimer(moveIntv) - elseif p1 == keys.q and shootTimer == -1 and not pfalling and spawnTimer == -1 then - shootBlock(plX-1,plY+1) - shootTimer = os.startTimer(moveIntv) - elseif p1 == keys.e and shootTimer == -1 and not pfalling and spawnTimer == -1 then - shootBlock(plX+1,plY+1) - shootTimer = os.startTimer(moveIntv) - elseif p1 == keys.space and started then - started = false - elseif p1 == keys.enter then - if not started then - if inLevelSelect then - currentLevel = menIndex + (levelLot - 1) * 10 - menSel = "New Game" - else - menSel = titleOptions[menIndex] - end - else - started = false - menIndex = 1 - menSel = inGameMenu(inGameOptions) - end - end - elseif id == "timer" then - if p1 == shootTimer then shootTimer = -1 - elseif p1 == spawnTimer then - started = false - elseif p1 == moveTimer then - if pfalling then - movePlayer(plX,plY+1) - moveTimer = os.startTimer(moveIntv) - else - moveTimer = -1 - end - elseif p1 == monkTimer then - updateMonks() - monkTimer = os.startTimer(moveIntv * 2) - elseif updateBlockTimer(p1) then - else - for _,monk in pairs(monks) do - if p1 == monk.trapped then - --You can stand on a monk to force them to be killed- so we check for that - --along with being buried in tunnels, etc. - local stillTrapped = map[monk.y-1][monk.x] == 0 or (plX == monk.x and plY == monk.y-1) - for _,omonk in pairs(monks) do - if omonk.x == monk.x and omonk.y == monk.y-1 then - stillTrapped = true - break - end - end - --Perpetually trapped monks will try to excape much more quickly - if stillTrapped then - --This needs to be tweaked - monk.trapped = os.startTimer(0.75) - else - --When free, they head in your general direction, re-evaluate later - monk.y = monk.y - 1 - --This is necessary to stop 'double jumping' - monk.desX = nil - monk.trapped = nil - monk.behaviour = "none" - monk.justEscaped = true - - updateMap(monk.x, monk.y+1) - drawMonk(monk) - end - break - elseif p1 == monk.dead then - --Same deal- you can camp spawn - local stillDead = plX == monk.spawnX and plY == monk.spawnY - for _,omonk in pairs(monks) do - if omonk.x == monk.spawnX and omonk.y == monk.spawnY then - stillDead = true - break - end - end - --They'll spawn the second you give them the chance - if stillDead then - monk.dead = os.startTimer(0.5) - else - monk.x = monk.spawnX - monk.y = monk.spawnY - monk.dead = nil - monk.justSpawned = true - monk.behaviour = "none" - drawMonk(monk) - break - end - end - end - end - end -end - ---[[ Level Editor ]]-- - -local pallette = { { t = colours.black, b = colours.blue, s = " ", n = "Solid Ground", v = 0 }, - { t = colours.orange, b = colours.blue, s = "V", n = "Trap Ground", v = "V" }, - { t = colours.grey, b = colours.grey, s = " ", n = "Cement Ground", v = "#" }, - { t = colours.brown, b = colours.black, s = "H", n = "Ladder", v = "H" }, - { t = colours.brown, b = colours.black, s = "-", n = "Monkey Bars", v = "-" }, - { t = colours.white, b = colours.black, s = "&", n = "Player Spawn", v = "player" }, - { t = colours.red, b = colours.black, s = "&", n = "Mad Monk", v = "&" }, - { t = colours.yellow, b = colours.black, s = "$", n = "Gold", v = "$" }, - { t = colours.lightGrey, b = colours.black, s = "H", n = "Hidden Ladder", v = "h" }, - { t = colours.lime, b = colours.black, s = "@", n = "Exit Portal", v = "@" }, - { t = colours.red, b = colours.black, s = "ERASE", n = "Eraser", v = nil } } -local brushType = 1 - -local function getHexOf(colour) - if not colour or not tonumber(colour) then - return " " - end - local value = math.log(colour)/math.log(2) - if value > 9 then - value = hexnums[value] - end - return value -end - -local function drawFooter() - for i=1,h-1 do - if i % 2 == 0 then term.setBackgroundColour(colours.grey) - else term.setBackgroundColour(colours.yellow) end - term.setCursorPos(1,i) - term.write(" ") - term.setCursorPos(w,i) - term.write(" ") - end - - term.setBackgroundColour(colours.black) - term.setTextColour(colours.blue) - term.setCursorPos(2,h) - term.clearLine() - term.write("Editor Mode: ") - term.setTextColour(colours.yellow) - term.write(levelEditName) - local msg = "Tool: "..pallette[brushType].n.." "..pallette[brushType].s - term.setCursorPos(w - #msg - 1, 19) - term.setTextColour(colours.blue) - term.write("Tool: ") - term.setTextColour(colours.yellow) - term.write(pallette[brushType].n.." ") - term.setBackgroundColour(pallette[brushType].b) - term.setTextColour(pallette[brushType].t) - term.write(pallette[brushType].s) -end - -local function drawPallette(xpos,ypos) - local xdim = 7 - local ydim = 5 - local left = xpos - local top = ypos - if xpos + xdim > w then left = left + (w - xpos - xdim) end - if ypos + ydim > h then top = top + (h - ypos - ydim) end - - --There's no easy way to do this... so we draw it manually :( - for i=0,4 do - term.setCursorPos(left, top + i) - term.setBackgroundColour(colours.black) - term.setTextColour(colours.red) - if i == 0 or i == 4 then term.write("*-----*") - else term.write("* *") end - end - - for i=1,#pallette-1 do - local ypl = 1 - local xmv = i - if i > 5 then ypl = 2 xmv = i - 5 end - - term.setCursorPos(left + xmv, top+ypl) - term.setBackgroundColour(pallette[i].b) - term.setTextColour(pallette[i].t) - term.write(pallette[i].s) - end - - term.setCursorPos(left + 1, top + 3) - term.setBackgroundColour(colours.red) - term.setTextColour(colours.black) - term.write("ERASE") - - local _,button,x,y = os.pullEvent("mouse_click") - - if button == 1 then - if y == top + 1 and x > left and x < left + 6 then - brushType = x-left - elseif y == top + 2 and x > left and x < left + 6 then - brushType = x-left+5 - elseif y == top + 3 and x > left and x < left + 6 then - brushType = 11 - end - end - - for y = top,top+ydim do - for x = left,left+xdim do - --Not sure why the -2 is necessary - if map[y+drawOffsetY] then updateMap(x-2,y+drawOffsetY) end - end - end - drawFooter() - return -end - -local function saveCurrentMap(path) - local file = io.open(shell.resolve(".").."/levels/"..path, "w") - if not file then return false end - - drawMap() - drawFooter() - local msg = "Saving.." - term.setCursorPos(w/2-#msg/2, 5) - term.setTextColour(colours.yellow) - term.setBackgroundColour(colours.blue) - term.write(msg) - term.setCursorPos(w/2-9, 6) - term.setBackgroundColour(colours.red) - term.write(string.rep(" ", 18)) - term.setCursorPos(w/2-9,6) - term.setBackgroundColour(colours.lime) - - for y=1,#map do - local xstr = "" - for x=1,49 do - --This again... - if map[y][x] == 0 then xstr = xstr..getHexOf(colours.blue) - elseif map[y][x] == "V" then xstr = xstr..getHexOf(colours.orange) - elseif map[y][x] == "#" then xstr = xstr..getHexOf(colours.grey) - elseif map[y][x] == "H" then xstr = xstr..getHexOf(colours.brown) - elseif map[y][x] == "h" then xstr = xstr..getHexOf(colours.lightGrey) - elseif map[y][x] == "-" then xstr = xstr..getHexOf(colours.green) - elseif map[y][x] == "&" then xstr = xstr..getHexOf(colours.red) - elseif goldMap[y][x] == 1 then xstr = xstr..getHexOf(colours.yellow) - elseif plX == x and plY == y then xstr = xstr..getHexOf(colours.white) - elseif exX == x and exY == y then xstr = xstr..getHexOf(colours.lime) - else xstr = xstr.." " - end - end - file:write(xstr.."\n") - term.write(" ") - sleep(0) - end - file:close() - return true -end - -local function runLevelEditor() - inLevelEditor = true - term.setBackgroundColour(colours.black) - term.clear() - if not fs.exists(shell.resolve(".").."/levels/"..levelEditName) then - map = {} - goldMap = {} - monks = {} - for i=1,18 do map[i] = {} goldMap[i] = {} end - plX = 2 - plY = 2 - plspawnX = plX - plspawnY = plY - exX = 48 - exY = 17 - else - loadMap(shell.resolve(".").."/levels/"..levelEditName) - for _,monk in pairs(monks) do - map[monk.y][monk.x] = "&" - end - monks = {} - end - - drawMap() - drawFooter() - - while inLevelEditor do - local id,button,x,y = os.pullEvent() - if id == "mouse_click" or id == "mouse_drag" then - if button == 2 then - drawPallette(x,y) - elseif x > drawOffsetX and x <= 49 + drawOffsetX and y > drawOffsetY and y <= 18 + drawOffsetY then - if pallette[brushType].v == "player" then - local ox = plX - local oy = plY - if plX == exX and plY == exY then - exX = ox - exY = oy - end - plX = x - drawOffsetX - plY = y - drawOffsetY - map[plY][plX] = nil - goldMap[plY][plX] = nil - updateMap(ox,oy) - elseif pallette[brushType].v == "@" then - local ox = exX - local oy = exY - if plX == exX and plY == exY then - plX = ox - plY = oy - end - exX = x - drawOffsetX - exY = y - drawOffsetY - map[plY][plX] = nil - goldMap[plY][plX] = nil - updateMap(ox,oy) - elseif pallette[brushType].v == "$" then - goldMap[y-drawOffsetY][x-drawOffsetX] = 1 - map[y-drawOffsetY][x-drawOffsetX] = nil - elseif pallette[brushType].v == nil then - map[y-drawOffsetY][x-drawOffsetX] = nil - goldMap[y-drawOffsetY][x-drawOffsetX] = nil - else - map[y-drawOffsetY][x-drawOffsetX] = pallette[brushType].v - goldMap[y-drawOffsetY][x-drawOffsetX] = nil - --term.setCursorPos(1,19) - --print("At "..(x-drawOffsetX)..", "..(y-drawOffsetY).." have placed "..pallette[brushType].v) - end - updateMap(x-drawOffsetX, y-drawOffsetY) - end - elseif id == "mouse_scroll" then - brushType = brushType + button - if brushType == 0 then brushType = #pallette - elseif brushType > #pallette then brushType = 1 end - drawFooter() - elseif id == "key" and button == keys.enter then - menSel = inGameMenu(levelEditOptions) - if menSel == "Save" then - saveCurrentMap(levelEditName) - drawMap() - drawFooter() - elseif menSel == "Save and Exit" then - saveCurrentMap(levelEditName) - menSel = "none" - inLevelEditor = false - elseif menSel == "Discard and Exit" then - menSel = "none" - inLevelEditor = false - elseif menSel == "Play Level" then - saveCurrentMap(levelEditName) - inLevelEditor = false - end - end - end -end - - -local function runLevelSelect() - if not titleLoaded then - loadTitleScreen() - monkTimer = os.startTimer(moveIntv * 1.5) - else - drawMap() - drawEndgameMap() - term.setCursorPos(1,19) - term.setBackgroundColour(colours.blue) - term.clearLine() - end - drawLevelList() - - menSel = "none" - repeat - handleEvents() - - term.setBackgroundColour(colours.black) - term.setTextColour(colours.yellow) - for i=1,10 do - term.setCursorPos(16,3+i) - if i == menIndex then - term.write(">") - else - term.write(" ") - end - end - until menSel ~= "none" - inLevelSelect = false - menSel = "New Game" -end - -local function runTitle() - loadTitleScreen() - term.setCursorPos(15,3) - term.setTextColour(colours.red) - term.setBackgroundColour(colours.black) - term.write("Gold Runner") - term.setCursorPos(16,4) - term.write("By Nitrogen Fingers") - - term.setTextColour(colours.white) - for i=1,#titleOptions do - term.setCursorPos(19, 5 + (i*2)) - term.write(titleOptions[i]) - end - - term.setCursorPos(16, 7) - term.setTextColour(colours.yellow) - term.write("->") - - menSel = "none" - monkTimer = os.startTimer(moveIntv * 1.5) - - repeat - handleEvents() - - term.setBackgroundColour(colours.black) - term.setTextColour(colours.yellow) - for i=1,#titleOptions do - term.setCursorPos(16, 5 + i*2) - if menIndex == i then term.write("->") - else term.write(" ") end - end - until menSel ~= "none" -end - -local function playLevel() - loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel]) - running = true - while running do - drawMap() - drawHUD() - os.pullEvent("key") - movePlayer(plX,plY,true) - - monkTimer = os.startTimer(moveIntv * 1.5) - moveTimer = os.startTimer(moveIntv) - shootTimer = -1 - spawnTimer = -1 - - started = true - while started do - handleEvents() - end - - if menSel == "Quit" or menSel == "Back to Title" or menSel == "Edit Level" then - running = false - return - end - menSel = "none" - - if nextLevel then - if currentLevel == #levelList then - started = false - running = false - break - else - currentLevel = currentLevel + 1 - playerLives = playerLives + 1 - resetMap() - loadMap(shell.resolve(".").."/levels/"..levelList[currentLevel]) - end - nextLevel = false - else - playerLives = playerLives-1 - if playerLives > 0 then resetMap() - else - running = false - end - end - end - - if nextLevel then - local msg = "All levels defeated, Gold Runner!" - term.setBackgroundColour(colours.black) - term.setTextColour(colours.lime) - term.setCursorPos(25 - #msg/2, 2) - term.write(msg) - else - local msg = "Game over!" - term.setBackgroundColour(colours.black) - term.setTextColour(colours.red) - term.setCursorPos(25 - #msg/2, 2) - term.write(msg) - end - currentLevel = 1 - sleep(2) -end - -term.clear() -if not fs.exists(shell.resolve(".").."/levels") then - error("Level directory not present!") -end -levelList = fs.list(shell.resolve(".").."/levels") -if #levelList == 0 then - error("Level directory is empty!") -end - -runTitle() -menIndex = 1 - -while menSel ~= "Quit" do - if menSel == "Select Level" then - inLevelSelect = true - runLevelSelect() - elseif menSel == "New Game" then - playerLives = 3 - playerScore = 0 - playLevel() - elseif menSel == "Create Level" then - --This is a bit lazy... well it's all been a bit lazy :P - drawMap() - term.setCursorPos(1,19) - term.setBackgroundColour(colours.blue) - term.clearLine() - - term.setCursorPos(16,10) - term.setBackgroundColour(colours.black) - term.setTextColour(colours.white) - term.write("Enter level name:") - term.setTextColour(colours.lime) - term.setCursorPos(17,11) - term.setCursorBlink(true) - local levelName = "" - - local id,p1 - repeat - id,p1 = os.pullEvent() - if id == "key" and p1 == keys.backspace then - levelName = string.sub(levelName, 1, #levelName - 1) - elseif id == "timer" and p1 == monkTimer then - updateMonks() - monkTimer = os.startTimer(moveIntv * 2) - elseif id == "char" and #levelName < 14 then - levelName = levelName..p1 - end - term.setTextColour(colours.lime) - term.setCursorPos(17,11) - term.write(levelName..string.rep(" ",14 - #levelName)) - term.setCursorPos(17 + #levelName ,11) - until id == "key" and p1 == keys.enter and #levelName > 0 - - term.setCursorBlink(false) - levelEditName = levelName - runLevelEditor() - - if menSel == "Play Level" then - currentLevel = nil - levelList = fs.list(shell.resolve(".").."/levels") - for num,name in pairs(levelList) do - if name == levelName then - currentLevel = num - break - end - end - menSel = "New Game" - else - menSel = "none" - end - elseif menSel == "Edit Level" then - levelEditName = levelList[currentLevel] - runLevelEditor() - term.setBackgroundColour(colours.black) - term.clear() - - if menSel == "Play Level" then - menSel = "New Game" - else - menSel = "none" - end - elseif menSel == "none" or menSel == "Back to Title" then - runTitle() - end - menIndex = 1 -end - -term.setBackgroundColour(colours.black) -shell.run("clear") -term.setTextColour(colours.white) -print("Thanks for playing Gold Runner!") diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/01_welcome b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/01_welcome deleted file mode 100644 index 9be5a826b..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/01_welcome +++ /dev/null @@ -1,18 +0,0 @@ - - 5 - bb8bb - b8b - 8 - 4 ddddddddddddddd 8 - bbbbcbbbbbbb 8 - bbbc 8 - c 4 4 8 - c bbbbbbb - bcbbbbbbbb bbbbbbb - c 44 bbbb - c 4 bbbb bbb - 4bbbbbbbbbbc bb 4 4 bb - bbbbbbbbbb c bbbcbbbbb bb -b bbb c c bb -bbb c 4 4 c 0 bbb -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/02_coalmine b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/02_coalmine deleted file mode 100644 index 219a502e2..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/02_coalmine +++ /dev/null @@ -1,18 +0,0 @@ -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -b 0 b -bbbb bb dddd cb b -b bbbb e cbb 4 4 cb 44 b -bbbbbbbbbbbbbbbbbbbbcbbbbbbb bbbbbbbbbbbb7777b -b b dddddddd c b -b b c cbb b -b 44 b c cbbbb 4 4 4 b -bbbbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbb7b7bbbbb7bbb -bbbbbb4 bbbbcb4 4 4bb4 4bbbbbbbbbbb7bbb7b7b77b -b bb bbbcbbbbbbbbbbbbbbbbb b -b c 7777777777b -b c dd ddddddddddddcb7777777777b -bbbbbbbbbbbbbbbbbb cbbb cbbbb 5 b -bbbbbbbbbbbbbbbbbb cbbb c7b 8bbbbbb -b cbbb c7b 8 4 4 b -b 4 4 4 4 4 cb cbb c7b cbbbbbbbb -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb777777777777b diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/03_seeker b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/03_seeker deleted file mode 100644 index 49cff842d..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/03_seeker +++ /dev/null @@ -1,18 +0,0 @@ - - - 5 - 4 4 8 4 4 - bbcbb 8 bbbbbbcb - c 8 c - c 4 dddd 4 e 4 dddddd 8 c - bbbb bbbbcbbbbbb 8 c - c 4 8 e 4 c - c bbbbbbbbcbb c - c c c - 4 c 4 0 4 c 4 c - bbbcbbbbbbbbb bbbbcbbbbbbbc - c c - c c - c c -b c 4 4 4 4 c b -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/04_fortress b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/04_fortress deleted file mode 100644 index 461eceeab..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/04_fortress +++ /dev/null @@ -1,18 +0,0 @@ - -7 4 547 0 -7ccbbbb7 cbbbbb -7cc77777 cb 4 4 -7cc cb7777 -7cc7 -7cc7 -7cc 4 dddd dddd dddd -7cc77 c777b777c c c c7 -7cc7c77 dddddd 4 4 c 7c c e c c7 -7cc c bbbbcbbbbc 777777777777777777 -7777c7 7 c c -7c77c 77 c c4 4 dddddddd 4 4 -7c c 77 4 bbbbc7b7b7b7b7c bbbbbc -7c c 7bb c c c -77c777c777b 4 c c c -7ece 7c 7bbbbbb c c e c -7777777777777777777777777777777777777777777777777 diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/05_caged b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/05_caged deleted file mode 100644 index b286f0ae3..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/05_caged +++ /dev/null @@ -1,18 +0,0 @@ - - 88888888888 - e 4 cb8 8bc 4 e - cbbbbbbcdddddddcb8 8bcdddddddcbbbbbbc - cb bc b8 8b cb bc - cb bc b8 8b cb bc - cb bc b8 8b cb bc - cbb4 bc b8 5 8b cbb 4 bc - cbbbbbbc b8dddd dddd8b cbbbbbbc - cb bcddddddddb8 4 4 8bddddddddcb bc - cb b cbcbbbbbbbbbcbc b bc - cb b cbc cbc b bc - cb 4ebb cbc e cbc bbe4 bc - cbbbbbb cb77777777777bc bbbbbbc - c b c c b c - c b c c b c - c 4b c 0 c b4 c -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/06_flowers b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/06_flowers deleted file mode 100644 index db0c50e4b..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/06_flowers +++ /dev/null @@ -1,18 +0,0 @@ - ddddddd -c bbbbcddddddd dddc d 4ed dddd -c bbe44ebb c 4 c bbb c 4 c -c 4777 7b7777b7 bbbb bbbb c -c bb c -c 4 dd 4 4 4c -c 4 e bb dd 4 4ddd bb bb bc -c bbb bb b c 4 0 bb c -c 4 c bb 4 4 c -cb 4 bbb c bb c -cbb bb dddd d 4d c 4 c -cbbbb bbc bb c 4 cd 5 dc -c 4 4 4 c 4 c bbb c c -c bb 4 bb c bb 4 c 444 c -c 4 4 4 4c bb cbbbc 444 c -c bbb cbbc c 444 c -c c c c -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/07_pyramid b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/07_pyramid deleted file mode 100644 index 6f861bfc1..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/07_pyramid +++ /dev/null @@ -1,18 +0,0 @@ - 8 bbbb 0 b b - 8b bbbb 8bbb 5 b - 8b 8bbb 8 b - 8bbbbbbbbbbbbbbbbbbbb - 8 - 8 ddd b - 8 c bbbbbbbbbcb - 8 c 4bbb cb -b 8ddd ddddddd e dddddddc bbb4 cb -bbbbbbbbb c bbbbbbb c 4bbb cb -b b c bbb444bbb c bbb4 cb -b 4 b c bbb4 4bbb c 4bbb cb -b bbb b c bbb4 4bbb c 7777 cb -b 4 4 b c bbb4 4bbb cbbbbbbbbbbbbbb -b bbbbb b c bbb bbb c b -bddd4dddb c bbbbbbbbbbbbbbbbbbb c cbbb b -b4 b 4 c e e c cbbb 4444 b -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/08_cavein b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/08_cavein deleted file mode 100644 index f7cfd6e11..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/08_cavein +++ /dev/null @@ -1,18 +0,0 @@ -bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb bbbbbbbbbbbbbb -b 8 8 8 8 8 b 4 5 b4 e 4 b -b 888 8 8 8 bbbbbbbcbbbbc 8 bbbbbbbcbbbbbb -b 8 8 8 88888 bbbb4bbcbbbbbbbbbb bbb c b -b e c bbbb bbb c b -bbbbbbbbbbbbbbbb77bcbbbbbbbbbbbcbbbb bbb c 4 4b -b 4 4 bb bbc cb44b bbb c b -bbbbbbbbbbbbb bc cbbbbbbbb c b -b 4 4 b4 4 4bc c 4bbb4 c b -bbbbbbbbbbbbb4 4 4bc bbbcbbbbbbbbbbbbbbbbbccbb -b 4 4 b bc bbbc e 4 cbbccbb -bbbbbbbbbbbbbbbcbbbc 4bbbc cbbbbbbbbbbcbbccbb -b c cbbbbb c4 c bbbbbbcbbccbb -b c cbbbbbcbbbbbcbbbbbb44 cbbccbb -b 4 4 cbbbbbbbcbbbbbcbbbbbcbbbb4bbbbbbbbccbb -bbbbbbbbbbbbbbbbbbbce cbb4bbc 0 cc4b -bb bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -7777777777777777777777777777777777777777777777777 diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/09_skyislands b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/09_skyislands deleted file mode 100644 index b666d74f0..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/09_skyislands +++ /dev/null @@ -1,18 +0,0 @@ - - 05 ddddd 4e4 - 4ddddddd cc bbcbb - bbbc 4 ccddddd 4 c - 4 c 4 dddddcc bbbb c 4 - bcbb 4 4 cc b44bddd 4 c4 - c4 bbbbbbbb cc bbbb bbbbbbbb - bbcb 4 4 ccdddddddd b e 44b - c 4 4 cc b cbbbbb - c ddd cc 4 b4c b - bbbb bbbbbbbbbbbb cc cbbb bbcddc b - bbbbbbbbbbbb cc 4 c4 b c c b - b4 c ddddcc bbbbbbb b4c4bc4b - c bbbbbbc 4b cc bbbbbbbb - c4b4 ec b cc 4 - bbbbbbbbbbbb cc -7 e 4 cc 4 7 -7b7b7b7b7b7b7b7b7b7b7b7b77b7b7b7b7b7b7b7b7b7b7b77 diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/10_convert b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/10_convert deleted file mode 100644 index 14a5f70ea..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/goldrunner/levels/10_convert +++ /dev/null @@ -1,16 +0,0 @@ - 8 - 8 4 e -777 8 7777c7777777 - 77 8 77 c - 77 8 77 c -4e 777 8 4777 c 4 -77c7777 8 7777c777c7777777 - c 77 8 77 c - c4e 77c77 c 4 -c777c c 7c77c777 -c c c -c c 4 e c -c c7777777c777777c77777c77 -c c c -c c 0 c -7777777777777777777777777777 diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua deleted file mode 100644 index 89dc031cc..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/3dprint.lua +++ /dev/null @@ -1,119 +0,0 @@ ---[[ - 3D Print - A printing program for use with NPaintPro - - By NitrogenFingers -]]-- - -local activeCommander = -1 -local operatingPrint = false - ---Whether or not the print can be ended -local function endPrint() - operatingPrint = false -end - ---The list of all commands the printer can be ginve -local commandList = { - ["FW"] = { turtle.dig, turtle.forward }; - ["BK"] = turtle.back; - ["UP"] = { turtle.digUp, turtle.up }; - ["DW"] = { turtle.digDown, turtle.down }; - ["TL"] = turtle.turnLeft; - ["TR"] = turtle.turnRight; - ["TU"] = { turtle.turnLeft, turtle.turnLeft }; - ["PF"] = { turtle.dig, turtle.place }; - ["PU"] = { turtle.digUp, turtle.placeUp }; - ["PD"] = { turtle.digDown, turtle.placeDown }; - ["SS"] = turtle.select; - ["RF"] = turtle.refuel; - ["DE"] = endPrint; -} - ---Splits a string according to a pattern into a table -local function split(str, pattern) - local t = { } - local fpat = "(.-)" .. pattern - local last_end = 1 - local s, e, cap = str:find(fpat, 1) - while s do - if s ~= 1 or cap ~= "" then - table.insert(t,cap) - end - last_end = e+1 - s, e, cap = str:find(fpat, last_end) - end - if last_end <= #str then - cap = str:sub(last_end) - table.insert(t, cap) - end - return t -end - ---Listens for any instructions given referring to identification and activation. Once activated, the mode exits. -local function respondToQuery() - while true do - print("Listening for ACT/ID query") - local id,key = rednet.receive() - print("Received : "..key) - - if key == "$3DPRINT IDENTIFY" then - print("Requested Identification") - rednet.send(id, "$3DPRINT IDACK "..os.getComputerLabel()) - - elseif key == "$3DPRINT ACTIVATE" then - print("Requested Activation") - activeCommander = id - rednet.send(id, "$3DPRINT ACTACK") - break - end - end -end - ---Performs the print. Follows instrutions as given, and responds as necessary -local function performPrint() - operatingPrint = true - while operatingPrint do - local id,msg = rednet.receive() - print("Command : "..msg) - - if id == activeCommander and string.find(msg, "$PC") == 1 then - local cmds = split(msg, " ") - - --It's a bit of a hack, but those are the 2 methods required for a refuel - if turtle.getFuelLevel() == 0 and cmds[2] ~= "SS" and cmds[2] ~= "RF" then - rednet.send(id, "$3DPRINT OOF") - elseif (tonumber(cmds[3])) and turtle.getItemCount(tonumber(cmds[3])) == 0 and - turtle.getFuelLevel() ~= 0 then - rednet.send(id, "$3DPRINT DEP") - else - if cmds[2] == "RF" then cmds[3] = "64" end - if type(commandList[cmds[2]]) == "function" then - commandList[cmds[2]](tonumber(cmds[3])) - elseif type(commandList[cmds[2]]) == "table" then - for i=1,#commandList[cmds[2]] do - commandList[cmds[2]][i](tonumber(cmds[3])) - end - end - - rednet.send(activeCommander, "$3DPRINT ACK") - end - end - end -end - -rednet.open("right") -term.clear() -term.setCursorPos(1,1) -if not os.getComputerLabel() then - term.write("Name this computer:") - os.setComputerLabel(io.read()) -end -print("3D printer online") - -while true do - --Wait for activation - respondToQuery() - --Perform the print - performPrint() -end diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua deleted file mode 100644 index dac2bcc78..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/gameutils.lua +++ /dev/null @@ -1,615 +0,0 @@ ---[[ - GameUtil - An API for drawing sprites and animations made in NPaintPro - By NitrogenFingers -]]-- - - ---The back buffer. Initialized as nil -local backbuffer = nil ---The bounds of the terminal the back buffer displays to -local tw,th = nil, nil - ---[[Constructs a new buffer. This must be done before the buffer can written to. - Params: terminal:?table = The function table to draw to a screen. By default (nil) this refers - to the native terminal, but monitor displays can be passed through as well: - local leftMonitor = peripherals.wrap("left") - initializeBuffer(leftMonitor) - Returns:boolean = True if the buffer was successfully initialized; false otherwise -]]-- -function initializeBuffer(terminal) - if not terminal then terminal = term end - if not terminal.getSize then - error("Parameter cannot be used to initialize the backbuffer.") - end - if not terminal.isColour() then - error("Parameter does not represent an advanced computer.") - end - - tw,th = terminal.getSize() - backbuffer = { } - for y=1,th do - backbuffer[y] = { } - end - return true -end - ---[[Will clear the buffer and reset to nil, or to a colour if provided - Params: colour:?number = The colour to set the back buffer to - Returns:nil -]]-- -function clearBuffer(colour) - if not backbuffer then - error("Back buffer not yet initialized!") - end - - for y=1,#backbuffer do - backbuffer[y] = { } - if colour then - for x=1,tw do - backbuffer[y][x] = colour - end - end - end -end - ---[[Draws the given entity to the back buffer - Params: entity:table = the entity to draw to the buffer - Returns:nil -]]-- -function writeToBuffer(entity) - if not backbuffer then - error("Back buffer not yet initialized!") - end - - local image = nil - if entity.type == "animation" then - image = entity.frames[entity.currentFrame] - else - image = entity.image - end - - for y=1,image.dimensions.height do - for x=1,image.dimensions.width do - if image[y][x] then - local xpos,ypos = x,y - if entity.mirror.x then xpos = image.dimensions.width - x + 1 end - if entity.mirror.y then ypos = image.dimensions.height - y + 1 end - - --If the YPos doesn't exist, no need to loop through the rest of X! - --Don't you love optimization? - if not backbuffer[entity.y + ypos - 1] then break end - - backbuffer[entity.y + ypos - 1][entity.x + xpos - 1] = image[y][x] - end - end - end -end - ---[[Draws the contents of the buffer to the screen. This will not clear the screen or the buffer. - Params: terminal:table = the terminal to draw to - Returns:nil -]]-- -function drawBuffer(terminal) - if not backbuffer then - error("Back buffer not yet initialized!") - end - if not terminal then terminal = term end - if not terminal.setCursorPos or not terminal.setBackgroundColour or not terminal.write then - error("Parameter cannot be used to initialize the backbuffer.") - end - if not terminal.isColour() then - error("Parameter does not represent an advanced computer.") - end - - for y=1,math.min(#backbuffer, th) do - for x=1,tw do - if backbuffer[y][x] then - terminal.setCursorPos(x,y) - terminal.setBackgroundColour(backbuffer[y][x]) - terminal.write(" ") - end - end - end -end - ---[[Converts a hex digit into a colour value - Params: hex:?string = the hex digit to be converted - Returns:string A colour value corresponding to the hex, or nil if the character is invalid -]]-- -local function getColourOf(hex) - local value = tonumber(hex, 16) - if not value then return nil end - value = math.pow(2,value) - return value -end - ---[[Converts every pixel of one colour in a given sprite to another colour - Use for "reskinning". Uses OO function. - Params: self:sprite = the sprite to reskin - oldcol:number = the colour to replace - newcol:number = the new colour - Returns:nil -]]-- -local function repaintS(self, oldcol, newcol) - for y=1,self.image.bounds.height do - for x=1, self.image.bounds.width do - if self.image[y][x] == oldcol then - self.image[y][x] = newcol - end - end - end -end - ---[[Converts every pixel of one colour in a given animation to another colour - Use for "reskinning". Uses OO function. - Params: self:animation = the animation to reskin - oldcol:number = the colour to replace - newcol:number = the new colour - Returns:nil -]]-- -local function repaintA(self, oldcol, newcol) - for f=1,#self.frames do - print(self.frames[f].bounds) - for y=1,self.frames[f].bounds.height do - for x=1, self.frames[f].bounds.width do - if self.frames[f][y][x] == oldcol then - self.frames[f][y][x] = newcol - end - end - end - end -end - ---[[Prints the sprite on the screen - Params: self:sprite = the sprite to draw - Returns:nil -]]-- -local function drawS(self) - local image = self.image - - for y=1,image.dimensions.height do - for x=1,image.dimensions.width do - if image[y][x] then - local xpos,ypos = x,y - if self.mirror.x then xpos = image.dimensions.width - x + 1 end - if self.mirror.y then ypos = image.dimensions.height - y + 1 end - - term.setBackgroundColour(image[y][x]) - term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1) - term.write(" ") - end - end - end -end - ---[[Prints the current frame of the animation on screen - Params: self:anim = the animation to draw - frame:?number = the specific frame to draw (default self.currentFrame) - Returns:nil -]]-- -local function drawA(self, frame) - if not frame then frame = self.currentFrame end - local image = self.frames[frame] - - for y=1,image.dimensions.height do - for x=1,image.dimensions.width do - if image[y][x] then - local xpos,ypos = x,y - if self.mirror.x then xpos = image.dimensions.width - x + 1 end - if self.mirror.y then ypos = image.dimensions.height - y + 1 end - - term.setBackgroundColour(image[y][x]) - term.setCursorPos(self.x + xpos - 1, self.y + ypos - 1) - term.write(" ") - end - end - end -end - ---[[Checks the animation timer provided to see whether or not the animation needs to be updated. - If so, it makes the necessary change. - Params: self:animation = the animation to be updated - timerID:number = the ID of the most recent timer event - Returns:bool = true if the animation was update; false otherwise -]]-- -local function updateA(self, timerID) - if self.timerID and timerID and self.timerID == timerID then - self.currentFrame = self.currentFrame + 1 - if self.currentFrame > self.upperBound then - self.currentFrame = self.lowerBound - end - return true - else - return false - end -end - ---[[Moves immediately to the next frame in the sequence, as though an update had been called. - Params: self:animation = the animation to update - Returns:nil -]]-- -local function nextA(self) - self.currentFrame = self.currentFrame + 1 - if self.currentFrame > self.upperBound then - self.currentFrame = self.lowerBound - end -end - ---[[Moves immediately to the previous frame in the sequence - Params: self:animation = the animation to update - Returns:nil -]]-- -local function previousA(self) - self.currentFrame = self.currentFrame - 1 - if self.currentFrame < self.lowerBound then - self.currentFrame = self.upperBound - end -end - ---[[A simple debug function that displays the outline of the bounds - on a given shape. Useful when testing collision detection or other game - features. - Params: entity:table = the bounded entity to represent - colour:?number = the colour to draw the rectangle (default red) - Returns:nil -]]-- -local function drawBounds(entity, colour) - if not colour then colour = colours.red end - local image = nil - if entity.type == "animation" then image = entity.frames[entity.currentFrame] - else image = entity.image end - - term.setBackgroundColour(colour) - - corners = { - topleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y - 1 }; - topright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y - 1 }; - botleft = { x = entity.x + image.bounds.x - 1, y = entity.y + image.bounds.y + image.bounds.height - 2 }; - botright = { x = entity.x + image.bounds.x + image.bounds.width - 2, y = entity.y + image.bounds.y + image.bounds.height - 2 }; - } - - term.setCursorPos(corners.topleft.x, corners.topleft.y) - term.write(" ") - term.setCursorPos(corners.topright.x, corners.topright.y) - term.write(" ") - term.setCursorPos(corners.botleft.x, corners.botleft.y) - term.write(" ") - term.setCursorPos(corners.botright.x, corners.botright.y) - term.write(" ") -end - ---[[Creates a bounding rectangle object. Used in drawing the bounds and the rCollidesWith methods - Params: self:table = the entity to create the rectangle - Returns:table = the left, right, top and bottom edges of the rectangle -]]-- -local function createRectangle(entity) - local image = nil - if entity.type == "animation" then - image = entity.frames[entity.currentFrame] - else - image = entity.image - end - --Note that the origin is always 1, so we subtract 1 for every absolute coordinate we have to test. - return { - left = entity.x + image.bounds.x - 1; - right = entity.x + image.bounds.x + image.bounds.width - 2; - top = entity.y + image.bounds.y - 1; - bottom = entity.y + image.bounds.y + image.bounds.height - 2; - } -end - ---[[Performs a rectangle collision with another given entity. Entity can be of sprite or animation - type (also true of the self). Bases collision using a least squared approach (rectangle precision). - Params: self:sprite,animation = the object in question of the testing - other:sprite,animation = the other object tested for collision - Returns:bool = true if bounding rectangle intersect is true; false otherwse -]]-- -local function rCollidesWith(self, other) - --First we construct the rectangles - local img1C, img2C = createRectangle(self), createRectangle(other) - - --We then determine the "relative position" , in terms of which is farther left or right - leftmost,rightmost,topmost,botmost = nil,nil,nil,nil - if img1C.left < img2C.left then - leftmost = img1C - rightmost = img2C - else - leftmost = img2C - rightmost = img1C - end - if img1C.top < img2C.top then - topmost = img1C - botmost = img2C - else - topmost = img2C - botmost = img1C - end - - --Then we determine the distance between the "extreme" edges- - --distance between leftmost/right edge and rightmost/left edge - --distance between topmost/bottom edge and bottommost/top edge - local xdist = rightmost.left - leftmost.right - local ydist = botmost.top - topmost.bottom - - --If both are negative, our rectangles intersect! - return xdist <= 0 and ydist <= 0 -end - ---[[Performs a pixel collision test on another given entity. Either entity can be of sprite or animation - type. This is done coarsegrain-finegrain, we first find the intersection between the rectangles - (if there is one), and then test the space within that intersection for any intersecting pixels. - Params: self:sprite,animation = the object in question of the testing - other:sprite,animation = the other object being tested for collision - Returns:?number,?number: The X and Y position in which the collision occurred. -]]-- -local function pCollidesWith(self, other) - --Identically to rCollidesWith, we create our rectangles... - local img1C, img2C = createRectangle(self), createRectangle(other) - --We'll also need the images to compare pixels later - local img1, img2 = nil,nil - if self.type == "animation" then img1 = self.frames[self.currentFrame] - else img1 = self.image end - if other.type == "animation" then img2 = other.frames[other.currentFrame] - else img2 = other.image end - - --...then we position them... - leftmost,rightmost,topmost,botmost = nil,nil,nil,nil - --We also keep track of which is left and which is right- it doesn't matter in a rectangle - --collision but it does in a pixel collision. - img1T,img2T = {},{} - - if img1C.left < img2C.left then - leftmost = img1C - rightmost = img2C - img1T.left = true - else - leftmost = img2C - rightmost = img1C - img2T.left = true - end - if img1C.top < img2C.top then - topmost = img1C - botmost = img2C - img1T.top = true - else - topmost = img2C - botmost = img1C - img2T.top = true - end - - --...and we again find the distances between the extreme edges. - local xdist = rightmost.left - leftmost.right - local ydist = botmost.top - topmost.bottom - - --If these distances are > 0 then we stop- no need to go any farther. - if xdist > 0 or ydist > 0 then return false end - - - for x = rightmost.left, rightmost.left + math.abs(xdist) do - for y = botmost.top, botmost.top + math.abs(ydist) do - --We know a collision has occurred if a pixel is occupied by both images. We do this by - --first transforming the coordinates based on which rectangle is which, then testing if a - --pixel is at that point - -- The leftmost and topmost takes the distance on x and y and removes the upper component - -- The rightmost and bottommost, being the farther extremes, compare from 1 upwards - local testX,testY = 1,1 - if img1T.left then testX = x - img1C.left + 1 - else testX = x - img1C.left + 1 end - if img1T.top then testY = y - img1C.top + 1 - else testY = y - img1C.top + 1 end - - local occupy1 = img1[testY + img1.bounds.y-1][testX + img1.bounds.x-1] ~= nil - - if img2T.left then testX = x - img2C.left + 1 - else testX = x - img2C.left + 1 end - if img2T.top then testY = y - img2C.top + 1 - else testY = y - img2C.top + 1 end - - local occupy2 = img2[testY + img2.bounds.y-1][testX + img2.bounds.x-1] ~= nil - - if occupy1 and occupy2 then return true end - end - end - --If the looop terminates without returning, then no pixels overlap - return false -end - ---[[Moves the sprite or animation to the specified coordinates. This performs the auto-centering, so - the user doesn't have to worry about adjusting for the bounds of the shape. Recommended for absolute - positioning operations (as relative direct access to the X will have unexpected results!) - Params: self:table = the animation or sprite to move - x:number = the new x position - y:number = the new y position -]]-- -local function moveTo(self, x, y) - local image = nil - if self.type == "animation" then - image = self.frames[self.currentFrame] - else - image = self.image - end - - self.x = x - image.bounds.x + 1 - self.y = y - image.bounds.y + 1 -end - ---[[ - Sprites Fields: -x:number = the x position of the sprite in the world -y:number = the y position of the sprite in the world -image:table = a table of the image. Indexed by height, a series of sub-tables, each entry being a pixel - at [y][x]. It also contains: - bounds:table = - x:number = the relative x position of the bounding rectangle - y:number = the relative y position of the bounding rectangle - width:number = the width of the bounding rectangle - height:number = the height of the bounding rectangle - dimensions:table = - width = the width of the entire image in pixels - height = the height of the entire image in pixels - -mirror:table = - x:bool = whether or not the image is mirrored on the X axis - y:bool = whether or not the image is mirrored on the Y axis -repaint:function = see repaintS (above) -rCollidesWith:function = see rCollidesWith (above) -pCollidesWith:function = see pCollidesWith (above) -draw:function = see drawS (above) -]]-- - ---[[Loads a new sprite into a table, and returns it to the user. - Params: path:string = the absolute path to the desired sprite - x:number = the initial X position of the sprite - y:number = the initial Y position of the sprite -]]-- -function loadSprite(path, x, y) - local sprite = { - type = "sprite", - x = x, - y = y, - image = { }, - mirror = { x = false, y = false } - } - - if fs.exists(path) then - local file = io.open(path, "r" ) - local leftX, rightX = math.huge, 0 - local topY, botY = nil,nil - - local lcount = 0 - for line in file:lines() do - lcount = lcount+1 - table.insert(sprite.image, {}) - for i=1,#line do - if string.sub(line, i, i) ~= " " then - leftX = math.min(leftX, i) - rightX = math.max(rightX, i) - if not topY then topY = lcount end - botY = lcount - end - sprite.image[#sprite.image][i] = getColourOf(string.sub(line,i,i)) - end - end - file:close() - - sprite.image.bounds = { - x = leftX, - width = rightX - leftX + 1, - y = topY, - height = botY - topY + 1 - } - sprite.image.dimensions = { - width = rightX, - height = botY - } - - sprite.x = sprite.x - leftX + 1 - sprite.y = sprite.y - topY + 1 - - sprite.repaint = repaintS - sprite.rCollidesWith = rCollidesWith - sprite.pCollidesWith = pCollidesWith - sprite.draw = drawS - sprite.moveTo = moveTo - return sprite - else - error(path.." not found!") - end -end - ---Animations contain - --Everything a sprite contains, but the image is a series of frames, not just one image - --An timerID that tracks the last animation - --An upper and lower bound on the active animation - --An update method that takes a timer event and updates the animation if necessary - ---[[ - -]]-- -function loadAnimation(path, x, y, currentFrame) - local anim = { - type = "animation", - x = x, - y = y, - frames = { }, - mirror = { x = false, y = false }, - currentFrame = currentFrame - } - - table.insert(anim.frames, { }) - if fs.exists(path) then - local file = io.open(path, "r") - local leftX, rightX = math.huge, 0 - local topY, botY = nil,nil - - local lcount = 0 - for line in file:lines() do - lcount = lcount+1 - local cFrame = #anim.frames - if line == "~" then - anim.frames[cFrame].bounds = { - x = leftX, - y = topY, - width = rightX - leftX + 1, - height = botY - topY + 1 - } - anim.frames[cFrame].dimensions = { - width = rightX, - height = botY - } - table.insert(anim.frames, { }) - leftX, rightX = math.huge, 0 - topY, botY = nil,nil - lcount = 0 - else - table.insert(anim.frames[cFrame], {}) - for i=1,#line do - if string.sub(line, i, i) ~= " " then - leftX = math.min(leftX, i) - rightX = math.max(rightX, i) - if not topY then topY = lcount end - botY = lcount - end - anim.frames[cFrame][#anim.frames[cFrame]] [i] = getColourOf(string.sub(line,i,i)) - end - end - end - file:close() - local cFrame = #anim.frames - anim.frames[cFrame].bounds = { - x = leftX, - y = topY, - width = rightX - leftX + 1, - height = botY - topY + 1 - } - anim.frames[cFrame].dimensions = { - width = rightX, - height = botY - } - anim.x = anim.x - leftX + 1 - anim.y = anim.y - topY + 1 - - if not currentFrame or type(currentFrame) ~= "number" or currentFrame < 1 or - currentFrame > #anim.frames then - anim.currentFrame = 1 - end - - anim.timerID = nil - anim.lowerBound = 1 - anim.upperBound = #anim.frames - anim.updating = false - - anim.repaint = repaintA - anim.rCollidesWith = rCollidesWith - anim.pCollidesWith = pCollidesWith - anim.draw = drawA - anim.update = updateA - anim.next = nextA - anim.previous = previousA - anim.moveTo = moveTo - return anim - else - error(path.." not found!") - end -end diff --git a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua b/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua deleted file mode 100644 index 826468eb7..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/nitrogenfingers/npaintpro/npaintpro.lua +++ /dev/null @@ -1,2517 +0,0 @@ ---[[ - NPaintPro - By NitrogenFingers -]]-- - ---The screen size -local w,h = term.getSize() ---Whether or not the program is currently waiting on user input -local inMenu = false ---Whether or not a drop down menu is active -local inDropDown = false ---Whether or not animation tools are enabled (use -a to turn them on) -local animated = false ---Whether or not the text tools are enabled (use -t to turn them on) -local textual = false ---Whether or not "blueprint" display mode is on -local blueprint = false ---Whether or not the "layer" display is on -local layerDisplay = false ---Whether or not the "direction" display is on -local printDirection = false ---The tool/mode npaintpro is currently in. Default is "paint" ---For a list of modes, check out the help file -local state = "paint" ---Whether or not the program is presently running -local isRunning = true ---The rednet address of the 3D printer, if one has been attached -local printer = nil - ---The list of every frame, containing every image in the picture/animation ---Note: nfp files always have the picture at frame 1 -local frames = { } ---How many frames are currently in the given animation. -local frameCount = 1 ---The Colour Picker column -local column = {} ---The currently selected left and right colours -local lSel,rSel = colours.white,nil ---The amount of scrolling on the X and Y axis -local sx,sy = 0,0 ---The alpha channel colour ---Change this to change default canvas colour -local alphaC = colours.black ---The currently selected frame. Default is 1 -local sFrame = 1 ---The contents of the image buffer- contains contents, width and height -local buffer = nil ---The position, width and height of the selection rectangle -local selectrect = nil - ---Whether or not text tools are enabled for this document -local textEnabled = false ---The X and Y positions of the text cursor -local textCurX, textCurY = 1,1 - ---The currently calculated required materials -local requiredMaterials = {} ---Whether or not required materials are being displayed in the pallette -local requirementsDisplayed = false ---A list of the rednet ID's all in-range printers located -local printerList = { } ---A list of the names of all in-range printers located. Same as the printerList in reference -local printerNames = { } ---The selected printer -local selectedPrinter = 1 ---The X,Y,Z and facing of the printer -local px,py,pz,pfx,pfz = 0,0,0,0,0 ---The form of layering used -local layering = "up" - ---The animation state of the selection rectangle and image buffer -local rectblink = 0 ---The ID for the timer -local recttimer = nil ---The radius of the brush tool -local brushsize = 3 ---Whether or not "record" mode is activated (animation mode only) -local record = false ---The time between each frame when in play mode (animation mode only) -local animtime = 0.3 - ---The current "cursor position" in text mode -local cursorTexX,cursorTexY = 1,1 - ---A list of hexidecimal conversions from numbers to hex digits -local hexnums = { [10] = "a", [11] = "b", [12] = "c", [13] = "d", [14] = "e" , [15] = "f" } ---The NPaintPro logo (divine, isn't it?) -local logo = { -"fcc 3 339"; -" fcc 9333 33"; -" fcc 933 333 33"; -" fcc 933 33 33"; -" fcc 933 33 33"; -" c88 333 93333"; -" 888 333 9333"; -" 333 3 333 939"; -} ---The Layer Up and Layer Forward printing icons -local layerUpIcon = { - "0000000"; - "0088880"; - "0888870"; - "07777f0"; - "0ffff00"; - "0000000"; -} -local layerForwardIcon = { - "0000000"; - "000fff0"; - "00777f0"; - "0888700"; - "0888000"; - "0000000"; -} ---The available menu options in the ctrl menu -local mChoices = {"Save","Exit"} ---The available modes from the dropdown menu- tables indicate submenus (include a name!) -local ddModes = { { "paint", "brush", "pippette", "flood", "move", "clear", "select", name = "painting" }, { "alpha to left", "alpha to right", name = "display" }, "help", { "print", "save", "exit", name = "file" }, name = "menu" } ---The available modes from the selection right-click menu -local srModes = { "cut", "copy", "paste", "clear", "hide", name = "selection" } ---The list of available help topics for each mode 127 -local helpTopics = { - [1] = { - name = "Paint Mode", - key = nil, - animonly = false, - textonly = false, - message = "The default mode for NPaintPro, for painting pixels." - .." Controls here that are not overridden will apply for all other modes. Leaving a mode by selecting that mode " - .." again will always send the user back to paint mode.", - controls = { - { "Arrow keys", "Scroll the canvas" }, - { "Left Click", "Paint/select left colour" }, - { "Right Click", "Paint/select right colour" }, - { "Z Key", "Clear image on screen" }, - { "Tab Key", "Hide selection rectangle if visible" }, - { "Q Key", "Set alpha mask to left colour" }, - { "W Key", "Set alpha mask to right colour" }, - { "Number Keys", "Swich between frames 1-9" }, - { " keys", "Move to the next/last frame" }, - { "R Key", "Removes every frame after the current frame"} - } - }, - [2] = { - name = "Brush Mode", - key = "b", - animonly = false, - textonly = false, - message = "Brush mode allows painting a circular area of variable diameter rather than a single pixel, working in ".. - "the exact same way as paint mode in all other regards.", - controls = { - { "Left Click", "Paints a brush blob with the left colour" }, - { "Right Click", "Paints a brush blob with the right colour" }, - { "Number Keys", "Changes the radius of the brush blob from 2-9" } - } - }, - [3] = { - name = "Pippette Mode", - key = "p", - animonly = false, - textonly = false, - message = "Pippette mode allows the user to click the canvas and set the colour clicked to the left or right ".. - "selected colour, for later painting.", - controls = { - { "Left Click", "Sets clicked colour to the left selected colour" }, - { "Right Click", "Sets clicked colour to the right selected colour" } - } - }, - [4] = { - name = "Move Mode", - key = "m", - animonly = false, - textonly = false, - message = "Mode mode allows the moving of the entire image on the screen. This is especially useful for justifying".. - " the image to the top-left for animations or game assets.", - controls = { - { "Left/Right Click", "Moves top-left corner of image to selected square" }, - { "Arrow keys", "Moves image one pixel in any direction" } - } - }, - [5] = { - name = "Flood Mode", - key = "f", - animonly = false, - textonly = false, - message = "Flood mode allows the changing of an area of a given colour to that of the selected colour. ".. - "The tool uses a flood4 algorithm and will not fill diagonally. Transparency cannot be flood filled.", - controls = { - { "Left Click", "Flood fills selected area to left colour" }, - { "Right Click", "Flood fills selected area to right colour" } - } - }, - [6] = { - name = "Select Mode", - key = "s", - animonly = false, - textonly = false, - message = "Select mode allows the creation and use of the selection rectangle, to highlight specific areas on ".. - "the screen and perform operations on the selected area of the image. The selection rectangle can contain an ".. - "image on the clipboard- if it does, the image will flash inside the rectangle, and the rectangle edges will ".. - "be light grey instead of dark grey.", - controls = { - { "C Key", "Copy: Moves selection into the clipboard" }, - { "X Key", "Cut: Clears canvas under the rectangle, and moves it into the clipboard" }, - { "V Key", "Paste: Copys clipboard to the canvas" }, - { "Z Key", "Clears clipboard" }, - { "Left Click", "Moves top-left corner of rectangle to selected pixel" }, - { "Right Click", "Opens selection menu" }, - { "Arrow Keys", "Moves rectangle one pixel in any direction" } - } - }, - [7] = { - name = "Corner Select Mode", - key = nil, - animonly = false, - textonly = false, - message = "If a selection rectangle isn't visible, this mode is selected automatically. It allows the ".. - "defining of the corners of the rectangle- one the top-left and bottom-right corners have been defined, ".. - "NPaintPro switches to selection mode. Note rectangle must be at least 2 pixels wide and high.", - controls = { - { "Left/Right Click", "Defines a corner of the selection rectangle" } - } - }, - [8] = { - name = "Play Mode", - key = "space", - animonly = true, - textonly = false, - message = "Play mode will loop through each frame in your animation at a constant rate. Editing tools are ".. - "locked in this mode, and the coordinate display will turn green to indicate it is on.", - controls = { - { " Keys", "Increases/Decreases speed of the animation" }, - { "Space Bar", "Returns to paint mode" } - } - }, - [9] = { - name = "Record Mode", - key = "\\", - animonly = true, - textonly = false, - message = "Record mode is not a true mode, but influences how other modes work. Changes made that modify the ".. - "canvas in record mode will affect ALL frames in the animation. The coordinates will turn red to indicate that ".. - "record mode is on.", - controls = { - { "", "Affects:" }, - { "- Paint Mode", "" }, - { "- Brush Mode", "" }, - { "- Cut and Paste in Select Mode", ""}, - { "- Move Mode", ""} - } - }, - [10] = { - name = "Help Mode", - key = "h", - animonly = false, - textonly = false, - message = "Displays this help screen. Clicking on options will display help on that topic. Clicking out of the screen".. - " will leave this mode.", - controls = { - { "Left/Right Click", "Displays a topic/Leaves the mode" } - } - }, - [11] = { - name = "File Mode", - key = nil, - animonly = false, - textonly = false, - message = "Clicking on the mode display at the bottom of the screen will open the options menu. Here you can".. - " activate all of the modes in the program with a simple mouse click. Pressing left control will open up the".. - " file menu automatically.", - controls = { - { "leftCtrl", "Opens the file menu" }, - { "leftAlt", "Opens the paint menu" } - } - }, - [12] = { - name = "Text Mode", - key = "t", - animonly = false, - textonly = true, - message = "In this mode, the user is able to type letters onto the document for display. The left colour ".. - "pallette value determines what colour the text will be, and the right determines what colour the background ".. - "will be (set either to nil to keep the same colours as already there).", - controls = { - { "Backspace", "Deletes the character on the previous line" }, - { "Arrow Keys", "Moves the cursor in any direction" }, - { "Left Click", "Moves the cursor to beneath the mouse cursor" } - } - }, - [13] = { - name = "Textpaint Mode", - key = "y", - animonly = false, - textonly = true, - message = "Allows the user to paint any text on screen to the desired colour with the mouse. If affects the text colour".. - " values rather than the background values, but operates identically to paint mode in all other regards.", - controls = { - { "Left Click", "Paints the text with the left colour" }, - { "Right Click", "Paints the text with the right colour" } - } - }, - [14] = { - name = "About NPaintPro", - keys = nil, - animonly = false, - textonly = false, - message = "NPaintPro: The feature-bloated paint program for ComputerCraft by Nitrogen Fingers.", - controls = { - { "Testers:", " "}, - { " ", "Faubiguy"}, - { " ", "TheOriginalBIT"} - } - } -} ---The "bounds" of the image- the first/last point on both axes where a pixel appears -local toplim,botlim,leflim,riglim = nil,nil,nil,nil ---The selected path -local sPath = nil - ---[[ - Section: Helpers -]]-- - ---[[Converts a colour parameter into a single-digit hex coordinate for the colour - Params: colour:int = The colour to be converted - Returns:string A string conversion of the colour -]]-- -local function getHexOf(colour) - if not colour or not tonumber(colour) then - return " " - end - local value = math.log(colour)/math.log(2) - if value > 9 then - value = hexnums[value] - end - return value -end - ---[[Converts a hex digit into a colour value - Params: hex:?string = the hex digit to be converted - Returns:string A colour value corresponding to the hex, or nil if the character is invalid -]]-- -local function getColourOf(hex) - local value = tonumber(hex, 16) - if not value then return nil end - value = math.pow(2,value) - return value -end - ---[[Finds the biggest and smallest bounds of the image- the outside points beyond which pixels do not appear - These values are assigned to the "lim" parameters for access by other methods - Params: forAllFrames:bool = True if all frames should be used to find bounds, otherwise false or nil - Returns:nil -]]-- -local function updateImageLims(forAllFrames) - local f,l = sFrame,sFrame - if forAllFrames == true then f,l = 1,framecount end - - toplim,botlim,leflim,riglim = nil,nil,nil,nil - for locf = f,l do - for y,_ in pairs(frames[locf]) do - if type(y) == "number" then - for x,_ in pairs(frames[locf][y]) do - if frames[locf][y][x] ~= nil then - if leflim == nil or x < leflim then leflim = x end - if toplim == nil or y < toplim then toplim = y end - if riglim == nil or x > riglim then riglim = x end - if botlim == nil or y > botlim then botlim = y end - end - end - end - end - end - - --There is just... no easier way to do this. It's horrible, but necessary - if textEnabled then - for locf = f,l do - for y,_ in pairs(frames[locf].text) do - for x,_ in pairs(frames[locf].text[y]) do - if frames[locf].text[y][x] ~= nil then - if leflim == nil or x < leflim then leflim = x end - if toplim == nil or y < toplim then toplim = y end - if riglim == nil or x > riglim then riglim = x end - if botlim == nil or y > botlim then botlim = y end - end - end - end - for y,_ in pairs(frames[locf].textcol) do - for x,_ in pairs(frames[locf].textcol[y]) do - if frames[locf].textcol[y][x] ~= nil then - if leflim == nil or x < leflim then leflim = x end - if toplim == nil or y < toplim then toplim = y end - if riglim == nil or x > riglim then riglim = x end - if botlim == nil or y > botlim then botlim = y end - end - end - end - end - end -end - ---[[Determines how much of each material is required for a print. Done each time printing is called. - Params: none - Returns:table A complete list of how much of each material is required. -]]-- -function calculateMaterials() - updateImageLims(animated) - requiredMaterials = {} - for i=1,16 do - requiredMaterials[i] = 0 - end - - if not toplim then return end - - for i=1,#frames do - for y = toplim, botlim do - for x = leflim, riglim do - if type(frames[i][y][x]) == "number" then - requiredMaterials[math.log(frames[i][y][x],10)/math.log(2,10) + 1] = - requiredMaterials[math.log(frames[i][y][x],10)/math.log(2,10) + 1] + 1 - end - end - end - end -end - - ---[[Updates the rectangle blink timer. Should be called anywhere events are captured, along with a timer capture. - Params: nil - Returns:nil -]]-- -local function updateTimer(id) - if id == recttimer then - recttimer = os.startTimer(0.5) - rectblink = (rectblink % 2) + 1 - end -end - ---[[Constructs a message based on the state currently selected - Params: nil - Returns:string A message regarding the state of the application -]]-- -local function getStateMessage() - local msg = " "..string.upper(string.sub(state, 1, 1))..string.sub(state, 2, #state).." mode" - if state == "brush" then msg = msg..", size="..brushsize end - return msg -end - ---[[Calls the rednet_message event, but also looks for timer events to keep then - system timer ticking. - Params: timeout:number how long before the event times out - Returns:number the id of the sender - :number the message send -]]-- -local function rsTimeReceive(timeout) - local timerID - if timeout then timerID = os.startTimer(timeout) end - - local id,key,msg = nil,nil - while true do - id,key,msg = os.pullEvent() - - if id == "timer" then - if key == timerID then return - else updateTimer(key) end - end - if id == "rednet_message" then - return key,msg - end - end -end - ---[[Draws a picture, in paint table format on the screen - Params: image:table = the image to display - xinit:number = the x position of the top-left corner of the image - yinit:number = the y position of the top-left corner of the image - alpha:number = the color to display for the alpha channel. Default is white. - Returns:nil -]]-- -local function drawPictureTable(image, xinit, yinit, alpha) - if not alpha then alpha = 1 end - for y=1,#image do - for x=1,#image[y] do - term.setCursorPos(xinit + x-1, yinit + y-1) - local col = getColourOf(string.sub(image[y], x, x)) - if not col then col = alpha end - term.setBackgroundColour(col) - term.write(" ") - end - end -end - ---[[ - Section: Loading -]]-- - ---[[Loads a non-animted paint file into the program - Params: path:string = The path in which the file is located - Returns:nil -]]-- -local function loadNFP(path) - sFrame = 1 - frames[sFrame] = { } - if fs.exists(path) then - local file = io.open(path, "r" ) - local sLine = file:read() - local num = 1 - while sLine do - table.insert(frames[sFrame], num, {}) - for i=1,#sLine do - frames[sFrame][num][i] = getColourOf(string.sub(sLine,i,i)) - end - num = num+1 - sLine = file:read() - end - file:close() - end -end - ---[[Loads a text-paint file into the program - Params: path:string = The path in which the file is located - Returns:nil -]]-- -local function loadNFT(path) - sFrame = 1 - frames[sFrame] = { } - frames[sFrame].text = { } - frames[sFrame].textcol = { } - - if fs.exists(path) then - local file = io.open(path, "r") - local sLine = file:read() - local num = 1 - while sLine do - table.insert(frames[sFrame], num, {}) - table.insert(frames[sFrame].text, num, {}) - table.insert(frames[sFrame].textcol, num, {}) - - --As we're no longer 1-1, we keep track of what index to write to - local writeIndex = 1 - --Tells us if we've hit a 30 or 31 (BG and FG respectively)- next char specifies the curr colour - local bgNext, fgNext = false, false - --The current background and foreground colours - local currBG, currFG = nil,nil - term.setCursorPos(1,1) - for i=1,#sLine do - local nextChar = string.sub(sLine, i, i) - if nextChar:byte() == 30 then - bgNext = true - elseif nextChar:byte() == 31 then - fgNext = true - elseif bgNext then - currBG = getColourOf(nextChar) - bgNext = false - elseif fgNext then - currFG = getColourOf(nextChar) - fgNext = false - else - if nextChar ~= " " and currFG == nil then - currFG = colours.white - end - frames[sFrame][num][writeIndex] = currBG - frames[sFrame].textcol[num][writeIndex] = currFG - frames[sFrame].text[num][writeIndex] = nextChar - writeIndex = writeIndex + 1 - end - end - num = num+1 - sLine = file:read() - end - file:close() - end -end - ---[[Loads an animated paint file into the program - Params: path:string = The path in which the file is located - Returns:nil -]]-- -local function loadNFA(path) - frames[sFrame] = { } - if fs.exists(path) then - local file = io.open(path, "r" ) - local sLine = file:read() - local num = 1 - while sLine do - table.insert(frames[sFrame], num, {}) - if sLine == "~" then - sFrame = sFrame + 1 - frames[sFrame] = { } - num = 1 - else - for i=1,#sLine do - frames[sFrame][num][i] = getColourOf(string.sub(sLine,i,i)) - end - num = num+1 - end - sLine = file:read() - end - file:close() - end - framecount = sFrame - sFrame = 1 -end - ---[[Saves a non-animated paint file to the specified path - Params: path:string = The path to save the file to - Returns:nil -]]-- -local function saveNFP(path) - local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath)) - if not fs.exists(sDir) then - fs.makeDir(sDir) - end - - local file = io.open(path, "w") - updateImageLims(false) - if not toplim then - file:close() - return - end - for y=1,botlim do - local line = "" - if frames[sFrame][y] then - for x=1,riglim do - line = line..getHexOf(frames[sFrame][y][x]) - end - end - file:write(line.."\n") - end - file:close() -end - ---[[Saves a text-paint file to the specified path - Params: path:string = The path to save the file to - Returns:nil -]]-- -local function saveNFT(path) - local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath)) - if not fs.exists(sDir) then - fs.makeDir(sDir) - end - - local file = io.open(path, "w") - updateImageLims(false) - if not toplim then - file:close() - return - end - for y=1,botlim do - local line = "" - local currBG, currFG = nil,nil - for x=1,riglim do - if frames[sFrame][y] and frames[sFrame][y][x] ~= currBG then - line = line..string.char(30)..getHexOf(frames[sFrame][y][x]) - currBG = frames[sFrame][y][x] - end - if frames[sFrame].textcol[y] and frames[sFrame].textcol[y][x] ~= currFG then - line = line..string.char(31)..getHexOf(frames[sFrame].textcol[y][x]) - currFG = frames[sFrame].textcol[y][x] - end - if frames[sFrame].text[y] then - local char = frames[sFrame].text[y][x] - if not char then char = " " end - line = line..char - end - end - file:write(line.."\n") - end - file:close() -end - ---[[Saves a animated paint file to the specified path - Params: path:string = The path to save the file to - Returns:nil -]]-- -local function saveNFA(path) - local sDir = string.sub(sPath, 1, #sPath - #fs.getName(sPath)) - if not fs.exists(sDir) then - fs.makeDir(sDir) - end - - local file = io.open(path, "w") - updateImageLims(true) - if not toplim then - file:close() - return - end - for i=1,#frames do - for y=1,botlim do - local line = "" - if frames[i][y] then - for x=1,riglim do - line = line..getHexOf(frames[i][y][x]) - end - end - file:write(line.."\n") - end - if i < #frames then file:write("~\n") end - end - file:close() -end - - ---[[Initializes the program, by loading in the paint file. Called at the start of each program. - Params: none - Returns:nil -]]-- -local function init() - if textEnabled then - loadNFT(sPath) - table.insert(ddModes, 2, { "text", "textpaint", name = "text"}) - elseif animated then - loadNFA(sPath) - table.insert(ddModes, #ddModes, { "record", "play", name = "anim" }) - table.insert(ddModes, #ddModes, { "go to", "remove", name = "frames"}) - table.insert(ddModes[2], #ddModes[2], "blueprint on") - table.insert(ddModes[2], #ddModes[2], "layers on") - else - loadNFP(sPath) - table.insert(ddModes[2], #ddModes[2], "blueprint on") - end - - for i=0,15 do - table.insert(column, math.pow(2,i)) - end -end - ---[[ - Section: Drawing -]]-- - - ---[[Draws the rather superflous logo. Takes about 1 second, before user is able to move to the - actual program. - Params: none - Returns:nil -]]-- -local function drawLogo() - term.setBackgroundColour(colours.white) - term.clear() - drawPictureTable(logo, w/2 - #logo[1]/2, h/2 - #logo/2, colours.white) - term.setBackgroundColour(colours.white) - term.setTextColour(colours.black) - local msg = "NPaintPro" - term.setCursorPos(w/2 - #msg/2, h-3) - term.write(msg) - msg = "By NitrogenFingers" - term.setCursorPos(w/2 - #msg/2, h-2) - term.write(msg) - - os.pullEvent() -end - ---[[Clears the display to the alpha channel colour, draws the canvas, the image buffer and the selection - rectanlge if any of these things are present. - Params: none - Returns:nil -]]-- -local function drawCanvas() - --We have to readjust the position of the canvas if we're printing - turtlechar = "@" - if state == "active print" then - if layering == "up" then - if py >= 1 and py <= #frames then - sFrame = py - end - if pz < sy then sy = pz - elseif pz > sy + h - 1 then sy = pz + h - 1 end - if px < sx then sx = px - elseif px > sx + w - 2 then sx = px + w - 2 end - else - if pz >= 1 and pz <= #frames then - sFrame = pz - end - - if py < sy then sy = py - elseif py > sy + h - 1 then sy = py + h - 1 end - if px < sx then sx = px - elseif px > sx + w - 2 then sx = px + w - 2 end - end - - if pfx == 1 then turtlechar = ">" - elseif pfx == -1 then turtlechar = "<" - elseif pfz == 1 then turtlechar = "V" - elseif pfz == -1 then turtlechar = "^" - end - end - - --Picture next - local topLayer, botLayer - if layerDisplay then - topLayer = sFrame - botLayer = 1 - else - topLayer,botLayer = sFrame,sFrame - end - - for currframe = botLayer,topLayer,1 do - for y=sy+1,sy+h-1 do - if frames[currframe][y] then - for x=sx+1,sx+w-2 do - term.setCursorPos(x-sx,y-sy) - if frames[currframe][y][x] then - term.setBackgroundColour(frames[currframe][y][x]) - if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then - term.setTextColour(frames[currframe].textcol[y][x]) - term.write(frames[currframe].text[y][x]) - else - term.write(" ") - end - else - tileExists = false - for i=currframe-1,botLayer,-1 do - if frames[i][y][x] then - tileExists = true - break - end - end - - if not tileExists then - if blueprint then - term.setBackgroundColour(colours.blue) - term.setTextColour(colours.white) - if x == sx+1 and y % 4 == 1 then - term.write(""..((y/4) % 10)) - elseif y == sy + 1 and x % 4 == 1 then - term.write(""..((x/4) % 10)) - elseif x % 2 == 1 and y % 2 == 1 then - term.write("+") - elseif x % 2 == 1 then - term.write("|") - elseif y % 2 == 1 then - term.write("-") - else - term.write(" ") - end - else - term.setBackgroundColour(alphaC) - if textEnabled and frames[currframe].textcol[y][x] and frames[currframe].text[y][x] then - term.setTextColour(frames[currframe].textcol[y][x]) - term.write(frames[currframe].text[y][x]) - else - term.write(" ") - end - end - end - end - end - else - for x=sx+1,sx+w-2 do - term.setCursorPos(x-sx,y-sy) - - tileExists = false - for i=currframe-1,botLayer,-1 do - if frames[i][y] and frames[i][y][x] then - tileExists = true - break - end - end - - if not tileExists then - if blueprint then - term.setBackgroundColour(colours.blue) - term.setTextColour(colours.white) - if x == sx+1 and y % 4 == 1 then - term.write(""..((y/4) % 10)) - elseif y == sy + 1 and x % 4 == 1 then - term.write(""..((x/4) % 10)) - elseif x % 2 == 1 and y % 2 == 1 then - term.write("+") - elseif x % 2 == 1 then - term.write("|") - elseif y % 2 == 1 then - term.write("-") - else - term.write(" ") - end - else - term.setBackgroundColour(alphaC) - term.write(" ") - end - end - end - end - end - end - - --Then the printer, if he's on - if state == "active print" then - local bgColour = alphaC - if layering == "up" then - term.setCursorPos(px-sx,pz-sy) - if frames[sFrame] and frames[sFrame][pz-sy] and frames[sFrame][pz-sy][px-sx] then - bgColour = frames[sFrame][pz-sy][px-sx] - elseif blueprint then bgColour = colours.blue end - else - term.setCursorPos(px-sx,py-sy) - if frames[sFrame] and frames[sFrame][py-sy] and frames[sFrame][py-sy][px-sx] then - bgColour = frames[sFrame][py-sy][px-sx] - elseif blueprint then bgColour = colours.blue end - end - - term.setBackgroundColour(bgColour) - if bgColour == colours.black then term.setTextColour(colours.white) - else term.setTextColour(colours.black) end - - term.write(turtlechar) - end - - --Then the buffer - if selectrect then - if buffer and rectblink == 1 then - for y=selectrect.y1, math.min(selectrect.y2, selectrect.y1 + buffer.height-1) do - for x=selectrect.x1, math.min(selectrect.x2, selectrect.x1 + buffer.width-1) do - if buffer.contents[y-selectrect.y1+1][x-selectrect.x1+1] then - term.setCursorPos(x+sx,y+sy) - term.setBackgroundColour(buffer.contents[y-selectrect.y1+1][x-selectrect.x1+1]) - term.write(" ") - end - end - end - end - - --This draws the "selection" box - local add = nil - if buffer then - term.setBackgroundColour(colours.lightGrey) - else - term.setBackgroundColour(colours.grey) - end - for i=selectrect.x1, selectrect.x2 do - add = (i + selectrect.y1 + rectblink) % 2 == 0 - term.setCursorPos(i-sx,selectrect.y1-sy) - if add then term.write(" ") end - add = (i + selectrect.y2 + rectblink) % 2 == 0 - term.setCursorPos(i-sx,selectrect.y2-sy) - if add then term.write(" ") end - end - for i=selectrect.y1 + 1, selectrect.y2 - 1 do - add = (i + selectrect.x1 + rectblink) % 2 == 0 - term.setCursorPos(selectrect.x1-sx,i-sy) - if add then term.write(" ") end - add = (i + selectrect.x2 + rectblink) % 2 == 0 - term.setCursorPos(selectrect.x2-sx,i-sy) - if add then term.write(" ") end - end - end -end - ---[[Draws the colour picker on the right side of the screen, the colour pallette and the footer with any - messages currently being displayed - Params: none - Returns:nil -]]-- -local function drawInterface() - --Picker - for i=1,#column do - term.setCursorPos(w-1, i) - term.setBackgroundColour(column[i]) - if state == "print" then - if i == 16 then - term.setTextColour(colours.white) - else - term.setTextColour(colours.black) - end - if requirementsDisplayed then - if requiredMaterials[i] < 10 then term.write(" ") end - term.setCursorPos(w-#tostring(requiredMaterials[i])+1, i) - term.write(requiredMaterials[i]) - else - if i < 10 then term.write(" ") end - term.write(i) - end - else - term.write(" ") - end - end - term.setCursorPos(w-1,#column+1) - term.setBackgroundColour(colours.black) - term.setTextColour(colours.red) - term.write("XX") - --Pallette - term.setCursorPos(w-1,h-1) - if not lSel then - term.setBackgroundColour(colours.black) - term.setTextColour(colours.red) - term.write("X") - else - term.setBackgroundColour(lSel) - term.setTextColour(lSel) - term.write(" ") - end - if not rSel then - term.setBackgroundColour(colours.black) - term.setTextColour(colours.red) - term.write("X") - else - term.setBackgroundColour(rSel) - term.setTextColour(rSel) - term.write(" ") - end - --Footer - if inMenu then return end - - term.setCursorPos(1, h) - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - term.clearLine() - if inDropDown then - term.write(string.rep(" ", 6)) - else - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - term.write("menu ") - end - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - term.write(getStateMessage()) - - local coords="X:"..sx.." Y:"..sy - if animated then coords = coords.." Frame:"..sFrame.."/"..framecount.." " end - term.setCursorPos(w-#coords+1,h) - if state == "play" then term.setBackgroundColour(colours.lime) - elseif record then term.setBackgroundColour(colours.red) end - term.write(coords) - - if animated then - term.setCursorPos(w-1,h) - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - term.write("<>") - end -end - ---[[Runs an interface where users can select topics of help. Will return once the user quits the help screen. - Params: none - Returns:nil -]]-- -local function drawHelpScreen() - local selectedHelp = nil - while true do - term.setBackgroundColour(colours.lightGrey) - term.clear() - if not selectedHelp then - term.setCursorPos(4, 1) - term.setTextColour(colours.brown) - term.write("Available modes (click for info):") - for i=1,#helpTopics do - term.setCursorPos(2, 2 + i) - term.setTextColour(colours.black) - term.write(helpTopics[i].name) - if helpTopics[i].key then - term.setTextColour(colours.red) - term.write(" ("..helpTopics[i].key..")") - end - end - term.setCursorPos(4,h) - term.setTextColour(colours.black) - term.write("Press any key to exit") - else - term.setCursorPos(4,1) - term.setTextColour(colours.brown) - term.write(helpTopics[selectedHelp].name) - if helpTopics[selectedHelp].key then - term.setTextColour(colours.red) - term.write(" ("..helpTopics[selectedHelp].key..")") - end - term.setCursorPos(1,3) - term.setTextColour(colours.black) - print(helpTopics[selectedHelp].message.."\n") - for i=1,#helpTopics[selectedHelp].controls do - term.setTextColour(colours.brown) - term.write(helpTopics[selectedHelp].controls[i][1].." ") - term.setTextColour(colours.black) - print(helpTopics[selectedHelp].controls[i][2]) - end - end - - local id,p1,p2,p3 = os.pullEvent() - - if id == "timer" then updateTimer(p1) - elseif id == "key" then - if selectedHelp then selectedHelp = nil - else break end - elseif id == "mouse_click" then - if not selectedHelp then - if p3 >=3 and p3 <= 2+#helpTopics then - selectedHelp = p3-2 - else break end - else - selectedHelp = nil - end - end - end -end - ---[[Draws a message in the footer bar. A helper for DrawInterface, but can be called for custom messages, if the - inMenu paramter is set to true while this is being done (remember to set it back when done!) - Params: message:string = The message to be drawn - Returns:nil -]]-- -local function drawMessage(message) - term.setCursorPos(1,h) - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - term.clearLine() - term.write(message) -end - ---[[ - Section: Generic Interfaces -]]-- - - ---[[One of my generic text printing methods, printing a message at a specified position with width and offset. - No colour materials included. - Params: msg:string = The message to print off-center - height:number = The starting height of the message - width:number = The limit as to how many characters long each line may be - offset:number = The starting width offset of the message - Returns:number the number of lines used in printing the message -]]-- -local function wprintOffCenter(msg, height, width, offset) - local inc = 0 - local ops = 1 - while #msg - ops > width do - local nextspace = 0 - while string.find(msg, " ", ops + nextspace) and - string.find(msg, " ", ops + nextspace) - ops < width do - nextspace = string.find(msg, " ", nextspace + ops) + 1 - ops - end - local ox,oy = term.getCursorPos() - term.setCursorPos(width/2 - (nextspace)/2 + offset, height + inc) - inc = inc + 1 - term.write(string.sub(msg, ops, nextspace + ops - 1)) - ops = ops + nextspace - end - term.setCursorPos(width/2 - #string.sub(msg, ops)/2 + offset, height + inc) - term.write(string.sub(msg, ops)) - - return inc + 1 -end - ---[[Draws a message that must be clicked on or a key struck to be cleared. No options, so used for displaying - generic information. - Params: ctitle:string = The title of the confirm dialogue - msg:string = The message displayed in the dialogue - Returns:nil -]]-- -local function displayConfirmDialogue(ctitle, msg) - local dialogoffset = 8 - --We actually print twice- once to get the lines, second time to print proper. Easier this way. - local lines = wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2) - - term.setCursorPos(dialogoffset, 3) - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - term.write(string.rep(" ", w - dialogoffset * 2)) - term.setCursorPos(dialogoffset + (w - dialogoffset * 2)/2 - #ctitle/2, 3) - term.write(ctitle) - term.setTextColour(colours.grey) - term.setBackgroundColour(colours.lightGrey) - term.setCursorPos(dialogoffset, 4) - term.write(string.rep(" ", w - dialogoffset * 2)) - for i=5,5+lines do - term.setCursorPos(dialogoffset, i) - term.write(" "..string.rep(" ", w - (dialogoffset) * 2 - 2).." ") - end - wprintOffCenter(msg, 5, w - (dialogoffset+2) * 2, dialogoffset + 2) - - --In the event of a message, the player hits anything to continue - while true do - local id,key = os.pullEvent() - if id == "timer" then updateTimer(key); - elseif id == "key" or id == "mouse_click" or id == "mouse_drag" then break end - end -end - ---[[Produces a nice dropdown menu based on a table of strings. Depending on the position, this will auto-adjust the position - of the menu drawn, and allows nesting of menus and sub menus. Clicking anywhere outside the menu will cancel and return nothing - Params: x:int = the x position the menu should be displayed at - y:int = the y position the menu should be displayed at - options:table = the list of options available to the user, as strings or submenus (tables of strings, with a name parameter) - Returns:string the selected menu option. -]]-- -local function displayDropDown(x, y, options) - inDropDown = true - --Figures out the dimensions of our thing - local longestX = #options.name - for i=1,#options do - local currVal = options[i] - if type(currVal) == "table" then currVal = currVal.name end - - longestX = math.max(longestX, #currVal) - end - local xOffset = math.max(0, longestX - ((w-2) - x) + 1) - local yOffset = math.max(0, #options - ((h-1) - y)) - - local clickTimes = 0 - local tid = nil - local selection = nil - while clickTimes < 2 do - drawCanvas() - drawInterface() - - term.setCursorPos(x-xOffset,y-yOffset) - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - term.write(options.name..string.rep(" ", longestX-#options.name + 2)) - - for i=1,#options do - term.setCursorPos(x-xOffset, y-yOffset+i) - if i==selection and clickTimes % 2 == 0 then - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - else - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - end - local currVal = options[i] - if type(currVal) == "table" then - term.write(currVal.name..string.rep(" ", longestX-#currVal.name + 1)) - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - term.write(">") - else - term.write(currVal..string.rep(" ", longestX-#currVal + 2)) - end - end - - local id, p1, p2, p3 = os.pullEvent() - if id == "timer" then - if p1 == tid then - clickTimes = clickTimes + 1 - if clickTimes > 2 then - break - else - tid = os.startTimer(0.1) - end - else - updateTimer(p1) - drawCanvas() - drawInterface() - end - elseif id == "mouse_click" then - if p2 >=x-xOffset and p2 <= x-xOffset + longestX + 1 and p3 >= y-yOffset+1 and p3 <= y-yOffset+#options then - selection = p3-(y-yOffset) - tid = os.startTimer(0.1) - else - selection = "" - break - end - end - end - - if type(selection) == "number" then - selection = options[selection] - end - - if type(selection) == "string" then - inDropDown = false - return selection - elseif type(selection) == "table" then - return displayDropDown(x, y, selection) - end -end - ---[[A custom io.read() function with a few differences- it limits the number of characters being printed, - waits a 1/100th of a second so any keys still in the event library are removed before input is read and - the timer for the selectionrectangle is continuously updated during the process. - Params: lim:int = the number of characters input is allowed - Returns:string the inputted string, trimmed of leading and tailing whitespace -]]-- -local function readInput(lim) - term.setCursorBlink(true) - - local inputString = "" - if not lim or type(lim) ~= "number" or lim < 1 then lim = w - ox end - local ox,oy = term.getCursorPos() - --We only get input from the footer, so this is safe. Change if recycling - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - term.write(string.rep(" ", lim)) - term.setCursorPos(ox, oy) - --As events queue immediately, we may get an unwanted key... this will solve that problem - local inputTimer = os.startTimer(0.01) - local keysAllowed = false - - while true do - local id,key = os.pullEvent() - - if keysAllowed then - if id == "key" and key == 14 and #inputString > 0 then - inputString = string.sub(inputString, 1, #inputString-1) - term.setCursorPos(ox + #inputString,oy) - term.write(" ") - elseif id == "key" and key == 28 and inputString ~= string.rep(" ", #inputString) then - break - elseif id == "key" and key == keys.leftCtrl then - return "" - elseif id == "char" and #inputString < lim then - inputString = inputString..key - end - end - - if id == "timer" then - if key == inputTimer then - keysAllowed = true - else - updateTimer(key) - drawCanvas() - drawInterface() - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - end - end - term.setCursorPos(ox,oy) - term.write(inputString) - term.setCursorPos(ox + #inputString, oy) - end - - while string.sub(inputString, 1, 1) == " " do - inputString = string.sub(inputString, 2, #inputString) - end - while string.sub(inputString, #inputString, #inputString) == " " do - inputString = string.sub(inputString, 1, #inputString-1) - end - term.setCursorBlink(false) - - return inputString -end - ---[[ - Section: Image tools -]]-- - - ---[[Copies all pixels beneath the selection rectangle into the image buffer. Empty buffers are converted to nil. - Params: removeImage:bool = true if the image is to be erased after copying, false otherwise - Returns:nil -]]-- -local function copyToBuffer(removeImage) - buffer = { width = selectrect.x2 - selectrect.x1 + 1, height = selectrect.y2 - selectrect.y1 + 1, contents = { } } - - local containsSomething = false - for y=1,buffer.height do - buffer.contents[y] = { } - local f,l = sFrame,sFrame - if record then f,l = 1, framecount end - - for fra = f,l do - if frames[fra][selectrect.y1 + y - 1] then - for x=1,buffer.width do - buffer.contents[y][x] = frames[sFrame][selectrect.y1 + y - 1][selectrect.x1 + x - 1] - if removeImage then frames[fra][selectrect.y1 + y - 1][selectrect.x1 + x - 1] = nil end - if buffer.contents[y][x] then containsSomething = true end - end - end - end - end - --I don't classify an empty buffer as a real buffer- confusing to the user. - if not containsSomething then buffer = nil end -end - ---[[Replaces all pixels under the selection rectangle with the image buffer (or what can be seen of it). Record-dependent. - Params: removeBuffer:bool = true if the buffer is to be emptied after copying, false otherwise - Returns:nil -]]-- -local function copyFromBuffer(removeBuffer) - if not buffer then return end - - for y = 1, math.min(buffer.height,selectrect.y2-selectrect.y1+1) do - local f,l = sFrame, sFrame - if record then f,l = 1, framecount end - - for fra = f,l do - if not frames[fra][selectrect.y1+y-1] then frames[fra][selectrect.y1+y-1] = { } end - for x = 1, math.min(buffer.width,selectrect.x2-selectrect.x1+1) do - frames[fra][selectrect.y1+y-1][selectrect.x1+x-1] = buffer.contents[y][x] - end - end - end - - if removeBuffer then buffer = nil end -end - ---[[Moves the entire image (or entire animation) to the specified coordinates. Record-dependent. - Params: newx:int = the X coordinate to move the image to - newy:int = the Y coordinate to move the image to - Returns:nil -]]-- -local function moveImage(newx,newy) - if not leflim or not toplim then return end - if newx <=0 or newy <=0 then return end - local f,l = sFrame,sFrame - if record then f,l = 1,framecount end - - for i=f,l do - local newlines = { } - for y=toplim,botlim do - local line = frames[i][y] - if line then - newlines[y-toplim+newy] = { } - for x,char in pairs(line) do - newlines[y-toplim+newy][x-leflim+newx] = char - end - end - end - --Exceptions that allow us to move the text as well - if textEnabled then - newlines.text = { } - for y=toplim,botlim do - local line = frames[i].text[y] - if line then - newlines.text[y-toplim+newy] = { } - for x,char in pairs(line) do - newlines.text[y-toplim+newy][x-leflim+newx] = char - end - end - end - - newlines.textcol = { } - for y=toplim,botlim do - local line = frames[i].textcol[y] - if line then - newlines.textcol[y-toplim+newy] = { } - for x,char in pairs(line) do - newlines.textcol[y-toplim+newy][x-leflim+newx] = char - end - end - end - end - - frames[i] = newlines - end -end - ---[[Prompts the user to clear the current frame or all frames. Record-dependent., - Params: none - Returns:nil -]]-- -local function clearImage() - inMenu = true - if not animated then - drawMessage("Clear image? Y/N: ") - elseif record then - drawMessage("Clear ALL frames? Y/N: ") - else - drawMessage("Clear current frame? Y/N :") - end - if string.find(string.upper(readInput(1)), "Y") then - local f,l = sFrame,sFrame - if record then f,l = 1,framecount end - - for i=f,l do - frames[i] = { } - end - end - inMenu = false -end - ---[[A recursively called method (watch out for big calls!) in which every pixel of a set colour is - changed to another colour. Does not work on the nil colour, for obvious reasons. - Params: x:int = The X coordinate of the colour to flood-fill - y:int = The Y coordinate of the colour to flood-fill - targetColour:colour = the colour that is being flood-filled - newColour:colour = the colour with which to replace the target colour - Returns:nil -]]-- -local function floodFill(x, y, targetColour, newColour) - if not newColour or not targetColour then return end - local nodeList = { } - - table.insert(nodeList, {x = x, y = y}) - - while #nodeList > 0 do - local node = nodeList[1] - if frames[sFrame][node.y] and frames[sFrame][node.y][node.x] == targetColour then - frames[sFrame][node.y][node.x] = newColour - table.insert(nodeList, { x = node.x + 1, y = node.y}) - table.insert(nodeList, { x = node.x, y = node.y + 1}) - if x > 1 then table.insert(nodeList, { x = node.x - 1, y = node.y}) end - if y > 1 then table.insert(nodeList, { x = node.x, y = node.y - 1}) end - end - table.remove(nodeList, 1) - end -end - ---[[ - Section: Animation Tools -]]-- - ---[[Enters play mode, allowing the animation to play through. Interface is restricted to allow this, - and method only leaves once the player leaves play mode. - Params: none - Returns:nil -]]-- -local function playAnimation() - state = "play" - selectedrect = nil - - local animt = os.startTimer(animtime) - repeat - drawCanvas() - drawInterface() - - local id,key,_,y = os.pullEvent() - - if id=="timer" then - if key == animt then - animt = os.startTimer(animtime) - sFrame = (sFrame % framecount) + 1 - else - updateTimer(key) - end - elseif id=="key" then - if key == keys.comma and animtime > 0.1 then animtime = animtime - 0.05 - elseif key == keys.period and animtime < 0.5 then animtime = animtime + 0.05 - elseif key == keys.space then state = "paint" end - elseif id=="mouse_click" and y == h then - state = "paint" - end - until state ~= "play" - os.startTimer(0.5) -end - ---[[Changes the selected frame (sFrame) to the chosen frame. If this frame is above the framecount, - additional frames are created with a copy of the image on the selected frame. - Params: newframe:int = the new frame to move to - Returns:nil -]]-- -local function changeFrame(newframe) - inMenu = true - if not tonumber(newframe) then - term.setCursorPos(1,h) - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.grey) - term.clearLine() - - term.write("Go to frame: ") - newframe = tonumber(readInput(2)) - if not newframe or newframe <= 0 then - inMenu = false - return - end - elseif newframe <= 0 then return end - - if newframe > framecount then - for i=framecount+1,newframe do - frames[i] = {} - for y,line in pairs(frames[sFrame]) do - frames[i][y] = { } - for x,v in pairs(line) do - frames[i][y][x] = v - end - end - end - framecount = newframe - end - sFrame = newframe - inMenu = false -end - ---[[Removes every frame leading after the frame passed in - Params: frame:int the non-inclusive lower bounds of the delete - Returns:nil -]]-- -local function removeFramesAfter(frame) - inMenu = true - if frame==framecount then return end - drawMessage("Remove frames "..(frame+1).."/"..framecount.."? Y/N :") - local answer = string.upper(readInput(1)) - - if string.find(answer, string.upper("Y")) ~= 1 then - inMenu = false - return - end - - for i=frame+1, framecount do - frames[i] = nil - end - framecount = frame - inMenu = false -end - ---[[ - Section: Printing Tools -]]-- - ---[[Constructs a new facing to the left of the current facing - Params: curx:number = The facing on the X axis - curz:number = The facing on the Z axis - hand:string = The hand of the axis ("right" or "left") - Returns:number,number = the new facing on the X and Z axis after a left turn -]]-- -local function getLeft(curx, curz) - local hand = "left" - if layering == "up" then hand = "right" end - - if hand == "right" then - if curx == 1 then return 0,-1 end - if curx == -1 then return 0,1 end - if curz == 1 then return 1,0 end - if curz == -1 then return -1,0 end - else - if curx == 1 then return 0,1 end - if curx == -1 then return 0,-1 end - if curz == 1 then return -1,0 end - if curz == -1 then return 1,0 end - end -end - ---[[Constructs a new facing to the right of the current facing - Params: curx:number = The facing on the X axis - curz:number = The facing on the Z axis - hand:string = The hand of the axis ("right" or "left") - Returns:number,number = the new facing on the X and Z axis after a right turn -]]-- -local function getRight(curx, curz) - local hand = "left" - if layering == "up" then hand = "right" end - - if hand == "right" then - if curx == 1 then return 0,1 end - if curx == -1 then return 0,-1 end - if curz == 1 then return -1,0 end - if curz == -1 then return 1,0 end - else - if curx == 1 then return 0,-1 end - if curx == -1 then return 0,1 end - if curz == 1 then return 1,0 end - if curz == -1 then return -1,0 end - end -end - - ---[[Sends out a rednet signal requesting local printers, and will listen for any responses. Printers found are added to the - printerList (for ID's) and printerNames (for names) - Params: nil - Returns:nil -]]-- -local function locatePrinters() - printerList = { } - printerNames = { name = "Printers" } - local oldState = state - state = "Locating printers, please wait... " - drawCanvas() - drawInterface() - state = oldState - - local modemOpened = false - for k,v in pairs(rs.getSides()) do - if peripheral.isPresent(v) and peripheral.getType(v) == "modem" then - rednet.open(v) - modemOpened = true - break - end - end - - if not modemOpened then - displayConfirmDialogue("Modem not found!", "No modem peripheral. Must have network modem to locate printers.") - return false - end - - rednet.broadcast("$3DPRINT IDENTIFY") - - while true do - local id, msg = rsTimeReceive(1) - - if not id then break end - if string.find(msg, "$3DPRINT IDACK") == 1 then - msg = string.gsub(msg, "$3DPRINT IDACK ", "") - table.insert(printerList, id) - table.insert(printerNames, msg) - end - end - - if #printerList == 0 then - displayConfirmDialogue("Printers not found!", "No active printers found in proximity of this computer.") - return false - else - return true - end -end - ---[[Sends a request to the printer. Waits on a response and updates the state of the application accordingly. - Params: command:string the command to send - param:string a parameter to send, if any - Returns:nil -]]-- -local function sendPC(command,param) - local msg = "$PC "..command - if param then msg = msg.." "..param end - rednet.send(printerList[selectedPrinter], msg) - - while true do - local id,key = rsTimeReceive() - if id == printerList[selectedPrinter] then - if key == "$3DPRINT ACK" then - break - elseif key == "$3DPRINT DEP" then - displayConfirmDialogue("Printer Empty", "The printer has exhasted a material. Please refill slot "..param.. - ", and click this message when ready to continue.") - rednet.send(printerList[selectedPrinter], msg) - elseif key == "$3DPRINT OOF" then - displayConfirmDialogue("Printer Out of Fuel", "The printer has no fuel. Please replace the material ".. - "in slot 1 with a fuel source, then click this message.") - rednet.send(printerList[selectedPrinter], "$PC SS 1") - id,key = rsTimeReceive() - rednet.send(printerList[selectedPrinter], "$PC RF") - id,key = rsTimeReceive() - rednet.send(printerList[selectedPrinter], msg) - end - end - end - - --Changes to position are handled after the event has been successfully completed - if command == "FW" then - px = px + pfx - pz = pz + pfz - elseif command == "BK" then - px = px - pfx - pz = pz - pfz - elseif command == "UP" then - if layering == "up" then - py = py + 1 - else - py = py - 1 - end - elseif command == "DW" then - if layering == "up" then - py = py - 1 - else - py = py + 1 - end - elseif command == "TL" then - pfx,pfz = getLeft(pfx,pfz) - elseif command == "TR" then - pfx,pfz = getRight(pfx,pfz) - elseif command == "TU" then - pfx = -pfx - pfz = -pfz - end - - drawCanvas() - drawInterface() -end - ---[[A printing function that commands the printer to turn to face the desired direction, if it is not already doing so - Params: desx:number = the normalized x direction to face - desz:number = the normalized z direction to face - Returns:nil -]]-- -local function turnToFace(desx,desz) - if desx ~= 0 then - if pfx ~= desx then - local temppfx,_ = getLeft(pfx,pfz) - if temppfx == desx then - sendPC("TL") - elseif temppfx == -desx then - sendPC("TR") - else - sendPC("TU") - end - end - else - print("on the z axis") - if pfz ~= desz then - local _,temppfz = getLeft(pfx,pfz) - if temppfz == desz then - sendPC("TL") - elseif temppfz == -desz then - sendPC("TR") - else - sendPC("TU") - end - end - end -end - ---[[Performs the print - Params: nil - Returns:nil -]]-- -local function performPrint() - state = "active print" - if layering == "up" then - --An up layering starts our builder bot on the bottom left corner of our build - px,py,pz = leflim, 0, botlim + 1 - pfx,pfz = 0,-1 - - --We move him forward and up a bit from his original position. - sendPC("FW") - sendPC("UP") - --For each layer that needs to be completed, we go up by one each time - for layers=1,#frames do - --We first decide if we're going forwards or back, depending on what side we're on - local rowbot,rowtop,rowinc = nil,nil,nil - if pz == botlim then - rowbot,rowtop,rowinc = botlim,toplim,-1 - else - rowbot,rowtop,rowinc = toplim,botlim,1 - end - - for rows = rowbot,rowtop,rowinc do - --Then we decide if we're going left or right, depending on what side we're on - local linebot,linetop,lineinc = nil,nil,nil - if px == leflim then - --Facing from the left side has to be easterly- it's changed here - turnToFace(1,0) - linebot,linetop,lineinc = leflim,riglim,1 - else - --Facing from the right side has to be westerly- it's changed here - turnToFace(-1,0) - linebot,linetop,lineinc = riglim,leflim,-1 - end - - for lines = linebot,linetop,lineinc do - --We move our turtle forward, placing the right material at each step - local material = frames[py][pz][px] - if material then - material = math.log10(frames[py][pz][px])/math.log10(2) + 1 - sendPC("SS", material) - sendPC("PD") - end - if lines ~= linetop then - sendPC("FW") - end - end - - --The printer then has to do a U-turn, depending on which way he's facing and - --which way he needs to go - local temppfx,temppfz = getLeft(pfx,pfz) - if temppfz == rowinc and rows ~= rowtop then - sendPC("TL") - sendPC("FW") - sendPC("TL") - elseif temppfz == -rowinc and rows ~= rowtop then - sendPC("TR") - sendPC("FW") - sendPC("TR") - end - end - --Now at the end of a run he does a 180 and moves up to begin the next part of the print - sendPC("TU") - if layers ~= #frames then - sendPC("UP") - end - end - --All done- now we head back to where we started. - if px ~= leflim then - turnToFace(-1,0) - while px ~= leflim do - sendPC("FW") - end - end - if pz ~= botlim then - turnToFace(0,-1) - while pz ~= botlim do - sendPC("BK") - end - end - turnToFace(0,-1) - sendPC("BK") - while py > 0 do - sendPC("DW") - end - else - --The front facing is at the top-left corner, facing south not north - px,py,pz = leflim, botlim, 1 - pfx,pfz = 0,1 - --We move the printer to the last layer- he prints from the back forwards - while pz < #frames do - sendPC("FW") - end - - --For each layer in the frame we build our wall, the move back - for layers = 1,#frames do - --We first decide if we're going left or right based on our position - local rowbot,rowtop,rowinc = nil,nil,nil - if px == leflim then - rowbot,rowtop,rowinc = leflim,riglim,1 - else - rowbot,rowtop,rowinc = riglim,leflim,-1 - end - - for rows = rowbot,rowtop,rowinc do - --Then we decide if we're going up or down, depending on our given altitude - local linebot,linetop,lineinc = nil,nil,nil - if py == botlim then - linebot,linetop,lineinc = botlim,toplim,-1 - else - linebot,linetop,lineinc = toplim,botlim,1 - end - - for lines = linebot,linetop,lineinc do - --We move our turtle up/down, placing the right material at each step - local material = frames[pz][py][px] - if material then - material = math.log10(frames[pz][py][px])/math.log10(2) + 1 - sendPC("SS", material) - sendPC("PF") - end - if lines ~= linetop then - if lineinc == 1 then sendPC("DW") - else sendPC("UP") end - end - end - - if rows ~= rowtop then - turnToFace(rowinc,0) - sendPC("FW") - turnToFace(0,1) - end - end - - if layers ~= #frames then - sendPC("TU") - sendPC("FW") - sendPC("TU") - end - end - --He's easy to reset - while px ~= leflim do - turnToFace(-1,0) - sendPC("FW") - end - turnToFace(0,1) - end - - sendPC("DE") - - displayConfirmDialogue("Print complete", "The 3D print was successful.") -end - ---[[ - Section: Interface -]]-- - ---[[Runs the printing interface. Allows users to find/select a printer, the style of printing to perform and to begin the operation - Params: none - Returns:boolean true if printing was started, false otherwse -]]-- -local function runPrintInterface() - calculateMaterials() - --There's nothing on canvas yet! - if not botlim then - displayConfirmDialogue("Cannot Print Empty Canvas", "There is nothing on canvas that ".. - "can be printed, and the operation cannot be completed.") - return false - end - --No printers nearby - if not locatePrinters() then - return false - end - - layering = "up" - requirementsDisplayed = false - selectedPrinter = 1 - while true do - drawCanvas() - term.setBackgroundColour(colours.lightGrey) - for i=1,10 do - term.setCursorPos(1,i) - term.clearLine() - end - drawInterface() - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.black) - - local msg = "3D Printing" - term.setCursorPos(w/2-#msg/2 - 2, 1) - term.write(msg) - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - if(requirementsDisplayed) then - msg = "Count:" - else - msg = " Slot:" - end - term.setCursorPos(w-3-#msg, 1) - term.write(msg) - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.black) - - term.setCursorPos(7, 2) - term.write("Layering") - drawPictureTable(layerUpIcon, 3, 3, colours.white) - drawPictureTable(layerForwardIcon, 12, 3, colours.white) - if layering == "up" then - term.setBackgroundColour(colours.red) - else - term.setBackgroundColour(colours.lightGrey) - end - term.setCursorPos(3, 9) - term.write("Upwards") - if layering == "forward" then - term.setBackgroundColour(colours.red) - else - term.setBackgroundColour(colours.lightGrey) - end - term.setCursorPos(12, 9) - term.write("Forward") - - term.setBackgroundColour(colours.lightGrey) - term.setTextColour(colours.black) - term.setCursorPos(31, 2) - term.write("Printer ID") - term.setCursorPos(33, 3) - if #printerList > 1 then - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - else - term.setTextColour(colours.red) - end - term.write(" "..printerNames[selectedPrinter].." ") - - term.setBackgroundColour(colours.grey) - term.setTextColour(colours.lightGrey) - term.setCursorPos(25, 10) - term.write(" Cancel ") - term.setCursorPos(40, 10) - term.write(" Print ") - - local id, p1, p2, p3 = os.pullEvent() - - if id == "timer" then - updateTimer(p1) - elseif id == "mouse_click" then - --Layering Buttons - if p2 >= 3 and p2 <= 9 and p3 >= 3 and p3 <= 9 then - layering = "up" - elseif p2 >= 12 and p2 <= 18 and p3 >= 3 and p3 <= 9 then - layering = "forward" - --Count/Slot - elseif p2 >= w - #msg - 3 and p2 <= w - 3 and p3 == 1 then - requirementsDisplayed = not requirementsDisplayed - --Printer ID - elseif p2 >= 33 and p2 <= 33 + #printerNames[selectedPrinter] and p3 == 3 and #printerList > 1 then - local chosenName = displayDropDown(33, 3, printerNames) - for i=1,#printerNames do - if printerNames[i] == chosenName then - selectedPrinter = i - break; - end - end - --Print and Cancel - elseif p2 >= 25 and p2 <= 32 and p3 == 10 then - break - elseif p2 >= 40 and p2 <= 46 and p3 == 10 then - rednet.send(printerList[selectedPrinter], "$3DPRINT ACTIVATE") - ready = false - while true do - local id,msg = rsTimeReceive(10) - - if id == printerList[selectedPrinter] and msg == "$3DPRINT ACTACK" then - ready = true - break - end - end - if ready then - performPrint() - break - else - displayConfirmDialogue("Printer Didn't Respond", "The printer didn't respond to the activation command. Check to see if it's online") - end - end - end - end - state = "paint" -end - ---[[This function changes the current paint program to another tool or mode, depending on user input. Handles - any necessary changes in logic involved in that. - Params: mode:string = the name of the mode to change to - Returns:nil -]]-- -local function performSelection(mode) - if not mode or mode == "" then return - - elseif mode == "help" then - drawHelpScreen() - - elseif mode == "blueprint on" then - blueprint = true - ddModes[2][3] = "blueprint off" - - elseif mode == "blueprint off" then - blueprint = false - ddModes[2][3] = "blueprint on" - - elseif mode == "layers on" then - layerDisplay = true - ddModes[2][4] = "layers off" - - elseif mode == "layers off" then - layerDisplay = false - ddModes[2][4] = "layers on" - - elseif mode == "direction on" then - printDirection = true - ddModes[2][5] = "direction off" - - elseif mode == "direction off" then - printDirection = false - ddModes[2][5] = "direction on" - - elseif mode == "go to" then - changeFrame() - - elseif mode == "remove" then - removeFramesAfter(sFrame) - - elseif mode == "play" then - playAnimation() - - elseif mode == "copy" then - if selectrect and selectrect.x1 ~= selectrect.x2 then - copyToBuffer(false) - end - - elseif mode == "cut" then - if selectrect and selectrect.x1 ~= selectrect.x2 then - copyToBuffer(true) - end - - elseif mode == "paste" then - if selectrect and selectrect.x1 ~= selectrect.x2 then - copyFromBuffer(false) - end - - elseif mode == "hide" then - selectrect = nil - if state == "select" then state = "corner select" end - - elseif mode == "alpha to left" then - if lSel then alphaC = lSel end - - elseif mode == "alpha to right" then - if rSel then alphaC = rSel end - - elseif mode == "record" then - record = not record - - elseif mode == "clear" then - if state=="select" then buffer = nil - else clearImage() end - - elseif mode == "select" then - if state=="corner select" or state=="select" then - state = "paint" - elseif selectrect and selectrect.x1 ~= selectrect.x2 then - state = "select" - else - state = "corner select" - end - - elseif mode == "print" then - state = "print" - runPrintInterface() - state = "paint" - - elseif mode == "save" then - if animated then saveNFA(sPath) - elseif textEnabled then saveNFT(sPath) - else saveNFP(sPath) end - - elseif mode == "exit" then - isRunning = false - - elseif mode ~= state then state = mode - else state = "paint" - - end -end - ---[[The main function of the program, reads and handles all events and updates them accordingly. Mode changes, - painting to the canvas and general selections are done here. - Params: none - Returns:nil -]]-- -local function handleEvents() - recttimer = os.startTimer(0.5) - while isRunning do - drawCanvas() - drawInterface() - - if state == "text" then - term.setCursorPos(textCurX - sx, textCurY - sy) - term.setCursorBlink(true) - end - - local id,p1,p2,p3 = os.pullEvent() - term.setCursorBlink(false) - if id=="timer" then - updateTimer(p1) - elseif id=="mouse_click" or id=="mouse_drag" then - if p2 >=w-1 and p3 < #column+1 then - if p1==1 then lSel = column[p3] - else rSel = column[p3] end - elseif p2 >=w-1 and p3==#column+1 then - if p1==1 then lSel = nil - else rSel = nil end - elseif p2==w-1 and p3==h and animated then - changeFrame(sFrame-1) - elseif p2==w and p3==h and animated then - changeFrame(sFrame+1) - elseif p2 < w-10 and p3==h then - local sel = displayDropDown(1, h-1, ddModes) - performSelection(sel) - elseif p2 < w-1 and p3 <= h-1 then - if state=="pippette" then - if p1==1 then - if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then - lSel = frames[sFrame][p3+sy][p2+sx] - end - elseif p1==2 then - if frames[sFrame][p3+sy] and frames[sFrame][p3+sy][p2+sx] then - rSel = frames[sFrame][p3+sy][p2+sx] - end - end - elseif state=="move" then - updateImageLims(record) - moveImage(p2,p3) - elseif state=="flood" then - if p1 == 1 and lSel and frames[sFrame][p3+sy] then - floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],lSel) - elseif p1 == 2 and rSel and frames[sFrame][p3+sy] then - floodFill(p2,p3,frames[sFrame][p3+sy][p2+sx],rSel) - end - elseif state=="corner select" then - if not selectrect then - selectrect = { x1=p2+sx, x2=p2+sx, y1=p3+sy, y2=p3+sy } - elseif selectrect.x1 ~= p2+sx and selectrect.y1 ~= p3+sy then - if p2+sx w + sx - 2 then sx = textCurX - w + 2 end - elseif tonumber(p1) then - if state=="brush" and tonumber(p1) > 1 then - brushsize = tonumber(p1) - elseif animated and tonumber(p1) > 0 then - changeFrame(tonumber(p1)) - end - end - elseif id=="key" then - --Text needs special handlers (all other keyboard shortcuts are of course reserved for typing) - if state=="text" then - if p1==keys.backspace and textCurX > 1 then - textCurX = textCurX-1 - if frames[sFrame].text[textCurY] then - frames[sFrame].text[textCurY][textCurX] = nil - frames[sFrame].textcol[textCurY][textCurX] = nil - end - if textCurX < sx then sx = textCurX end - elseif p1==keys.left and textCurX > 1 then - textCurX = textCurX-1 - if textCurX-1 < sx then sx = textCurX-1 end - elseif p1==keys.right then - textCurX = textCurX+1 - if textCurX > w + sx - 2 then sx = textCurX - w + 2 end - elseif p1==keys.up and textCurY > 1 then - textCurY = textCurY-1 - if textCurY-1 < sy then sy = textCurY-1 end - elseif p1==keys.down then - textCurY = textCurY+1 - if textCurY > h + sy - 1 then sy = textCurY - h + 1 end - end - - elseif p1==keys.leftCtrl then - local sel = displayDropDown(1, h-1, ddModes[#ddModes]) - performSelection(sel) - elseif p1==keys.leftAlt then - local sel = displayDropDown(1, h-1, ddModes[1]) - performSelection(sel) - elseif p1==keys.h then - performSelection("help") - elseif p1==keys.x then - performSelection("cut") - elseif p1==keys.c then - performSelection("copy") - elseif p1==keys.v then - performSelection("paste") - elseif p1==keys.z then - performSelection("clear") - elseif p1==keys.s then - performSelection("select") - elseif p1==keys.tab then - performSelection("hide") - elseif p1==keys.q then - performSelection("alpha to left") - elseif p1==keys.w then - performSelection("alpha to right") - elseif p1==keys.f then - performSelection("flood") - elseif p1==keys.b then - performSelection("brush") - elseif p1==keys.m then - performSelection("move") - elseif p1==keys.backslash and animated then - performSelection("record") - elseif p1==keys.p then - performSelection("pippette") - elseif p1==keys.g and animated then - performSelection("go to") - elseif p1==keys.period and animated then - changeFrame(sFrame+1) - elseif p1==keys.comma and animated then - changeFrame(sFrame-1) - elseif p1==keys.r and animated then - performSelection("remove") - elseif p1==keys.space and animated then - performSelection("play") - elseif p1==keys.t and textEnabled then - performSelection("text") - sleep(0.01) - elseif p1==keys.y and textEnabled then - performSelection("textpaint") - elseif p1==keys.left then - if state == "move" and toplim then - updateImageLims(record) - if toplim and leflim then - moveImage(leflim-1,toplim) - end - elseif state=="select" and selectrect.x1 > 1 then - selectrect.x1 = selectrect.x1-1 - selectrect.x2 = selectrect.x2-1 - elseif sx > 0 then sx=sx-1 end - elseif p1==keys.right then - if state == "move" then - updateImageLims(record) - if toplim and leflim then - moveImage(leflim+1,toplim) - end - elseif state=="select" then - selectrect.x1 = selectrect.x1+1 - selectrect.x2 = selectrect.x2+1 - else sx=sx+1 end - elseif p1==keys.up then - if state == "move" then - updateImageLims(record) - if toplim and leflim then - moveImage(leflim,toplim-1) - end - elseif state=="select" and selectrect.y1 > 1 then - selectrect.y1 = selectrect.y1-1 - selectrect.y2 = selectrect.y2-1 - elseif sy > 0 then sy=sy-1 end - elseif p1==keys.down then - if state == "move" then - updateImageLims(record) - if toplim and leflim then - moveImage(leflim,toplim+1) - end - elseif state=="select" then - selectrect.y1 = selectrect.y1+1 - selectrect.y2 = selectrect.y2+1 - else sy=sy+1 end - end - end - end -end - ---[[ - Section: Main -]]-- - -if not term.isColour() then - printError("Requires an Advanced Computer") - return -end - ---Taken almost directly from edit (for consistency) -local tArgs = {...} - -local ca = 1 - -if tArgs[ca] == "-a" then - animated = true - ca = ca + 1 -end - -if tArgs[ca] == "-t" then - textEnabled = true - ca = ca + 1 -end - -if #tArgs < ca then - print("Usage: npaintpro [-a,-t] ") - return -end - ---Yeah you can't have animated text files YET... I haven't supported that, maybe later? -if animated and textEnabled then - print("No support for animated text files- cannot have both -a and -t") -end - -sPath = shell.resolve(tArgs[ca]) -local bReadOnly = fs.isReadOnly(sPath) -if fs.exists(sPath) then - if fs.isDir(sPath) then - print("Cannot edit a directory.") - return - elseif string.find(sPath, ".nfp") ~= #sPath-3 and string.find(sPath, ".nfa") ~= #sPath-3 and - string.find(sPath, ".nft") ~= #sPath-3 then - print("Can only edit .nfp, .nft and .nfa files:",string.find(sPath, ".nfp"),#sPath-3) - return - end - - if string.find(sPath, ".nfa") == #sPath-3 then - animated = true - end - - if string.find(sPath, ".nft") == #sPath-3 then - textEnabled = true - end - - if string.find(sPath, ".nfp") == #sPath-3 and animated then - print("Convert to nfa? Y/N") - if string.find(string.lower(io.read()), "y") then - local nsPath = string.sub(sPath, 1, #sPath-1).."a" - fs.move(sPath, nsPath) - sPath = nsPath - else - animated = false - end - end - - --Again this is possible, I just haven't done it. Maybe I will? - if textEnabled and (string.find(sPath, ".nfp") == #sPath-3 or string.find(sPath, ".nfa") == #sPath-3) then - print("Cannot convert to nft") - end -else - if not animated and not textEnabled and string.find(sPath, ".nfp") ~= #sPath-3 then - sPath = sPath..".nfp" - elseif animated and string.find(sPath, ".nfa") ~= #sPath-3 then - sPath = sPath..".nfa" - elseif textEnabled and string.find(sPath, ".nft") ~= #sPath-3 then - sPath = sPath..".nft" - end -end - -drawLogo() -init() -handleEvents() - -term.setBackgroundColour(colours.black) -shell.run("clear") diff --git a/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua b/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua deleted file mode 100644 index 2a1a447a4..000000000 --- a/src/main/resources/data/computercraft/lua/treasure/vilsol/gameoflife/gameoflife.lua +++ /dev/null @@ -1,178 +0,0 @@ -board = {} -tArgs = { ... } -generation = 0 -sleeptime = 0.5 - -if(tArgs[1] == "left" or tArgs[1] == "right" or tArgs[1] == "top" or tArgs[1] == "bottom" or tArgs[1] == "front" or tArgs[1] == "back")then - mon = peripheral.wrap(tArgs[1]) -else - mon = term -end - -if(mon.isColor() or mon.isColor)then - colored = true -else - colored = false -end - -w, h = mon.getSize() -for x = 1, w do - board[x] = {} - for y = 1, h do - board[x][y] = 0 - end -end - -function drawScreen() - w, h = mon.getSize() - for x = 1, w do - for y = 1, h do - nei = getNeighbours(x, y) - if(board[x][y] == 1)then - if colored then - if(nei < 2 or nei > 3)then - mon.setBackgroundColor(colors.red) - else - mon.setBackgroundColor(colors.green) - end - else - mon.setBackgroundColor(colors.white) - end - else - if colored then - if(nei == 3)then - mon.setBackgroundColor(colors.yellow) - else - mon.setBackgroundColor(colors.black) - end - else - mon.setBackgroundColor(colors.black) - end - end - mon.setCursorPos(x, y) - mon.write(" ") - end - end - mon.setCursorPos(1,1) - if colored then - mon.setTextColor(colors.blue) - end - mon.write(generation) -end - -function getNeighbours(x, y) - w, h = mon.getSize() - total = 0 - if(x > 1 and y > 1)then if(board[x-1][y-1] == 1)then total = total + 1 end end - if(y > 1)then if(board[x][y-1] == 1)then total = total + 1 end end - if(x < w and y > 1)then if(board[x+1][y-1] == 1)then total = total + 1 end end - if(x > 1)then if(board[x-1][y] == 1)then total = total + 1 end end - if(x < w)then if(board[x+1][y] == 1)then total = total + 1 end end - if(x > 1 and y < h)then if(board[x-1][y+1] == 1)then total = total + 1 end end - if(y < h)then if(board[x][y+1] == 1)then total = total + 1 end end - if(x < w and y < h)then if(board[x+1][y+1] == 1)then total = total + 1 end end - return total -end - -function compute() - w, h = mon.getSize() - while true do - newBoard = {} - for x = 1, w do - newBoard[x] = {} - for y = 1, h do - nei = getNeighbours(x, y) - if(board[x][y] == 1)then - if(nei < 2)then - newBoard[x][y] = 0 - elseif(nei > 3)then - newBoard[x][y] = 0 - else - newBoard[x][y] = 1 - end - else - if(nei == 3)then - newBoard[x][y] = 1 - end - end - end - end - board = newBoard - generation = generation + 1 - sleep(sleeptime) - end -end - -function loop() - while true do - event, variable, xPos, yPos = os.pullEvent() - if event == "mouse_click" or event == "monitor_touch" or event == "mouse_drag" then - if variable == 1 then - board[xPos][yPos] = 1 - else - board[xPos][yPos] = 0 - end - end - if event == "key" then - if tostring(variable) == "28" then - return true - elseif tostring(variable) == "57" then - if(mon.isColor() or mon.isColor)then - colored = not colored - end - elseif tostring(variable) == "200" then - if sleeptime > 0.1 then - sleeptime = sleeptime - 0.1 - end - elseif tostring(variable) == "208" then - if sleeptime < 1 then - sleeptime = sleeptime + 0.1 - end - end - end - drawScreen() - end -end - -function intro() - mon.setBackgroundColor(colors.black) - mon.clear() - mon.setCursorPos(1,1) - mon.write("Conway's Game Of Life") - mon.setCursorPos(1,2) - mon.write("It is a game which represents life.") - mon.setCursorPos(1,3) - mon.write("The game runs by 4 basic rules:") - mon.setCursorPos(1,4) - mon.write("1. If a cell has less than 2 neighbours, it dies.") - mon.setCursorPos(1,5) - mon.write("2. If a cell has 2 or 3 neightbours, it lives.") - mon.setCursorPos(1,6) - mon.write("3. If a cell has more than 3 neighbours, it dies.") - mon.setCursorPos(1,7) - mon.write("4. If a cell has exactly 3 neighbours it is born.") - mon.setCursorPos(1,9) - mon.write("At the top left is the generation count.") - mon.setCursorPos(1,10) - mon.write("Press spacebar to switch between color modes") - mon.setCursorPos(1,11) - mon.write("Press enter to start the game") - mon.setCursorPos(1,13) - mon.write("Colors:") - mon.setCursorPos(1,14) - mon.write("Red - Cell will die in next generation") - mon.setCursorPos(1,15) - mon.write("Green - Cell will live in next generation") - mon.setCursorPos(1,16) - mon.write("Yellow - Cell will be born in next generation") - mon.setCursorPos(1,18) - mon.write("Press any key to continue!") - event, variable, xPos, yPos = os.pullEvent("key") -end - -intro() -drawScreen() -while true do - loop() - parallel.waitForAny(loop, compute) -end From 9f87eda5def567372398a34f675a948431ca9ff5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 30 Apr 2020 11:19:46 +0100 Subject: [PATCH 203/711] Load treasure disks from various loot tables --- .../loot_tables/treasure_disk.json | 1 + .../computercraft/client/ClientRegistry.java | 2 +- .../dan200/computercraft/data/LootTables.java | 6 +++ .../proxy/ComputerCraftProxyCommon.java | 37 +++++++++++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/generated/resources/data/computercraft/loot_tables/treasure_disk.json diff --git a/src/generated/resources/data/computercraft/loot_tables/treasure_disk.json b/src/generated/resources/data/computercraft/loot_tables/treasure_disk.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/treasure_disk.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 7f0338538..3da3090d3 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -116,7 +116,7 @@ public final class ClientRegistry event.getItemColors().register( ( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF, - ComputerCraft.Items.disk + ComputerCraft.Items.disk, ComputerCraft.Items.treasureDisk ); event.getItemColors().register( ( stack, layer ) -> { diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index 02db8551e..57854429a 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -9,6 +9,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; +import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; import net.minecraft.block.Block; import net.minecraft.data.DataGenerator; import net.minecraft.util.ResourceLocation; @@ -41,6 +42,11 @@ public class LootTables extends LootTableProvider computerDrop( add, ComputerCraft.Blocks.computerAdvanced ); computerDrop( add, ComputerCraft.Blocks.turtleNormal ); computerDrop( add, ComputerCraft.Blocks.turtleAdvanced ); + + add.accept( ComputerCraftProxyCommon.ForgeHandlers.LOOT_TREASURE_DISK, LootTable + .builder() + .setParameterSet( LootParameterSets.GENERIC ) + .build() ); } private static void basicDrop( BiConsumer add, Block block ) diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 27a45a406..6a1981402 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -31,7 +31,12 @@ import net.minecraft.item.MusicDiscItem; import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.storage.loot.ConstantRange; +import net.minecraft.world.storage.loot.LootPool; +import net.minecraft.world.storage.loot.LootTables; +import net.minecraft.world.storage.loot.TableLootEntry; import net.minecraft.world.storage.loot.conditions.LootConditionManager; +import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -41,6 +46,10 @@ import net.minecraftforge.fml.event.server.FMLServerStartedEvent; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class ComputerCraftProxyCommon { @@ -167,5 +176,33 @@ public final class ComputerCraftProxyCommon WirelessNetwork.resetNetworks(); Tracking.reset(); } + + public static final ResourceLocation LOOT_TREASURE_DISK = new ResourceLocation( ComputerCraft.MOD_ID, "treasure_disk" ); + + private static final Set TABLES = new HashSet<>( Arrays.asList( + LootTables.CHESTS_SIMPLE_DUNGEON, + LootTables.CHESTS_ABANDONED_MINESHAFT, + LootTables.CHESTS_STRONGHOLD_CORRIDOR, + LootTables.CHESTS_STRONGHOLD_CROSSING, + LootTables.CHESTS_STRONGHOLD_LIBRARY, + LootTables.CHESTS_DESERT_PYRAMID, + LootTables.CHESTS_JUNGLE_TEMPLE, + LootTables.CHESTS_IGLOO_CHEST, + LootTables.CHESTS_WOODLAND_MANSION, + LootTables.CHESTS_VILLAGE_VILLAGE_CARTOGRAPHER + ) ); + + @SubscribeEvent + public static void lootLoad( LootTableLoadEvent event ) + { + ResourceLocation name = event.getName(); + if( !name.getNamespace().equals( "minecraft" ) || !TABLES.contains( name ) ) return; + + event.getTable().addPool( LootPool.builder() + .addEntry( TableLootEntry.builder( LOOT_TREASURE_DISK ) ) + .rolls( ConstantRange.of( 1 ) ) + .name( "computercraft_treasure" ) + .build() ); + } } } From 52c6584c81bded5f1457c352de6d2e0fa4c9d31a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 30 Apr 2020 11:33:31 +0100 Subject: [PATCH 204/711] Fix treasure disk colour handler --- .../java/dan200/computercraft/client/ClientRegistry.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 3da3090d3..67f9f776a 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -9,6 +9,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.TurtleModelLoader; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.media.items.ItemDisk; +import dan200.computercraft.shared.media.items.ItemTreasureDisk; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.renderer.model.IBakedModel; @@ -116,7 +117,12 @@ public final class ClientRegistry event.getItemColors().register( ( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF, - ComputerCraft.Items.disk, ComputerCraft.Items.treasureDisk + ComputerCraft.Items.disk + ); + + event.getItemColors().register( + ( stack, layer ) -> layer == 1 ? ItemTreasureDisk.getColour( stack ) : 0xFFFFFF, + ComputerCraft.Items.treasureDisk ); event.getItemColors().register( ( stack, layer ) -> { From e1663f3df044f0e808af621e391c6da7f954f107 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 1 May 2020 08:50:44 +0100 Subject: [PATCH 205/711] Fix malformed doc comments --- .../resources/assets/computercraft/lua/rom/apis/rednet.lua | 4 ++-- src/test/resources/test-rom/mcfly.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua index 358c62bd5..3a8f3a5c0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/rednet.lua @@ -29,7 +29,7 @@ local tReceivedMessageTimeouts = {} local tHostnames = {} --- Opens a modem with the given @{peripheral} name, allowing it to send and ---- receive messages over rednet. +-- receive messages over rednet. -- -- This will open the modem on two channels: one which has the same -- @{os.getComputerID|ID} as the computer, and another on @@ -246,7 +246,7 @@ function host(sProtocol, sHostname) end --- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer ---- respond to @{rednet.lookup} requests. +-- respond to @{rednet.lookup} requests. -- -- @tparam string sProtocol The protocol to unregister your self from. function unhost(sProtocol) diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 81e5afb3c..5081447a6 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -47,7 +47,7 @@ local function default_stub() end --- Stub a table entry with a new value. -- --- @tparam table +-- @tparam table tbl The table whose field should be stubbed. -- @tparam string key The variable to stub -- @param[opt] value The value to stub it with. If this is a function, one can -- use the various stub expectation methods to determine what it was called From 3fb906ef6cecc2783b01139d492e238782bd6d11 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 2 May 2020 10:16:36 +0100 Subject: [PATCH 206/711] Show computer/disk ids in the tool tip more often - Remove the parenthesis around the text (so it's now "Computer ID: 12"), rather than "(Computer ID: 12"). - Show the tooltip if the computer has an ID and no label (as well as when in advanced mode). --- .../computercraft/shared/computer/items/ItemComputerBase.java | 2 +- .../computercraft/shared/media/items/ItemDiskLegacy.java | 2 +- .../computercraft/shared/pocket/items/ItemPocketComputer.java | 2 +- src/main/resources/assets/computercraft/lang/da_dk.lang | 4 ++-- src/main/resources/assets/computercraft/lang/de_de.lang | 4 ++-- src/main/resources/assets/computercraft/lang/en_us.lang | 4 ++-- src/main/resources/assets/computercraft/lang/ko_kr.lang | 4 ++-- src/main/resources/assets/computercraft/lang/zh_cn.lang | 4 ++-- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index e00ec444a..dfee4beac 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -39,7 +39,7 @@ public abstract class ItemComputerBase extends ItemBlock implements IComputerIte @Override public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag flag ) { - if( flag.isAdvanced() ) + if( flag.isAdvanced() || getLabel( stack ) == null ) { int id = getComputerID( stack ); if( id >= 0 ) list.add( StringUtil.translateFormatted( "gui.computercraft.tooltip.computer_id", id ) ); diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java index 73f574dfd..eef8bed22 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDiskLegacy.java @@ -80,7 +80,7 @@ public class ItemDiskLegacy extends Item implements IMedia, IColouredItem @Override public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag flag ) { - if( flag.isAdvanced() ) + if( flag.isAdvanced() || getLabel( stack ) == null ) { int id = getDiskID( stack ); if( id >= 0 ) list.add( StringUtil.translateFormatted( "gui.computercraft.tooltip.disk_id", id ) ); diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 6cfe430f5..3a117bff5 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -211,7 +211,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Override public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag flag ) { - if( flag.isAdvanced() ) + if( flag.isAdvanced() || getLabel( stack ) == null ) { int id = getComputerID( stack ); if( id >= 0 ) list.add( StringUtil.translateFormatted( "gui.computercraft.tooltip.computer_id", id ) ); diff --git a/src/main/resources/assets/computercraft/lang/da_dk.lang b/src/main/resources/assets/computercraft/lang/da_dk.lang index 3da64d2a4..a54df9dee 100644 --- a/src/main/resources/assets/computercraft/lang/da_dk.lang +++ b/src/main/resources/assets/computercraft/lang/da_dk.lang @@ -44,5 +44,5 @@ chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet # Misc tooltips gui.computercraft.tooltip.copy=Kopier til udklipsholder -gui.computercraft.tooltip.computer_id=(Computer-ID: %s) -gui.computercraft.tooltip.disk_id=(Disk-ID: %s) +gui.computercraft.tooltip.computer_id=Computer-ID: %s +gui.computercraft.tooltip.disk_id=Disk-ID: %s diff --git a/src/main/resources/assets/computercraft/lang/de_de.lang b/src/main/resources/assets/computercraft/lang/de_de.lang index 6fabe4002..f416b3024 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.lang +++ b/src/main/resources/assets/computercraft/lang/de_de.lang @@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=Koroutinen gelöscht # Misc tooltips gui.computercraft.tooltip.copy=In die Zwischenablage kopieren -gui.computercraft.tooltip.computer_id=(Computer ID: %s) -gui.computercraft.tooltip.disk_id=(Disketten ID: %s) +gui.computercraft.tooltip.computer_id=Computer ID: %s +gui.computercraft.tooltip.disk_id=Disketten ID: %s # Config options gui.computercraft:config.computer_space_limit=Speicherplatz von Computern (Bytes) diff --git a/src/main/resources/assets/computercraft/lang/en_us.lang b/src/main/resources/assets/computercraft/lang/en_us.lang index 254fb0e21..6c7490fdb 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.lang +++ b/src/main/resources/assets/computercraft/lang/en_us.lang @@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=Coroutines disposed # Misc tooltips gui.computercraft.tooltip.copy=Copy to clipboard -gui.computercraft.tooltip.computer_id=(Computer ID: %s) -gui.computercraft.tooltip.disk_id=(Disk ID: %s) +gui.computercraft.tooltip.computer_id=Computer ID: %s +gui.computercraft.tooltip.disk_id=Disk ID: %s # Config options gui.computercraft:config.computer_space_limit=Computer space limit (bytes) diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.lang b/src/main/resources/assets/computercraft/lang/ko_kr.lang index 784bb4b31..24c220059 100644 --- a/src/main/resources/assets/computercraft/lang/ko_kr.lang +++ b/src/main/resources/assets/computercraft/lang/ko_kr.lang @@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=코루틴 ì²˜ë¦¬ë¨ # Misc tooltips gui.computercraft.tooltip.copy=í´ë¦½ë³´ë“œì— 복사 -gui.computercraft.tooltip.computer_id=(컴퓨터 ID: %s) -gui.computercraft.tooltip.disk_id=(ë””ìŠ¤í¬ ID: %s) +gui.computercraft.tooltip.computer_id=컴퓨터 ID: %s +gui.computercraft.tooltip.disk_id=ë””ìŠ¤í¬ ID: %s # Config options gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (ë°”ì´íЏ) diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.lang b/src/main/resources/assets/computercraft/lang/zh_cn.lang index 86c43c33f..32009fed5 100644 --- a/src/main/resources/assets/computercraft/lang/zh_cn.lang +++ b/src/main/resources/assets/computercraft/lang/zh_cn.lang @@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=ååŒå¤„ç† # Misc tooltips gui.computercraft.tooltip.copy=å¤åˆ¶åˆ°å‰ªè´´æ¿ -gui.computercraft.tooltip.computer_id=(计算机ID: %s) -gui.computercraft.tooltip.disk_id=(ç£ç›˜ID: %s) +gui.computercraft.tooltip.computer_id=计算机ID: %s +gui.computercraft.tooltip.disk_id=ç£ç›˜ID: %s # Config options gui.computercraft:config.computer_space_limit=计算机空间é™åˆ¶(字节) From ed4229ab70b4d31edba0e0ab2e6ac8caa4b39934 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 2 May 2020 10:19:30 +0100 Subject: [PATCH 207/711] Keep ids of unlabelled computers and turtles --- .../computer/blocks/BlockComputerBase.java | 2 +- .../computer/items/ComputerItemFactory.java | 4 +--- .../shared/turtle/items/TurtleItemFactory.java | 18 +++++++----------- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index c54387691..d917ee5f6 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -128,7 +128,7 @@ public abstract class BlockComputerBase extends BlockDirectional if( tile instanceof TileComputerBase ) { TileComputerBase computer = (TileComputerBase) tile; - if( !player.capabilities.isCreativeMode || computer.getLabel() != null ) + if( !player.capabilities.isCreativeMode || computer.getLabel() != null || computer.getComputerID() != -1 ) { spawnAsEntity( world, pos, getItem( computer ) ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index e742ec317..212579b2b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -19,9 +19,7 @@ public final class ComputerItemFactory @Nonnull public static ItemStack create( TileComputer tile ) { - String label = tile.getLabel(); - int id = label != null ? tile.getComputerID() : -1; - return create( id, label, tile.getFamily() ); + return create( tile.getComputerID(), tile.getLabel(), tile.getFamily() ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index 28811f00c..2c2733578 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -22,18 +23,13 @@ public final class TurtleItemFactory @Nonnull public static ItemStack create( ITurtleTile turtle ) { - ITurtleUpgrade leftUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Left ); - ITurtleUpgrade rightUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Right ); + ITurtleAccess access = turtle.getAccess(); - String label = turtle.getLabel(); - if( label == null ) - { - return create( -1, null, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, 0, turtle.getOverlay() ); - } - - int id = turtle.getComputerID(); - int fuelLevel = turtle.getAccess().getFuelLevel(); - return create( id, label, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, fuelLevel, turtle.getOverlay() ); + return create( + turtle.getComputerID(), turtle.getLabel(), turtle.getColour(), turtle.getFamily(), + access.getUpgrade( TurtleSide.Left ), access.getUpgrade( TurtleSide.Right ), + access.getFuelLevel(), turtle.getOverlay() + ); } @Nonnull From fb64b6017b1f9ebd30e2ffbad9280eb210318b64 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 2 May 2020 11:05:09 +0100 Subject: [PATCH 208/711] Add shell.execute This functions the same as shell.run, but does not tokenise the arguments. This allows us to pass command line arguments through to another program without having to re-quote them. Closes #417 --- .../lua/rom/programs/monitor.lua | 2 +- .../computercraft/lua/rom/programs/shell.lua | 26 ++++++++++++++++--- .../resources/test-rom/data/dump-args.lua | 1 + .../test-rom/spec/programs/shell_spec.lua | 24 ++++++++++------- 4 files changed, 39 insertions(+), 14 deletions(-) create mode 100644 src/test/resources/test-rom/data/dump-args.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua index e6daed9e8..01c9d7949 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/monitor.lua @@ -28,7 +28,7 @@ local monitor = peripheral.wrap(sName) local previousTerm = term.redirect(monitor) local co = coroutine.create(function() - shell.run(sProgram, table.unpack(tArgs, 3)) + (shell.execute or shell.run)(sProgram, table.unpack(tArgs, 3)) end) local function resume(...) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 474d3ecfd..843e28e71 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -130,8 +130,25 @@ else bgColour = colours.black end -local function run(_sCommand, ...) - local sPath = shell.resolveProgram(_sCommand) +--- Run a program with the supplied arguments. +-- +-- Unlike @{shell.run}, each argument is passed to the program verbatim. While +-- `shell.run("echo", "b c")` runs `echo` with `b` and `c`, +-- `shell.execute("echo", "b c")` runs `echo` with a single argument `b c`. +-- +-- @tparam string command The program to execute. +-- @tparam string ... Arguments to this program. +-- @treturn boolean Whether the program exited successfully. +-- @usage Run `paint my-image` from within your program: +-- +-- shell.execute("paint", "my-image") +function shell.execute(command, ...) + expect(1, command, "string") + for i = 1, select('#', ...) do + expect(i + 1, select(i, ...), "string") + end + + local sPath = shell.resolveProgram(command) if sPath ~= nil then tProgramStack[#tProgramStack + 1] = sPath if multishell then @@ -144,7 +161,7 @@ local function run(_sCommand, ...) local sDir = fs.getDir(sPath) local env = createShellEnv(sDir) - env.arg = { [0] = _sCommand, ... } + env.arg = { [0] = command, ... } local result = os.run(env, sPath, ...) tProgramStack[#tProgramStack] = nil @@ -196,11 +213,12 @@ end -- @usage Run `paint my-image` from within your program: -- -- shell.run("paint", "my-image") +-- @see shell.execute Run a program directly without parsing the arguments. function shell.run(...) local tWords = tokenise(...) local sCommand = tWords[1] if sCommand then - return run(sCommand, table.unpack(tWords, 2)) + return shell.execute(sCommand, table.unpack(tWords, 2)) end return false end diff --git a/src/test/resources/test-rom/data/dump-args.lua b/src/test/resources/test-rom/data/dump-args.lua new file mode 100644 index 000000000..3772a43ec --- /dev/null +++ b/src/test/resources/test-rom/data/dump-args.lua @@ -0,0 +1 @@ +_G.__arg = _ENV.arg diff --git a/src/test/resources/test-rom/spec/programs/shell_spec.lua b/src/test/resources/test-rom/spec/programs/shell_spec.lua index cb35d70f6..fae7b85d1 100644 --- a/src/test/resources/test-rom/spec/programs/shell_spec.lua +++ b/src/test/resources/test-rom/spec/programs/shell_spec.lua @@ -6,19 +6,25 @@ describe("The shell", function() end) end) - describe("shell.run", function() - it("sets the arguments", function() - local handle = fs.open("test-files/out.txt", "w") - handle.writeLine("_G.__arg = arg") - handle.close() - - shell.run("/test-files/out.txt", "arg1", "arg2") - fs.delete("test-files/out.txt") + describe("shell.execute", function() + it("parses in arguments verbatim", function() + shell.execute("/test-rom/data/dump-args", "arg1", "arg 2") local args = _G.__arg _G.__arg = nil - expect(args):same { [0] = "/test-files/out.txt", "arg1", "arg2" } + expect(args):same { [0] = "/test-rom/data/dump-args", "arg1", "arg 2" } + end) + end) + + describe("shell.run", function() + it("tokenises the arguments", function() + shell.run("/test-rom/data/dump-args", "arg1", "arg 2") + + local args = _G.__arg + _G.__arg = nil + + expect(args):same { [0] = "/test-rom/data/dump-args", "arg1", "arg", "2" } end) end) From a565a571f9ea685d445a453fafeb6a6d0c3b4374 Mon Sep 17 00:00:00 2001 From: Drew Lemmy Date: Sun, 3 May 2020 06:53:42 +0100 Subject: [PATCH 209/711] Return the peripheral name when wrapping (#436) --- .../computercraft/lua/rom/apis/peripheral.lua | 56 ++++++++++++++----- .../computercraft/lua/rom/help/peripheral.txt | 1 + .../test-rom/spec/apis/peripheral_spec.lua | 22 +++++++- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua index 53b849adc..c737a915a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/peripheral.lua @@ -64,24 +64,33 @@ function isPresent(name) return false end ---- Get the type of the peripheral with the given name. +--- Get the type of a wrapped peripheral, or a peripheral with the given name. -- --- @tparam string name The name of the peripheral to find. +-- @tparam string|table peripheral The name of the peripheral to find, or a +-- wrapped peripheral instance. -- @treturn string|nil The peripheral's type, or `nil` if it is not present. -function getType(name) - expect(1, name, "string") - if native.isPresent(name) then - return native.getType(name) - end - for n = 1, #sides do - local side = sides[n] - if native.getType(side) == "modem" and not native.call(side, "isWireless") and - native.call(side, "isPresentRemote", name) - then - return native.call(side, "getTypeRemote", name) +function getType(peripheral) + expect(1, peripheral, "string", "table") + if type(peripheral) == "string" then -- Peripheral name passed + if native.isPresent(peripheral) then + return native.getType(peripheral) end + for n = 1, #sides do + local side = sides[n] + if native.getType(side) == "modem" and not native.call(side, "isWireless") and + native.call(side, "isPresentRemote", peripheral) + then + return native.call(side, "getTypeRemote", peripheral) + end + end + return nil + else + local mt = getmetatable(peripheral) + if not mt or mt.__name ~= "peripheral" or type(mt.type) ~= "string" then + error("bad argument #1 (table is not a peripheral)", 2) + end + return mt.type end - return nil end --- Get all available methods for the peripheral with the given name. @@ -105,6 +114,19 @@ function getMethods(name) return nil end +--- Get the name of a peripheral wrapped with @{peripheral.wrap}. +-- +-- @tparam table peripheral The peripheral to get the name of. +-- @treturn string The name of the given peripheral. +function getName(peripheral) + expect(1, peripheral, "table") + local mt = getmetatable(peripheral) + if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then + error("bad argument #1 (table is not a peripheral)", 2) + end + return mt.name +end + --- Call a method on the peripheral with the given name. -- -- @tparam string name The name of the peripheral to invoke the method on. @@ -148,7 +170,11 @@ function wrap(name) return nil end - local result = {} + local result = setmetatable({}, { + __name = "peripheral", + name = name, + type = peripheral.getType(name), + }) for _, method in ipairs(methods) do result[method] = function(...) return peripheral.call(name, method, ...) diff --git a/src/main/resources/assets/computercraft/lua/rom/help/peripheral.txt b/src/main/resources/assets/computercraft/lua/rom/help/peripheral.txt index 2b02b0a90..333f52f51 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/peripheral.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/peripheral.txt @@ -3,6 +3,7 @@ The peripheral API is for interacting with external peripheral devices. Type "he Functions in the peripheral API: peripheral.getNames() peripheral.isPresent( name ) +peripheral.getName( peripheral ) peripheral.getType( name ) peripheral.getMethods( name ) peripheral.call( name, methodName, param1, param2, etc ) diff --git a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua index c3fb5675f..1b11c6552 100644 --- a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -8,10 +8,30 @@ describe("The peripheral library", function() end) end) + describe("peripheral.getName", function() + it("validates arguments", function() + expect.error(peripheral.getName, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(peripheral.getName, {}):eq("bad argument #1 (table is not a peripheral)") + end) + + it_modem("can get the name of a wrapped peripheral", function() + expect(peripheral.getName(peripheral.wrap("top"))):eq("top") + end) + end) + describe("peripheral.getType", function() it("validates arguments", function() peripheral.getType("") - expect.error(peripheral.getType, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(peripheral.getType, nil):eq("bad argument #1 (expected string or table, got nil)") + expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)") + end) + + it_modem("can get the type of a peripheral by side", function() + expect(peripheral.getType("top")):eq("modem") + end) + + it_modem("can get the type of a wrapped peripheral", function() + expect(peripheral.getType(peripheral.wrap("top"))):eq("modem") end) end) From 17b77272620c0b499317763c0adead511034a20c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 3 May 2020 10:34:24 +0100 Subject: [PATCH 210/711] Improve serialisation of terminals - Write to a PacketBuffer instead of generating an NBT tag. This is then converted to an NBT byte array when we send across the network. - Pack background/foreground colours into a single byte. This derives from some work I did back in 2017, and some of the changes made/planned in #409. However, this patch does not change how terminals are represented, it simply makes the transfer more compact. This makes the patch incredibly small (100 lines!), but also limited in what improvements it can make compared with #409. We send 26626 bytes for a full-sized monitor. While a 2x improvement over the previous 58558 bytes, there's a lot of room for improvement. --- .../computercraft/core/terminal/Terminal.java | 98 ++++++++++++++----- .../shared/common/ClientTerminal.java | 4 +- .../shared/common/ServerTerminal.java | 21 +++- .../computercraft/shared/util/Palette.java | 17 ++++ 4 files changed, 110 insertions(+), 30 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index e053e41b4..2e6ac273d 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -7,16 +7,17 @@ package dan200.computercraft.core.terminal; import dan200.computercraft.shared.util.Palette; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; public class Terminal { private static final String base16 = "0123456789abcdef"; - private int m_cursorX; - private int m_cursorY; - private boolean m_cursorBlink; - private int m_cursorColour; - private int m_cursorBackgroundColour; + private int m_cursorX = 0; + private int m_cursorY = 0; + private boolean m_cursorBlink = false; + private int m_cursorColour = 0; + private int m_cursorBackgroundColour = 15; private int m_width; private int m_height; @@ -25,9 +26,9 @@ public class Terminal private TextBuffer[] m_textColour; private TextBuffer[] m_backgroundColour; - private final Palette m_palette; + private final Palette m_palette = new Palette(); - private boolean m_changed; + private boolean m_changed = false; private final Runnable onChanged; public Terminal( int width, int height ) @@ -41,9 +42,6 @@ public class Terminal m_height = height; onChanged = changedCallback; - m_cursorColour = 0; - m_cursorBackgroundColour = 15; - m_text = new TextBuffer[m_height]; m_textColour = new TextBuffer[m_height]; m_backgroundColour = new TextBuffer[m_height]; @@ -53,14 +51,6 @@ public class Terminal m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width ); m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width ); } - - m_cursorX = 0; - m_cursorY = 0; - m_cursorBlink = false; - - m_changed = false; - - m_palette = new Palette(); } public synchronized void reset() @@ -336,6 +326,59 @@ public class Terminal m_changed = false; } + public synchronized void write( PacketBuffer buffer ) + { + buffer.writeInt( m_cursorX ); + buffer.writeInt( m_cursorY ); + buffer.writeBoolean( m_cursorBlink ); + buffer.writeByte( m_cursorBackgroundColour << 4 | m_cursorColour ); + + for( int y = 0; y < m_height; y++ ) + { + TextBuffer text = m_text[y]; + TextBuffer textColour = m_textColour[y]; + TextBuffer backColour = m_backgroundColour[y]; + + for( int x = 0; x < m_width; x++ ) + { + buffer.writeByte( text.charAt( x ) & 0xFF ); + buffer.writeByte( colourIndex( backColour.charAt( x ) ) << 4 | colourIndex( textColour.charAt( x ) ) ); + } + } + + m_palette.write( buffer ); + } + + public synchronized void read( PacketBuffer buffer ) + { + m_cursorX = buffer.readInt(); + m_cursorY = buffer.readInt(); + m_cursorBlink = buffer.readBoolean(); + + byte cursorColour = buffer.readByte(); + m_cursorBackgroundColour = (cursorColour >> 4) & 0xF; + m_cursorColour = cursorColour & 0xF; + + for( int y = 0; y < m_height; y++ ) + { + TextBuffer text = m_text[y]; + TextBuffer textColour = m_textColour[y]; + TextBuffer backColour = m_backgroundColour[y]; + + for( int x = 0; x < m_width; x++ ) + { + text.setChar( x, (char) (buffer.readByte() & 0xFF) ); + + byte colour = buffer.readByte(); + backColour.setChar( x, base16.charAt( (colour >> 4) & 0xF ) ); + textColour.setChar( x, base16.charAt( colour & 0xF ) ); + } + } + + m_palette.read( buffer ); + setChanged(); + } + public synchronized NBTTagCompound writeToNBT( NBTTagCompound nbt ) { nbt.setInteger( "term_cursorX", m_cursorX ); @@ -349,10 +392,8 @@ public class Terminal nbt.setString( "term_textColour_" + n, m_textColour[n].toString() ); nbt.setString( "term_textBgColour_" + n, m_backgroundColour[n].toString() ); } - if( m_palette != null ) - { - m_palette.writeToNBT( nbt ); - } + + m_palette.writeToNBT( nbt ); return nbt; } @@ -382,10 +423,15 @@ public class Terminal m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) ); } } - if( m_palette != null ) - { - m_palette.readFromNBT( nbt ); - } + + m_palette.readFromNBT( nbt ); setChanged(); } + + private static int colourIndex( char c ) + { + if( c >= '0' && c <= '9' ) return c - '0'; + if( c >= 'a' && c <= 'f' ) return c - 'a' + 10; + return 0; + } } diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index f823724d0..5df44befa 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -6,7 +6,9 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; +import io.netty.buffer.Unpooled; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; public class ClientTerminal implements ITerminal { @@ -53,7 +55,7 @@ public class ClientTerminal implements ITerminal { NBTTagCompound terminal = nbt.getCompoundTag( "terminal" ); resizeTerminal( terminal.getInteger( "term_width" ), terminal.getInteger( "term_height" ) ); - m_terminal.readFromNBT( terminal ); + m_terminal.read( new PacketBuffer( Unpooled.wrappedBuffer( terminal.getByteArray( "term_contents" ) ) ) ); } else { diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 7c72b11c5..d4c89dba5 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -5,8 +5,12 @@ */ package dan200.computercraft.shared.common; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.terminal.Terminal; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import java.util.concurrent.atomic.AtomicBoolean; @@ -83,17 +87,28 @@ public class ServerTerminal implements ITerminal return m_colour; } - // Networking stuff - public void writeDescription( NBTTagCompound nbt ) { nbt.setBoolean( "colour", m_colour ); if( m_terminal != null ) { + // We have a 10 byte header (2 integer positions, then blinking and current colours), followed by the + // contents and palette. + // Yes, this serialisation code is terrible, but we need to serialise to NBT in order to work with monitors + // (or rather tile entity serialisation). + final int length = 10 + (2 * m_terminal.getWidth() * m_terminal.getHeight()) + (16 * 3); + ByteBuf buffer = Unpooled.buffer( length ); + m_terminal.write( new PacketBuffer( buffer ) ); + + if( buffer.writableBytes() != 0 ) + { + ComputerCraft.log.warn( "Should have written {} bytes, but have {} ({} remaining).", length, buffer.writerIndex(), buffer.writableBytes() ); + } + NBTTagCompound terminal = new NBTTagCompound(); terminal.setInteger( "term_width", m_terminal.getWidth() ); terminal.setInteger( "term_height", m_terminal.getHeight() ); - m_terminal.writeToNBT( terminal ); + terminal.setByteArray( "term_contents", buffer.array() ); nbt.setTag( "terminal", terminal ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index e177940c2..e7c296388 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.util; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; public class Palette { @@ -78,6 +79,22 @@ public class Palette }; } + public void write( PacketBuffer buffer ) + { + for( double[] colour : colours ) + { + for( double channel : colour ) buffer.writeByte( (int) (channel * 0xFF) & 0xFF ); + } + } + + public void read( PacketBuffer buffer ) + { + for( double[] colour : colours ) + { + for( int i = 0; i < colour.length; i++ ) colour[i] = buffer.readByte() * 255; + } + } + public NBTTagCompound writeToNBT( NBTTagCompound nbt ) { int[] rgb8 = new int[colours.length]; From 550ada2f9e5ede27164daefa5d6858acfff1dbe4 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 4 May 2020 09:15:23 +0100 Subject: [PATCH 211/711] Restore previous behaviour for unknown colours Unknown blit colours, such as " " will be translated to black for the background or white for the foreground. This restores the behaviour from before #412. --- .../client/gui/FixedWidthFontRenderer.java | 9 ++++----- .../dan200/computercraft/core/terminal/Terminal.java | 10 +++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index c214505d7..9e6d80268 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -55,10 +55,9 @@ public final class FixedWidthFontRenderer return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); } - private static int getColour( char c ) + private static int getColour( char c, Colour def ) { - int i = "0123456789abcdef".indexOf( c ); - return i < 0 ? 0 : 15 - i; + return 15 - Terminal.getColour( c, def ); } private static void drawChar( BufferBuilder buffer, float x, float y, int index, float r, float g, float b ) @@ -92,7 +91,7 @@ public final class FixedWidthFontRenderer private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) { - double[] colour = palette.getColour( getColour( colourIndex ) ); + double[] colour = palette.getColour( getColour( colourIndex, Colour.Black ) ); float r, g, b; if( greyscale ) { @@ -160,7 +159,7 @@ public final class FixedWidthFontRenderer for( int i = 0; i < text.length(); i++ ) { - double[] colour = palette.getColour( getColour( textColour.charAt( i ) ) ); + double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.White ) ); float r, g, b; if( greyscale ) { diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 2e6ac273d..bbe2e1551 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.core.terminal; +import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; @@ -342,7 +343,10 @@ public class Terminal for( int x = 0; x < m_width; x++ ) { buffer.writeByte( text.charAt( x ) & 0xFF ); - buffer.writeByte( colourIndex( backColour.charAt( x ) ) << 4 | colourIndex( textColour.charAt( x ) ) ); + buffer.writeByte( getColour( + backColour.charAt( x ), Colour.Black ) << 4 | + getColour( textColour.charAt( x ), Colour.White ) + ); } } @@ -428,10 +432,10 @@ public class Terminal setChanged(); } - private static int colourIndex( char c ) + public static int getColour( char c, Colour def ) { if( c >= '0' && c <= '9' ) return c - '0'; if( c >= 'a' && c <= 'f' ) return c - 'a' + 10; - return 0; + return 15 - def.ordinal(); } } From c28b4688449c44e1bf9be2b92a9b1d2b5cdc98cb Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 4 May 2020 09:57:38 +0100 Subject: [PATCH 212/711] Update languages and language script --- .../assets/computercraft/lang/da_dk.json | 55 +++++ .../assets/computercraft/lang/da_dk.lang | 48 ----- .../assets/computercraft/lang/ko_kr.json | 185 +++++++++++++++++ .../assets/computercraft/lang/ko_kr.lang | 195 ------------------ .../assets/computercraft/lang/zh_cn.lang | 195 ------------------ tools/language.lua | 2 + 6 files changed, 242 insertions(+), 438 deletions(-) create mode 100644 src/main/resources/assets/computercraft/lang/da_dk.json delete mode 100644 src/main/resources/assets/computercraft/lang/da_dk.lang create mode 100644 src/main/resources/assets/computercraft/lang/ko_kr.json delete mode 100644 src/main/resources/assets/computercraft/lang/ko_kr.lang delete mode 100644 src/main/resources/assets/computercraft/lang/zh_cn.lang diff --git a/src/main/resources/assets/computercraft/lang/da_dk.json b/src/main/resources/assets/computercraft/lang/da_dk.json new file mode 100644 index 000000000..fa2465308 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/da_dk.json @@ -0,0 +1,55 @@ +{ + + "block.computercraft.computer_normal": "Computer", + "block.computercraft.computer_advanced": "Avanceret Computer", + "block.computercraft.computer_command": "Kommandocomputer", + + "block.computercraft.disk_drive": "Diskdrev", + "block.computercraft.printer": "Printer", + "block.computercraft.speaker": "Højttaler", + + "block.computercraft.monitor_normal": "Skærm", + "block.computercraft.monitor_advanced": "Avanceret Skærm", + + "block.computercraft.wireless_modem_normal": "TrÃ¥dløst Modem", + "block.computercraft.wireless_modem_advanced": "Endermodem", + + "block.computercraft.wired_modem": "Kablet Modem", + "block.computercraft.cable": "Netværkskabel", + + "block.computercraft.turtle_normal": "Turtle", + "block.computercraft.turtle_normal.upgraded": "%s Turtle", + "block.computercraft.turtle_normal.upgraded_twice": "%s %s Turtle", + + "block.computercraft.turtle_advanced": "Avanceret Turtle", + "block.computercraft.turtle_advanced.upgraded": "Avanceret %s Turtle", + "block.computercraft.turtle_advanced.upgraded_twice": "Avanceret %s %s Turtle", + + "item.computercraft.disk": "Floppydisk", + "item.computercraft.treasure_disk": "Floppydisk", + "item.computercraft.printed_page": "Printet Side", + "item.computercraft.printed_pages": "Printede Sider", + "item.computercraft.printed_book": "Printet Bog", + + "item.computercraft.pocket_computer_normal": "Lommecomputer", + "item.computercraft.pocket_computer_normal.upgraded": "%s Lommecomputer", + "item.computercraft.pocket_computer_advanced": "Avanceret Lommecomputer", + "item.computercraft.pocket_computer_advanced.upgraded": "Avanceret %s Lommecomputer", + + "upgrade.minecraft.diamond_sword.adjective": "Kæmpende", + "upgrade.minecraft.diamond_shovel.adjective": "Gravende", + "upgrade.minecraft.diamond_pickaxe.adjective": "Brydende", + "upgrade.minecraft.diamond_axe.adjective": "Fældende", + "upgrade.minecraft.diamond_hoe.adjective": "Dyrkende", + "upgrade.minecraft.crafting_table.adjective": "Fremstillende", + "upgrade.computercraft.wireless_modem_normal.adjective": "TrÃ¥dløs", + "upgrade.computercraft.wireless_modem_advanced.adjective": "EndertrÃ¥dløs", + "upgrade.computercraft.speaker.adjective": "Larmende", + + "chat.computercraft.wired_modem.peripheral_connected": "Perifer enhed \"%s\" koblet til netværk", + "chat.computercraft.wired_modem.peripheral_disconnected": "Perifer enhed \"%s\" koblet fra netværk", + + "gui.computercraft.tooltip.copy": "Kopier til udklipsholder", + "gui.computercraft.tooltip.computer_id": "Computer-ID: %s", + "gui.computercraft.tooltip.disk_id": "Disk-ID: %s" +} diff --git a/src/main/resources/assets/computercraft/lang/da_dk.lang b/src/main/resources/assets/computercraft/lang/da_dk.lang deleted file mode 100644 index a54df9dee..000000000 --- a/src/main/resources/assets/computercraft/lang/da_dk.lang +++ /dev/null @@ -1,48 +0,0 @@ -tile.computercraft:computer.name=Computer -tile.computercraft:advanced_computer.name=Avanceret Computer -tile.computercraft:drive.name=Diskdrev -tile.computercraft:printer.name=Printer -tile.computercraft:monitor.name=Skærm -tile.computercraft:advanced_monitor.name=Avanceret Skærm -tile.computercraft:wireless_modem.name=TrÃ¥dløst Modem -tile.computercraft:wired_modem.name=Kablet Modem -tile.computercraft:cable.name=Netværkskabel -tile.computercraft:command_computer.name=Kommandocomputer -tile.computercraft:advanced_modem.name=Endermodem -tile.computercraft:speaker.name=Højttaler - -tile.computercraft:turtle.name=Turtle -tile.computercraft:turtle.upgraded.name=%s Turtle -tile.computercraft:turtle.upgraded_twice.name=%s %s Turtle -tile.computercraft:advanced_turtle.name=Avanceret Turtle -tile.computercraft:advanced_turtle.upgraded.name=Avanceret %s Turtle -tile.computercraft:advanced_turtle.upgraded_twice.name=Avanceret %s %s Turtle - -item.computercraft:disk.name=Floppydisk -item.computercraft:treasure_disk.name=Floppydisk -item.computercraft:page.name=Printet Side -item.computercraft:pages.name=Printede Sider -item.computercraft:book.name=Printet Bog - -item.computercraft:pocket_computer.name=Lommecomputer -item.computercraft:pocket_computer.upgraded.name=%s Lommecomputer -item.computercraft:advanced_pocket_computer.name=Avanceret Lommecomputer -item.computercraft:advanced_pocket_computer.upgraded.name=Avanceret %s Lommecomputer - -upgrade.minecraft:diamond_sword.adjective=Kæmpende -upgrade.minecraft:diamond_shovel.adjective=Gravende -upgrade.minecraft:diamond_pickaxe.adjective=Brydende -upgrade.minecraft:diamond_axe.adjective=Fældende -upgrade.minecraft:diamond_hoe.adjective=Dyrkende -upgrade.computercraft:wireless_modem.adjective=TrÃ¥dløs -upgrade.minecraft:crafting_table.adjective=Fremstillende -upgrade.computercraft:advanced_modem.adjective=EndertrÃ¥dløs -upgrade.computercraft:speaker.adjective=Larmende - -chat.computercraft.wired_modem.peripheral_connected=Perifer enhed "%s" koblet til netværk -chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet fra netværk - -# Misc tooltips -gui.computercraft.tooltip.copy=Kopier til udklipsholder -gui.computercraft.tooltip.computer_id=Computer-ID: %s -gui.computercraft.tooltip.disk_id=Disk-ID: %s diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.json b/src/main/resources/assets/computercraft/lang/ko_kr.json new file mode 100644 index 000000000..c3056c726 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/ko_kr.json @@ -0,0 +1,185 @@ +{ + "itemGroup.computercraft": "컴퓨터í¬ëž˜í”„트", + + "block.computercraft.computer_normal": "컴퓨터", + "block.computercraft.computer_advanced": "고급 컴퓨터", + "block.computercraft.computer_command": "명령 컴퓨터", + + "block.computercraft.disk_drive": "ë””ìŠ¤í¬ ë“œë¼ì´ë¸Œ", + "block.computercraft.printer": "프린터", + "block.computercraft.speaker": "스피커", + + "block.computercraft.monitor_normal": "모니터", + "block.computercraft.monitor_advanced": "고급 모니터", + + "block.computercraft.wireless_modem_normal": "무선 모뎀", + "block.computercraft.wireless_modem_advanced": "ì—”ë” ëª¨ëŽ€", + + "block.computercraft.wired_modem": "유선 모뎀", + "block.computercraft.cable": "ë„¤íŠ¸ì›Œí¬ ì¼€ì´ë¸”", + + "block.computercraft.turtle_normal": "í„°í‹€", + "block.computercraft.turtle_normal.upgraded": "%s í„°í‹€", + "block.computercraft.turtle_normal.upgraded_twice": "%s %s í„°í‹€", + + "block.computercraft.turtle_advanced": "고급 í„°í‹€", + "block.computercraft.turtle_advanced.upgraded": "고급 %s í„°í‹€", + "block.computercraft.turtle_advanced.upgraded_twice": "고급 %s %s í„°í‹€", + + "item.computercraft.disk": "플로피 디스í¬", + "item.computercraft.treasure_disk": "플로피 디스í¬", + "item.computercraft.printed_page": "ì¸ì‡„ëœ íŽ˜ì´ì§€", + "item.computercraft.printed_pages": "ì¸ì‡„ëœ íŽ˜ì´ì§€ 모ìŒ", + "item.computercraft.printed_book": "ì¸ì‡„ëœ ì±…", + + "item.computercraft.pocket_computer_normal": "í¬ì¼“ 컴퓨터", + "item.computercraft.pocket_computer_normal.upgraded": "%s í¬ì¼“ 컴퓨터", + "item.computercraft.pocket_computer_advanced": "고급 í¬ì¼“ 컴퓨터", + "item.computercraft.pocket_computer_advanced.upgraded": "고급 %s í¬ì¼“ 컴퓨터", + + "upgrade.minecraft.diamond_sword.adjective": "난투", + "upgrade.minecraft.diamond_shovel.adjective": "êµ´ì°©", + "upgrade.minecraft.diamond_pickaxe.adjective": "채굴", + "upgrade.minecraft.diamond_axe.adjective": "벌목", + "upgrade.minecraft.diamond_hoe.adjective": "ë†ì—…", + "upgrade.minecraft.crafting_table.adjective": "ì¡°í•©", + "upgrade.computercraft.wireless_modem_normal.adjective": "무선", + "upgrade.computercraft.wireless_modem_advanced.adjective": "ì—”ë”", + "upgrade.computercraft.speaker.adjective": "소ìŒ", + + "chat.computercraft.wired_modem.peripheral_connected": "주변 \"%s\"ì´ ë„¤íŠ¸ì›Œí¬ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤.", + "chat.computercraft.wired_modem.peripheral_disconnected": "주변 \"%s\"ì´ ë„¤íŠ¸ì›Œí¬ë¡œë¶€í„° 분리ë˜ì—ˆìŠµë‹ˆë‹¤.", + + "commands.computercraft.synopsis": "컴퓨터를 제어하기 위한 다양한 명령어", + "commands.computercraft.desc": "/computercraft 명령어는 컴퓨터를 제어하고 ìƒí˜¸ìž‘용하기 위한 다양한 디버깅 ë° ê´€ë¦¬ìž ë„구를 제공합니다.", + + "commands.computercraft.help.synopsis": "특정 ëª…ë ¹ì–´ì— ëŒ€í•œ ë„움ë§ì„ 제공하기", + "commands.computercraft.help.desc": "", + "commands.computercraft.help.no_children": "%sì—는 하위 명령어가 없습니다.", + "commands.computercraft.help.no_command": "'%s'ë¼ëŠ” 명령어가 없습니다.", + + "commands.computercraft.dump.synopsis": "ì»´í“¨í„°ì˜ ìƒíƒœë¥¼ 보여주기", + "commands.computercraft.dump.desc": "모든 ì‹œìŠ¤í…œì˜ ìƒíƒœ ë˜ëŠ” 한 ì‹œìŠ¤í…œì— ëŒ€í•œ 특정 정보를 표시합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: \"@My Computer\")ì„ ì§€ì •í•  수 있습니다.", + "commands.computercraft.dump.action": "ì´ ì»´í“¨í„°ì— ëŒ€í•œ 추가 정보를 봅니다.", + + "commands.computercraft.shutdown.synopsis": "ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 종료하기", + "commands.computercraft.shutdown.desc": "ë‚˜ì—´ëœ ì‹œìŠ¤í…œ ë˜ëŠ” ì§€ì •ëœ ì‹œìŠ¤í…œì´ ì—†ëŠ” 경우 ëª¨ë‘ ì¢…ë£Œí•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: \"@My Computer\")ì„ ì§€ì •í•  수 있습니다.", + "commands.computercraft.shutdown.done": "%s/%s 컴퓨터 시스템 종료", + + "commands.computercraft.turn_on.synopsis": "ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 실행하기", + "commands.computercraft.turn_on.desc": "ë‚˜ì—´ëœ ì»´í“¨í„°ë¥¼ 실행합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: \"@My Computer\")ì„ ì§€ì •í•  수 있습니다.", + "commands.computercraft.turn_on.done": "%s/%s 컴퓨터 시스템 실행", + + "commands.computercraft.tp.synopsis": "특정 컴퓨터로 순간ì´ë™í•˜ê¸°", + "commands.computercraft.tp.desc": "ì»´í“¨í„°ì˜ ìœ„ì¹˜ë¡œ 순간ì´ë™í•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", + "commands.computercraft.tp.action": "ì´ ì»´í“¨í„°ë¡œ 순간ì´ë™í•˜ê¸°", + "commands.computercraft.tp.not_there": "월드ì—서 컴퓨터를 위치시킬 수 없습니다.", + + "commands.computercraft.view.synopsis": "ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ë³´ê¸°", + "commands.computercraft.view.desc": "ì»´í“¨í„°ì˜ ì›ê²© 제어를 허용하는 ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ì—½ë‹ˆë‹¤. ì´ê²ƒì€ í„°í‹€ì˜ ì¸ë²¤í† ë¦¬ì— 대한 ì ‘ê·¼ì„ ì œê³µí•˜ì§€ 않습니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", + "commands.computercraft.view.action": "ì´ ì»´í“¨í„°ë¥¼ 봅니다.", + "commands.computercraft.view.not_player": "비플레ì´ì–´í•œí…Œ 터미ë„ì„ ì—´ 수 없습니다.", + + "commands.computercraft.track.synopsis": "ì»´í“¨í„°ì˜ ì‹¤í–‰ ì‹œê°„ì„ ì¶”ì í•˜ê¸°", + "commands.computercraft.track.desc": "컴퓨터가 실행ë˜ëŠ” 기간과 처리ë˜ëŠ” ì´ë²¤íЏ 수를 ì¶”ì í•©ë‹ˆë‹¤. ì´ëŠ” /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 ë¡œê·¸ì— ìœ ìš©í•  수 있습니다.", + + "commands.computercraft.track.start.synopsis": "모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 시작하기", + "commands.computercraft.track.start.desc": "모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 시작합니다. ì´ëŠ” ì´ì „ ì‹¤í–‰ì˜ ê²°ê³¼ë¥¼ í기할 것입니다.", + "commands.computercraft.track.start.stop": "%sì„(를) 실행하여 ì¶”ì ì„ 중지하고 결과를 확ì¸í•©ë‹ˆë‹¤.", + + "commands.computercraft.track.stop.synopsis": "모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 중지하기", + "commands.computercraft.track.stop.desc": "모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 중지합니다.", + "commands.computercraft.track.stop.action": "ì¶”ì ì„ 중지하려면 í´ë¦­í•˜ì„¸ìš”.", + "commands.computercraft.track.stop.not_enabled": "현재 ì¶”ì í•˜ëŠ” 컴퓨터가 없습니다.", + + "commands.computercraft.track.dump.synopsis": "최신 ì¶”ì  ê²°ê³¼ë¥¼ ë¤í”„하기", + "commands.computercraft.track.dump.desc": "최신 컴퓨터 ì¶”ì ì˜ 결과를 ë¤í”„합니다.", + "commands.computercraft.track.dump.no_timings": "사용가능한 ì‹œê°„ì´ ì—†ìŠµë‹ˆë‹¤.", + "commands.computercraft.track.dump.computer": "컴퓨터", + + "commands.computercraft.reload.synopsis": "컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드하기", + "commands.computercraft.reload.desc": "컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드합니다.", + "commands.computercraft.reload.done": "ë¦¬ë¡œë“œëœ êµ¬ì„±", + + "commands.computercraft.queue.synopsis": "computer_command ì´ë²¤íŠ¸ë¥¼ 명령 ì»´í“¨í„°ì— ë³´ë‚´ê¸°", + "commands.computercraft.queue.desc": "computer_command ì´ë²¤íŠ¸ë¥¼ 명령 컴퓨터로 전송하여 추가 ì¸ìˆ˜ë¥¼ 전달합니다. ì´ëŠ” 대부분 ì§€ë„ ì œìž‘ìžë¥¼ 위해 설계ë˜ì—ˆìœ¼ë©°, 보다 컴퓨터 친화ì ì¸ ë²„ì „ì˜ /trigger ì—­í• ì„ í•©ë‹ˆë‹¤. ì–´ë–¤ 플레ì´ì–´ë“  ëª…ë ¹ì„ ì‹¤í–‰í•  수 있으며, ì´ëŠ” í…스트 구성 ìš”ì†Œì˜ í´ë¦­ ì´ë²¤íŠ¸ë¥¼ 통해 ìˆ˜í–‰ë  ê°€ëŠ¥ì„±ì´ ê°€ìž¥ 높습니다.", + + "commands.computercraft.generic.no_position": "", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.yes": "Y", + "commands.computercraft.generic.no": "N", + "commands.computercraft.generic.exception": "처리ë˜ì§€ ì•Šì€ ì˜ˆì™¸ (%s)", + "commands.computercraft.generic.additional_rows": "%dê°œì˜ ì¶”ê°€ í–‰...", + + "argument.computercraft.computer.no_matching": "'%s'와 ì¼ì¹˜í•˜ëŠ” 컴퓨터가 없습니다.", + "argument.computercraft.computer.many_matching": "'%s'와 ì¼ì¹˜í•˜ëŠ” 여러 컴퓨터 (ì¸ìŠ¤í„´ìŠ¤ %s)", + + "tracking_field.computercraft.tasks.name": "작업", + "tracking_field.computercraft.total.name": "ì „ì²´ 시간", + "tracking_field.computercraft.average.name": "í‰ê·  시간", + "tracking_field.computercraft.max.name": "최대 시간", + + "tracking_field.computercraft.server_count.name": "서버 작업 수", + "tracking_field.computercraft.server_time.name": "서버 작업 시간", + + "tracking_field.computercraft.peripheral.name": "주변 호출", + "tracking_field.computercraft.fs.name": "파ì¼ì‹œìŠ¤í…œ 작업", + "tracking_field.computercraft.turtle.name": "í„°í‹€ 작업", + + "tracking_field.computercraft.http.name": "HTTP 요청", + "tracking_field.computercraft.http_upload.name": "HTTP 업로드", + "tracking_field.computercraft.http_download.name": "HTTT 다운로드", + + "tracking_field.computercraft.websocket_incoming.name": "웹소켓 수신", + "tracking_field.computercraft.websocket_outgoing.name": "웹소켓 송신", + + "tracking_field.computercraft.coroutines_created.name": "코루틴 ìƒì„±ë¨", + "tracking_field.computercraft.coroutines_dead.name": "코루틴 처리ë¨", + + "gui.computercraft.tooltip.copy": "í´ë¦½ë³´ë“œì— 복사", + "gui.computercraft.tooltip.computer_id": "컴퓨터 ID: %s", + "gui.computercraft.tooltip.disk_id": "ë””ìŠ¤í¬ ID: %s", + + "gui.computercraft.config.computer_space_limit": "컴퓨터 공간 제한 (ë°”ì´íЏ)", + "gui.computercraft.config.floppy_space_limit": "플로피 ë””ìŠ¤í¬ ê³µê°„ 제한 (ë°”ì´íЏ)", + "gui.computercraft.config.maximum_open_files": "컴퓨터당 최대 íŒŒì¼ ì—´ê¸°", + "gui.computercraft.config.disable_lua51_features": "Lua 5.1 기능 미사용", + "gui.computercraft.config.default_computer_settings": "기본 컴퓨터 설정", + "gui.computercraft.config.debug_enabled": "디버그 ë¼ì´ë¸ŒëŸ¬ë¦¬ 사용", + "gui.computercraft.config.log_computer_errors": "컴퓨터 오류 로그", + + "gui.computercraft.config.execution": "실행", + "gui.computercraft.config.execution.computer_threads": "컴퓨터 쓰레드", + "gui.computercraft.config.execution.max_main_global_time": "ì „ì—­ 시간 당 서버 제한", + "gui.computercraft.config.execution.max_main_computer_time": "컴퓨터 시간 당 서버 제한", + + "gui.computercraft.config.http": "HTTP", + "gui.computercraft.config.http.enabled": "HTTP API 사용하기", + "gui.computercraft.config.http.websocket_enabled": "웹소켓 사용", + + "gui.computercraft.config.http.timeout": "타임아웃", + "gui.computercraft.config.http.max_requests": "최대 ë™ì‹œ 요청 수", + "gui.computercraft.config.http.max_download": "최대 ì‘답 í¬ê¸°", + "gui.computercraft.config.http.max_upload": "최대 요청 í¬ê¸°", + "gui.computercraft.config.http.max_websockets": "최대 ë™ì‹œ 웹소켓 수", + "gui.computercraft.config.http.max_websocket_message": "최대 웹 í¬ì¼“ 메시지 í¬ê¸°", + + "gui.computercraft.config.peripheral": "주변", + "gui.computercraft.config.peripheral.command_block_enabled": "명령 ë¸”ë¡ ì£¼ë³€ 장치 사용", + "gui.computercraft.config.peripheral.modem_range": "모뎀 범위(기본값)", + "gui.computercraft.config.peripheral.modem_high_altitude_range": "모뎀 범위(ë†’ì€ ê³ ë„)", + "gui.computercraft.config.peripheral.modem_range_during_storm": "모뎀 범위(ë‚˜ìœ ë‚ ì”¨)", + "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "모뎀 범위(ë†’ì€ ê³ ë„, ë‚˜ìœ ë‚ ì”¨)", + "gui.computercraft.config.peripheral.max_notes_per_tick": "컴퓨터가 한 ë²ˆì— ìž¬ìƒí•  수 있는 최대 소리 수", + + "gui.computercraft.config.turtle": "í„°í‹€", + "gui.computercraft.config.turtle.need_fuel": "연료 사용", + "gui.computercraft.config.turtle.normal_fuel_limit": "í„°í‹€ 연료 제한", + "gui.computercraft.config.turtle.advanced_fuel_limit": "고급 í„°í‹€ 연료 제한", + "gui.computercraft.config.turtle.obey_block_protection": "í„°í‹€ì´ ë¸”ë¡ ë³´í˜¸ì— ë”°ë¥´ê¸°", + "gui.computercraft.config.turtle.can_push": "í„°í‹€ì´ ì—”í‹°í‹° 밀어내기", + "gui.computercraft.config.turtle.disabled_actions": "í„°í‹€ ì•¡ì…˜ 미사용", + + "gui.computercraft.config.http.allowed_domains": "í—ˆìš©ëœ ë„ë©”ì¸", + "gui.computercraft.config.http.blocked_domains": "ì°¨ë‹¨ëœ ë„ë©”ì¸" +} diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.lang b/src/main/resources/assets/computercraft/lang/ko_kr.lang deleted file mode 100644 index 24c220059..000000000 --- a/src/main/resources/assets/computercraft/lang/ko_kr.lang +++ /dev/null @@ -1,195 +0,0 @@ -itemGroup.computercraft=컴퓨터í¬ëž˜í”„트 - -tile.computercraft:computer.name=컴퓨터 -tile.computercraft:advanced_computer.name=고급 컴퓨터 -tile.computercraft:drive.name=ë””ìŠ¤í¬ ë“œë¼ì´ë¸Œ -tile.computercraft:printer.name=프린터 -tile.computercraft:monitor.name=모니터 -tile.computercraft:advanced_monitor.name=고급 모니터 -tile.computercraft:wireless_modem.name=무선 모뎀 -tile.computercraft:wired_modem.name=유선 모뎀 -tile.computercraft:cable.name=ë„¤íŠ¸ì›Œí¬ ì¼€ì´ë¸” -tile.computercraft:command_computer.name=명령 컴퓨터 -tile.computercraft:advanced_modem.name=ì—”ë” ëª¨ëŽ€ -tile.computercraft:speaker.name=스피커 - -tile.computercraft:turtle.name=í„°í‹€ -tile.computercraft:turtle.upgraded.name=%s í„°í‹€ -tile.computercraft:turtle.upgraded_twice.name=%s %s í„°í‹€ -tile.computercraft:advanced_turtle.name=고급 í„°í‹€ -tile.computercraft:advanced_turtle.upgraded.name=고급 %s í„°í‹€ -tile.computercraft:advanced_turtle.upgraded_twice.name=고급 %s %s í„°í‹€ - -item.computercraft:disk.name=플로피 ë””ìŠ¤í¬ -item.computercraft:treasure_disk.name=플로피 ë””ìŠ¤í¬ -item.computercraft:page.name=ì¸ì‡„ëœ íŽ˜ì´ì§€ -item.computercraft:pages.name=ì¸ì‡„ëœ íŽ˜ì´ì§€ ëª¨ìŒ -item.computercraft:book.name=ì¸ì‡„ëœ ì±… - -item.computercraft:pocket_computer.name=í¬ì¼“ 컴퓨터 -item.computercraft:pocket_computer.upgraded.name=%s í¬ì¼“ 컴퓨터 -item.computercraft:advanced_pocket_computer.name=고급 í¬ì¼“ 컴퓨터 -item.computercraft:advanced_pocket_computer.upgraded.name=고급 %s í¬ì¼“ 컴퓨터 - -upgrade.minecraft:diamond_sword.adjective=난투 -upgrade.minecraft:diamond_shovel.adjective=êµ´ì°© -upgrade.minecraft:diamond_pickaxe.adjective=채굴 -upgrade.minecraft:diamond_axe.adjective=벌목 -upgrade.minecraft:diamond_hoe.adjective=ë†ì—… -upgrade.computercraft:wireless_modem.adjective=무선 -upgrade.minecraft:crafting_table.adjective=ì¡°í•© -upgrade.computercraft:advanced_modem.adjective=ì—”ë” -upgrade.computercraft:speaker.adjective=ì†ŒìŒ - -chat.computercraft.wired_modem.peripheral_connected=주변 "%s"ì´ ë„¤íŠ¸ì›Œí¬ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤. -chat.computercraft.wired_modem.peripheral_disconnected=주변 "%s"ì´ ë„¤íŠ¸ì›Œí¬ë¡œë¶€í„° 분리ë˜ì—ˆìŠµë‹ˆë‹¤. - -# Command descriptions, usage and any additional messages. -commands.computercraft.synopsis=컴퓨터를 제어하기 위한 다양한 명령어 -commands.computercraft.desc=/computercraft 명령어는 컴퓨터를 제어하고 ìƒí˜¸ìž‘용하기 위한 다양한 디버깅 ë° ê´€ë¦¬ìž ë„구를 제공합니다. - -commands.computercraft.help.synopsis=특정 ëª…ë ¹ì–´ì— ëŒ€í•œ ë„움ë§ì„ 제공하기 -commands.computercraft.help.desc= -commands.computercraft.help.usage=[command] -commands.computercraft.help.no_children=%sì—는 하위 명령어가 없습니다. -commands.computercraft.help.no_command='%s'ë¼ëŠ” 명령어가 없습니다. - -commands.computercraft.dump.synopsis=ì»´í“¨í„°ì˜ ìƒíƒœë¥¼ 보여주기 -commands.computercraft.dump.desc=모든 ì‹œìŠ¤í…œì˜ ìƒíƒœ ë˜ëŠ” 한 ì‹œìŠ¤í…œì— ëŒ€í•œ 특정 정보를 표시합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: "@My Computer")ì„ ì§€ì •í•  수 있습니다. -commands.computercraft.dump.usage=[id] -commands.computercraft.dump.action=ì´ ì»´í“¨í„°ì— ëŒ€í•œ 추가 정보를 봅니다. - -commands.computercraft.shutdown.synopsis=ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 종료하기 -commands.computercraft.shutdown.desc=ë‚˜ì—´ëœ ì‹œìŠ¤í…œ ë˜ëŠ” ì§€ì •ëœ ì‹œìŠ¤í…œì´ ì—†ëŠ” 경우 ëª¨ë‘ ì¢…ë£Œí•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: "@My Computer")ì„ ì§€ì •í•  수 있습니다. -commands.computercraft.shutdown.usage=[ids...] -commands.computercraft.shutdown.done=%s/%s 컴퓨터 시스템 종료 - -commands.computercraft.turn_on.synopsis=ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 실행하기 -commands.computercraft.turn_on.desc=ë‚˜ì—´ëœ ì»´í“¨í„°ë¥¼ 실행합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: "@My Computer")ì„ ì§€ì •í•  수 있습니다. -commands.computercraft.turn_on.usage=[ids...] -commands.computercraft.turn_on.done=%s/%s 컴퓨터 시스템 실행 - -commands.computercraft.tp.synopsis=특정 컴퓨터로 순간ì´ë™í•˜ê¸° -commands.computercraft.tp.desc=ì»´í“¨í„°ì˜ ìœ„ì¹˜ë¡œ 순간ì´ë™í•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다. -commands.computercraft.tp.usage= -commands.computercraft.tp.action=ì´ ì»´í“¨í„°ë¡œ 순간ì´ë™í•˜ê¸° -commands.computercraft.tp.not_entity=비플레ì´ì–´í•œí…Œ 터미ë„ì„ ì—´ 수 없습니다. -commands.computercraft.tp.not_there=월드ì—서 컴퓨터를 위치시킬 수 없습니다. - -commands.computercraft.view.synopsis=ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ë³´ê¸° -commands.computercraft.view.desc=ì»´í“¨í„°ì˜ ì›ê²© 제어를 허용하는 ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ì—½ë‹ˆë‹¤. ì´ê²ƒì€ í„°í‹€ì˜ ì¸ë²¤í† ë¦¬ì— 대한 ì ‘ê·¼ì„ ì œê³µí•˜ì§€ 않습니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다. -commands.computercraft.view.usage= -commands.computercraft.view.action=ì´ ì»´í“¨í„°ë¥¼ 봅니다. -commands.computercraft.view.not_player=비플레ì´ì–´í•œí…Œ 터미ë„ì„ ì—´ 수 없습니다. - -commands.computercraft.track.synopsis=ì»´í“¨í„°ì˜ ì‹¤í–‰ ì‹œê°„ì„ ì¶”ì í•˜ê¸° -commands.computercraft.track.desc=컴퓨터가 실행ë˜ëŠ” 기간과 처리ë˜ëŠ” ì´ë²¤íЏ 수를 ì¶”ì í•©ë‹ˆë‹¤. ì´ëŠ” /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 ë¡œê·¸ì— ìœ ìš©í•  수 있습니다. - -commands.computercraft.track.start.synopsis=모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 시작하기 -commands.computercraft.track.start.desc=모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 시작합니다. ì´ëŠ” ì´ì „ ì‹¤í–‰ì˜ ê²°ê³¼ë¥¼ í기할 것입니다. -commands.computercraft.track.start.usage= -commands.computercraft.track.start.stop=%sì„(를) 실행하여 ì¶”ì ì„ 중지하고 결과를 확ì¸í•©ë‹ˆë‹¤. - -commands.computercraft.track.stop.synopsis=모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 중지하기 -commands.computercraft.track.stop.desc=모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 중지합니다. -commands.computercraft.track.stop.usage= -commands.computercraft.track.stop.action=ì¶”ì ì„ 중지하려면 í´ë¦­í•˜ì„¸ìš”. -commands.computercraft.track.stop.not_enabled=현재 ì¶”ì í•˜ëŠ” 컴퓨터가 없습니다. - -commands.computercraft.track.dump.synopsis=최신 ì¶”ì  ê²°ê³¼ë¥¼ ë¤í”„하기 -commands.computercraft.track.dump.desc=최신 컴퓨터 ì¶”ì ì˜ 결과를 ë¤í”„합니다. -commands.computercraft.track.dump.usage=[kind] -commands.computercraft.track.dump.no_timings=사용가능한 ì‹œê°„ì´ ì—†ìŠµë‹ˆë‹¤. -commands.computercraft.track.dump.no_field=알 수 없는 필드 '%s' -commands.computercraft.track.dump.computer=컴퓨터 - -commands.computercraft.reload.synopsis=컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드하기 -commands.computercraft.reload.desc=컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드합니다. -commands.computercraft.reload.usage= -commands.computercraft.reload.done=ë¦¬ë¡œë“œëœ êµ¬ì„± - -commands.computercraft.queue.synopsis=computer_command ì´ë²¤íŠ¸ë¥¼ 명령 ì»´í“¨í„°ì— ë³´ë‚´ê¸° -commands.computercraft.queue.desc=computer_command ì´ë²¤íŠ¸ë¥¼ 명령 컴퓨터로 전송하여 추가 ì¸ìˆ˜ë¥¼ 전달합니다. ì´ëŠ” 대부분 ì§€ë„ ì œìž‘ìžë¥¼ 위해 설계ë˜ì—ˆìœ¼ë©°, 보다 컴퓨터 친화ì ì¸ ë²„ì „ì˜ /trigger ì—­í• ì„ í•©ë‹ˆë‹¤. ì–´ë–¤ 플레ì´ì–´ë“  ëª…ë ¹ì„ ì‹¤í–‰í•  수 있으며, ì´ëŠ” í…스트 구성 ìš”ì†Œì˜ í´ë¦­ ì´ë²¤íŠ¸ë¥¼ 통해 ìˆ˜í–‰ë  ê°€ëŠ¥ì„±ì´ ê°€ìž¥ 높습니다. -commands.computercraft.queue.usage= [args...] - -commands.computercraft.generic.no_position= -commands.computercraft.generic.position=%s, %s, %s -commands.computercraft.generic.yes=Y -commands.computercraft.generic.no=N -commands.computercraft.generic.exception=처리ë˜ì§€ ì•Šì€ ì˜ˆì™¸ (%s) -commands.computercraft.generic.additional_rows=%dê°œì˜ ì¶”ê°€ í–‰... - -commands.computercraft.argument.no_matching='%s'와 ì¼ì¹˜í•˜ëŠ” 컴퓨터가 없습니다. -commands.computercraft.argument.many_matching='%s'와 ì¼ì¹˜í•˜ëŠ” 여러 컴퓨터 (ì¸ìŠ¤í„´ìŠ¤ %s) -commands.computercraft.argument.not_number='%s'는 숫ìžê°€ 아닙니다. - -# Names for the various tracking fields. -tracking_field.computercraft.tasks.name=작업 -tracking_field.computercraft.total.name=ì „ì²´ 시간 -tracking_field.computercraft.average.name=í‰ê·  시간 -tracking_field.computercraft.max.name=최대 시간 - -tracking_field.computercraft.server_count.name=서버 작업 수 -tracking_field.computercraft.server_time.name=서버 작업 시간 - -tracking_field.computercraft.peripheral.name=주변 호출 -tracking_field.computercraft.fs.name=파ì¼ì‹œìŠ¤í…œ 작업 -tracking_field.computercraft.turtle.name=í„°í‹€ 작업 - -tracking_field.computercraft.http.name=HTTP 요청 -tracking_field.computercraft.http_upload.name=HTTP 업로드 -tracking_field.computercraft.http_download.name=HTTT 다운로드 - -tracking_field.computercraft.websocket_incoming.name=웹소켓 수신 -tracking_field.computercraft.websocket_outgoing.name=웹소켓 송신 - -tracking_field.computercraft.coroutines_created.name=코루틴 ìƒì„±ë¨ -tracking_field.computercraft.coroutines_dead.name=코루틴 ì²˜ë¦¬ë¨ - -# Misc tooltips -gui.computercraft.tooltip.copy=í´ë¦½ë³´ë“œì— 복사 -gui.computercraft.tooltip.computer_id=컴퓨터 ID: %s -gui.computercraft.tooltip.disk_id=ë””ìŠ¤í¬ ID: %s - -# Config options -gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (ë°”ì´íЏ) -gui.computercraft:config.floppy_space_limit=플로피 ë””ìŠ¤í¬ ê³µê°„ 제한 (ë°”ì´íЏ) -gui.computercraft:config.maximum_open_files=컴퓨터당 최대 íŒŒì¼ ì—´ê¸° -gui.computercraft:config.disable_lua51_features=Lua 5.1 기능 미사용 -gui.computercraft:config.default_computer_settings=기본 컴퓨터 설정 -gui.computercraft:config.debug_enabled=디버그 ë¼ì´ë¸ŒëŸ¬ë¦¬ 사용 -gui.computercraft:config.log_computer_errors=컴퓨터 오류 로그 - -gui.computercraft:config.execution=실행 -gui.computercraft:config.execution.computer_threads=컴퓨터 쓰레드 -gui.computercraft:config.execution.max_main_global_time=ì „ì—­ 시간 당 서버 제한 -gui.computercraft:config.execution.max_main_computer_time=컴퓨터 시간 당 서버 제한 - -gui.computercraft:config.http=HTTP -gui.computercraft:config.http.enabled=HTTP API 사용하기 -gui.computercraft:config.http.websocket_enabled=웹소켓 사용 -gui.computercraft:config.http.allowed_domains=í—ˆìš©ëœ ë„ë©”ì¸ -gui.computercraft:config.http.blocked_domains=ì°¨ë‹¨ëœ ë„ë©”ì¸ - -gui.computercraft:config.http.timeout=타임아웃 -gui.computercraft:config.http.max_requests=최대 ë™ì‹œ 요청 수 -gui.computercraft:config.http.max_download=최대 ì‘답 í¬ê¸° -gui.computercraft:config.http.max_upload=최대 요청 í¬ê¸° -gui.computercraft:config.http.max_websockets=최대 ë™ì‹œ 웹소켓 수 -gui.computercraft:config.http.max_websocket_message=최대 웹 í¬ì¼“ 메시지 í¬ê¸° - -gui.computercraft:config.peripheral=주변 -gui.computercraft:config.peripheral.command_block_enabled=명령 ë¸”ë¡ ì£¼ë³€ 장치 사용 -gui.computercraft:config.peripheral.modem_range=모뎀 범위(기본값) -gui.computercraft:config.peripheral.modem_high_altitude_range=모뎀 범위(ë†’ì€ ê³ ë„) -gui.computercraft:config.peripheral.modem_range_during_storm=모뎀 범위(ë‚˜ìœ ë‚ ì”¨) -gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=모뎀 범위(ë†’ì€ ê³ ë„, ë‚˜ìœ ë‚ ì”¨) -gui.computercraft:config.peripheral.max_notes_per_tick=컴퓨터가 한 ë²ˆì— ìž¬ìƒí•  수 있는 최대 소리 수 - -gui.computercraft:config.turtle=í„°í‹€ -gui.computercraft:config.turtle.need_fuel=연료 사용 -gui.computercraft:config.turtle.normal_fuel_limit=í„°í‹€ 연료 제한 -gui.computercraft:config.turtle.advanced_fuel_limit=고급 í„°í‹€ 연료 제한 -gui.computercraft:config.turtle.obey_block_protection=í„°í‹€ì´ ë¸”ë¡ ë³´í˜¸ì— ë”°ë¥´ê¸° -gui.computercraft:config.turtle.can_push=í„°í‹€ì´ ì—”í‹°í‹° 밀어내기 -gui.computercraft:config.turtle.disabled_actions=í„°í‹€ ì•¡ì…˜ 미사용 diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.lang b/src/main/resources/assets/computercraft/lang/zh_cn.lang deleted file mode 100644 index ab29adfc6..000000000 --- a/src/main/resources/assets/computercraft/lang/zh_cn.lang +++ /dev/null @@ -1,195 +0,0 @@ -itemGroup.computercraft=CC: Tweaked - -tile.computercraft:computer.name=计算机 -tile.computercraft:advanced_computer.name=高级计算机 -tile.computercraft:drive.name=ç£ç›˜é©±åЍ噍 -tile.computercraft:printer.name=æ‰“å°æœº -tile.computercraft:monitor.name=显示器 -tile.computercraft:advanced_monitor.name=高级显示器 -tile.computercraft:wireless_modem.name=无线调制解调器 -tile.computercraft:wired_modem.name=有线调制解调器 -tile.computercraft:cable.name=网络电缆 -tile.computercraft:command_computer.name=命令电脑 -tile.computercraft:advanced_modem.name=末影调制解调器 -tile.computercraft:speaker.name=扬声器 - -tile.computercraft:turtle.name=海龟 -tile.computercraft:turtle.upgraded.name=%s海龟 -tile.computercraft:turtle.upgraded_twice.name=%s%s海龟 -tile.computercraft:advanced_turtle.name=高级海龟 -tile.computercraft:advanced_turtle.upgraded.name=高级%s海龟 -tile.computercraft:advanced_turtle.upgraded_twice.name=高级%s%s海龟 - -item.computercraft:disk.name=软盘 -item.computercraft:treasure_disk.name=软盘 -item.computercraft:page.name=打å°çº¸ -item.computercraft:pages.name=打å°çº¸ -item.computercraft:book.name=打å°ä¹¦ - -item.computercraft:pocket_computer.name=手æè®¡ç®—机 -item.computercraft:pocket_computer.upgraded.name=%s手æè®¡ç®—机 -item.computercraft:advanced_pocket_computer.name=高级手æè®¡ç®—机 -item.computercraft:advanced_pocket_computer.upgraded.name=高级%s手æè®¡ç®—机 - -upgrade.minecraft:diamond_sword.adjective=战斗 -upgrade.minecraft:diamond_shovel.adjective=挖掘 -upgrade.minecraft:diamond_pickaxe.adjective=采掘 -upgrade.minecraft:diamond_axe.adjective=伿œ¨ -upgrade.minecraft:diamond_hoe.adjective=è€•ç§ -upgrade.computercraft:wireless_modem.adjective=无线 -upgrade.minecraft:crafting_table.adjective=åˆæˆ -upgrade.computercraft:advanced_modem.adjective=末影 -upgrade.computercraft:speaker.adjective=å–§é—¹ - -chat.computercraft.wired_modem.peripheral_connected=Peripheral "%s"连接到网络 -chat.computercraft.wired_modem.peripheral_disconnected=Peripheral "%s"与网络断开连接 - -# Command descriptions, usage and any additional messages. -commands.computercraft.synopsis=å„ç§æŽ§åˆ¶è®¡ç®—æœºçš„å‘½ä»¤. -commands.computercraft.desc=/computercraft命令æä¾›å„ç§è°ƒè¯•和管ç†å·¥å…·ï¼Œç”¨äºŽæŽ§åˆ¶å’Œä¸Žè®¡ç®—机交互. - -commands.computercraft.help.synopsis=为特定的命令æä¾›å¸®åŠ© -commands.computercraft.help.desc= -commands.computercraft.help.usage=[command] -commands.computercraft.help.no_children=%s没有å­å‘½ä»¤ -commands.computercraft.help.no_command=没有这样的命令'%s' - -commands.computercraft.dump.synopsis=显示计算机的状æ€. -commands.computercraft.dump.desc=æ˜¾ç¤ºæ‰€æœ‰è®¡ç®—æœºçš„çŠ¶æ€æˆ–æŸå°è®¡ç®—机的特定信æ¯. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer"). -commands.computercraft.dump.usage=[id] -commands.computercraft.dump.action=æŸ¥çœ‹æœ‰å…³æ­¤è®¡ç®—æœºçš„æ›´å¤šä¿¡æ¯ - -commands.computercraft.shutdown.synopsis=远程关闭计算机. -commands.computercraft.shutdown.desc=关闭列出的计算机或全部计算机(如果未指定). ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer"). -commands.computercraft.shutdown.usage=[ids...] -commands.computercraft.shutdown.done=关闭%s/%s计算机 - -commands.computercraft.turn_on.synopsis=远程打开计算机. -commands.computercraft.turn_on.desc=打开列出的计算机. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer"). -commands.computercraft.turn_on.usage=[ids...] -commands.computercraft.turn_on.done=打开%s/%s计算机 - -commands.computercraft.tp.synopsis=ä¼ é€åˆ°ç‰¹å®šçš„计算机. -commands.computercraft.tp.desc=ä¼ é€åˆ°è®¡ç®—机的ä½ç½®. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123)或计算机id (例如. #123). -commands.computercraft.tp.usage= -commands.computercraft.tp.action=ä¼ é€åˆ°è¿™å°ç”µè„‘ -commands.computercraft.tp.not_entity=无法为éžçŽ©å®¶æ‰“å¼€ç»ˆç«¯ -commands.computercraft.tp.not_there=无法在世界上定ä½ç”µè„‘ - -commands.computercraft.view.synopsis=查看计算机的终端. -commands.computercraft.view.desc=打开计算机的终端,å…许远程控制计算机. è¿™ä¸æä¾›å¯¹æµ·é¾Ÿåº“å­˜çš„è®¿é—®. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123)或计算机id (例如. #123). -commands.computercraft.view.usage= -commands.computercraft.view.action=查看此计算机 -commands.computercraft.view.not_player=无法为éžçŽ©å®¶æ‰“å¼€ç»ˆç«¯ - -commands.computercraft.track.synopsis=跟踪计算机的执行时间. -commands.computercraft.track.desc=跟踪计算机执行的时间以åŠå®ƒä»¬å¤„ç†çš„事件数. 这以/forge track类似的方å¼å‘ˆçŽ°ä¿¡æ¯ï¼Œå¯ç”¨äºŽè¯Šæ–­æ»žåŽ. - -commands.computercraft.track.start.synopsis=开始跟踪所有计算机 -commands.computercraft.track.start.desc=开始跟踪所有计算机的执行时间和事件计数. 这将放弃先å‰è¿è¡Œçš„结果. -commands.computercraft.track.start.usage= -commands.computercraft.track.start.stop=è¿è¡Œ%sä»¥åœæ­¢è·Ÿè¸ªå¹¶æŸ¥çœ‹ç»“æžœ - -commands.computercraft.track.stop.synopsis=åœæ­¢è·Ÿè¸ªæ‰€æœ‰è®¡ç®—机 -commands.computercraft.track.stop.desc=åœæ­¢è·Ÿè¸ªæ‰€æœ‰è®¡ç®—机的事件和执行时间 -commands.computercraft.track.stop.usage= -commands.computercraft.track.stop.action=ç‚¹å‡»åœæ­¢è·Ÿè¸ª -commands.computercraft.track.stop.not_enabled=ç›®å‰æ²¡æœ‰è·Ÿè¸ªè®¡ç®—机 - -commands.computercraft.track.dump.synopsis=输出最新的跟踪结果 -commands.computercraft.track.dump.desc=输出计算机跟踪的最新结果. -commands.computercraft.track.dump.usage=[kind] -commands.computercraft.track.dump.no_timings=没有时间å¯ç”¨ -commands.computercraft.track.dump.no_field=未知字节'%s' -commands.computercraft.track.dump.computer=计算器 - -commands.computercraft.reload.synopsis=釿–°åŠ è½½ComputerCrafté…置文件 -commands.computercraft.reload.desc=釿–°åŠ è½½ComputerCrafté…置文件 -commands.computercraft.reload.usage= -commands.computercraft.reload.done=釿–°åŠ è½½é…ç½® - -commands.computercraft.queue.synopsis=å°†computer_command事件å‘é€åˆ°å‘½ä»¤è®¡ç®—机 -commands.computercraft.queue.desc=å‘é€computer_command事件到命令计算机,并传递其他傿•°. è¿™ä¸»è¦æ˜¯ä¸ºåœ°å›¾åˆ¶ä½œè€…设计的, 作为/trigger更加计算机å‹å¥½çš„版本. 任何玩家都å¯ä»¥è¿è¡Œå‘½ä»¤, 这很å¯èƒ½æ˜¯é€šè¿‡æ–‡æœ¬ç»„件的点击事件完æˆçš„. -commands.computercraft.queue.usage= [args...] - -commands.computercraft.generic.no_position=<æ— ä½ç½®> -commands.computercraft.generic.position=%s, %s, %s -commands.computercraft.generic.yes=Y -commands.computercraft.generic.no=N -commands.computercraft.generic.exception=未处ç†çš„异常(%s) -commands.computercraft.generic.additional_rows=%dé¢å¤–的行… - -commands.computercraft.argument.no_matching=没有计算机匹é…'%s' -commands.computercraft.argument.many_matching=多å°è®¡ç®—机匹é…'%s' (实例%s) -commands.computercraft.argument.not_number='%s'䏿˜¯ä¸€ä¸ªæ•°å­— - -# Names for the various tracking fields. -tracking_field.computercraft.tasks.name=任务 -tracking_field.computercraft.total.name=总计时间 -tracking_field.computercraft.average.name=平凿—¶é—´ -tracking_field.computercraft.max.name=最大时间 - -tracking_field.computercraft.server_count.name=æœåŠ¡å™¨ä»»åŠ¡è®¡æ•° -tracking_field.computercraft.server_time.name=æœåŠ¡å™¨ä»»åŠ¡æ—¶é—´ - -tracking_field.computercraft.peripheral.name=å¤–å›´è®¾å¤‡å‘¼å« -tracking_field.computercraft.fs.name=文件系统æ“作 -tracking_field.computercraft.turtle.name=海龟行动 - -tracking_field.computercraft.http.name=HTTP需求 -tracking_field.computercraft.http_upload.name=HTTP上传 -tracking_field.computercraft.http_download.name=HTTP下载 - -tracking_field.computercraft.websocket_incoming.name=Websocketä¼ å…¥ -tracking_field.computercraft.websocket_outgoing.name=Websocket传出 - -tracking_field.computercraft.coroutines_created.name=ååŒåˆ›å»º -tracking_field.computercraft.coroutines_dead.name=ååŒå¤„ç† - -# Misc tooltips -gui.computercraft.tooltip.copy=å¤åˆ¶åˆ°å‰ªè´´æ¿ -gui.computercraft.tooltip.computer_id=计算机ID: %s -gui.computercraft.tooltip.disk_id=ç£ç›˜ID: %s - -# Config options -gui.computercraft:config.computer_space_limit=计算机空间é™åˆ¶(字节) -gui.computercraft:config.floppy_space_limit=软盘空间é™åˆ¶(字节) -gui.computercraft:config.maximum_open_files=æ¯å°è®¡ç®—机打开的最大文件数 -gui.computercraft:config.disable_lua51_features=ç¦ç”¨Lua 5.1功能 -gui.computercraft:config.default_computer_settings=默认计算机设置 -gui.computercraft:config.debug_enabled=å¯ç”¨debug库 -gui.computercraft:config.log_computer_errors=记录计算机错误 - -gui.computercraft:config.execution=执行 -gui.computercraft:config.execution.computer_threads=计算机线程数 -gui.computercraft:config.execution.max_main_global_time=æœåС噍免局tickæ—¶é—´é™åˆ¶ -gui.computercraft:config.execution.max_main_computer_time=æœåŠ¡å™¨è®¡ç®—æœºtickæ—¶é—´é™åˆ¶ - -gui.computercraft:config.http=HTTP -gui.computercraft:config.http.enabled=å¯ç”¨HTTP API -gui.computercraft:config.http.websocket_enabled=å¯ç”¨websockets -gui.computercraft:config.http.whitelist=HTTP白åå• -gui.computercraft:config.http.blacklist=HTTP黑åå• - -gui.computercraft:config.http.timeout=Timeout -gui.computercraft:config.http.max_requests=最大并å‘请求数 -gui.computercraft:config.http.max_download=最大å“应数æ®å¤§å° -gui.computercraft:config.http.max_upload=最大请求数æ®å¤§å° -gui.computercraft:config.http.max_websockets=最大并å‘websocketsæ•° -gui.computercraft:config.http.max_websocket_message=最大websockets消æ¯å¤§å° - -gui.computercraft:config.peripheral=外围设备 -gui.computercraft:config.peripheral.command_block_enabled=å¯ç”¨å‘½ä»¤æ–¹å—外设 -gui.computercraft:config.peripheral.modem_range=调制解调器范围(默认) -gui.computercraft:config.peripheral.modem_high_altitude_range=调制解调器范围(高海拔) -gui.computercraft:config.peripheral.modem_range_during_storm=调制解调器范围(æ¶åŠ£å¤©æ°”) -gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=调制解调器范围(高海拔, æ¶åŠ£å¤©æ°”) -gui.computercraft:config.peripheral.max_notes_per_tick=计算机一次å¯ä»¥æ’­æ”¾çš„æœ€å¤§éŸ³ç¬¦æ•°é‡ - -gui.computercraft:config.turtle=海龟 -gui.computercraft:config.turtle.need_fuel=å¯ç”¨ç‡ƒæ–™ -gui.computercraft:config.turtle.normal_fuel_limit=海龟燃料é™åˆ¶ -gui.computercraft:config.turtle.advanced_fuel_limit=高级海龟燃料é™åˆ¶ -gui.computercraft:config.turtle.obey_block_protection=海龟æœä»Žæ–¹å—ä¿æŠ¤ -gui.computercraft:config.turtle.can_push=海龟å¯ä»¥æŽ¨åŠ¨å®žä½“ -gui.computercraft:config.turtle.disabled_actions=ç¦ç”¨æµ·é¾ŸåŠ¨ä½œ diff --git a/tools/language.lua b/tools/language.lua index 25e5a2588..2e1f56f75 100644 --- a/tools/language.lua +++ b/tools/language.lua @@ -19,10 +19,12 @@ local primary = "en_us" local secondary = { + "da_dk", "de_de", "es_es", "fr_fr", "it_it", + "ko_kr", "pt_br", "sv_se", "zh_cn", From 1547ecbeb3b0e022b42783c8861cf456c63fa467 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 4 May 2020 10:26:20 +0100 Subject: [PATCH 213/711] Fix incorrect palette serialisation --- src/main/java/dan200/computercraft/shared/util/Palette.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index e7c296388..6493f9c21 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -91,7 +91,7 @@ public class Palette { for( double[] colour : colours ) { - for( int i = 0; i < colour.length; i++ ) colour[i] = buffer.readByte() * 255; + for( int i = 0; i < colour.length; i++ ) colour[i] = (buffer.readByte() & 0xFF) / 255.0; } } From 70b457ed185a1629a015292d1e2c0c16f4fae1d7 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 5 May 2020 13:05:23 +0100 Subject: [PATCH 214/711] Add a monitor renderer using TBOs (#443) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This uses the system described in #409, to render monitors in a more efficient manner. Each monitor is backed by a texture buffer object (TBO) which contains a relatively compact encoding of the terminal state. This is then rendered using a shader, which consumes the TBO and uses it to index into main font texture. As we're transmitting significantly less data to the GPU (only 3 bytes per character), this effectively reduces any update lag to 0. FPS appears to be up by a small fraction (10-15fps on my machine, to ~110), possibly as we're now only drawing a single quad (though doing much more work in the shader). On my laptop, with its Intel integrated graphics card, I'm able to draw 120 full-sized monitors (with an effective resolution of 3972 x 2330) at a consistent 60fps. Updates still cause a slight spike, but we always remain above 30fps - a significant improvement over VBOs, where updates would go off the chart. Many thanks to @Lignum and @Lemmmy for devising this scheme, and helping test and review it! ♥ --- .../client/gui/FixedWidthFontRenderer.java | 4 +- .../render/MonitorTextureBufferShader.java | 176 ++++++++++++++++++ .../render/TileEntityMonitorRenderer.java | 63 ++++++- .../peripheral/monitor/ClientMonitor.java | 46 ++++- .../peripheral/monitor/MonitorRenderer.java | 36 +++- .../assets/computercraft/lang/en_us.lang | 1 + .../assets/computercraft/shaders/monitor.frag | 40 ++++ .../assets/computercraft/shaders/monitor.vert | 13 ++ 8 files changed, 367 insertions(+), 12 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java create mode 100644 src/main/resources/assets/computercraft/shaders/monitor.frag create mode 100644 src/main/resources/assets/computercraft/shaders/monitor.vert diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 9e6d80268..7cdeeb4d3 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -50,12 +50,12 @@ public final class FixedWidthFontRenderer { } - private static float toGreyscale( double[] rgb ) + public static float toGreyscale( double[] rgb ) { return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); } - private static int getColour( char c, Colour def ) + public static int getColour( char c, Colour def ) { return 15 - Terminal.getColour( c, def ); } diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java new file mode 100644 index 000000000..5d4a43043 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -0,0 +1,176 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.client.render; + +import com.google.common.base.Strings; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.gui.FixedWidthFontRenderer; +import dan200.computercraft.shared.util.Palette; +import net.minecraft.client.renderer.OpenGlHelper; +import org.apache.commons.io.IOUtils; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL20; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; + +class MonitorTextureBufferShader +{ + static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; + + private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 ); + private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 ); + + private static int uniformMv; + private static int uniformP; + + private static int uniformFont; + private static int uniformWidth; + private static int uniformHeight; + private static int uniformTbo; + private static int uniformPalette; + + private static boolean initialised; + private static boolean ok; + private static int program; + + static void setupUniform( int width, int height, Palette palette, boolean greyscale ) + { + MATRIX_BUFFER.rewind(); + GL11.glGetFloat( GL11.GL_MODELVIEW_MATRIX, MATRIX_BUFFER ); + MATRIX_BUFFER.rewind(); + OpenGlHelper.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER ); + + MATRIX_BUFFER.rewind(); + GL11.glGetFloat( GL11.GL_PROJECTION_MATRIX, MATRIX_BUFFER ); + MATRIX_BUFFER.rewind(); + OpenGlHelper.glUniformMatrix4( uniformP, false, MATRIX_BUFFER ); + + OpenGlHelper.glUniform1i( uniformWidth, width ); + OpenGlHelper.glUniform1i( uniformHeight, height ); + + PALETTE_BUFFER.rewind(); + for( int i = 0; i < 16; i++ ) + { + double[] colour = palette.getColour( i ); + if( greyscale ) + { + float f = FixedWidthFontRenderer.toGreyscale( colour ); + PALETTE_BUFFER.put( f ).put( f ).put( f ); + } + else + { + PALETTE_BUFFER.put( (float) colour[0] ).put( (float) colour[1] ).put( (float) colour[2] ); + } + } + PALETTE_BUFFER.flip(); + OpenGlHelper.glUniform3( uniformPalette, PALETTE_BUFFER ); + } + + static boolean use() + { + if( initialised ) + { + if( ok ) OpenGlHelper.glUseProgram( program ); + return ok; + } + + if( ok = load() ) + { + GL20.glUseProgram( program ); + OpenGlHelper.glUniform1i( uniformFont, 0 ); + OpenGlHelper.glUniform1i( uniformTbo, TEXTURE_INDEX - GL13.GL_TEXTURE0 ); + } + + return ok; + } + + private static boolean load() + { + initialised = true; + + try + { + int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" ); + int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" ); + + program = OpenGlHelper.glCreateProgram(); + OpenGlHelper.glAttachShader( program, vertexShader ); + OpenGlHelper.glAttachShader( program, fragmentShader ); + GL20.glBindAttribLocation( program, 0, "v_pos" ); + + OpenGlHelper.glLinkProgram( program ); + boolean ok = OpenGlHelper.glGetProgrami( program, GL20.GL_LINK_STATUS ) != 0; + String log = OpenGlHelper.glGetProgramInfoLog( program, Short.MAX_VALUE ).trim(); + if( !Strings.isNullOrEmpty( log ) ) + { + ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log ); + } + + GL20.glDetachShader( program, vertexShader ); + GL20.glDetachShader( program, fragmentShader ); + OpenGlHelper.glDeleteShader( vertexShader ); + OpenGlHelper.glDeleteShader( fragmentShader ); + + if( !ok ) return false; + + uniformMv = getUniformLocation( program, "u_mv" ); + uniformP = getUniformLocation( program, "u_p" ); + + uniformFont = getUniformLocation( program, "u_font" ); + uniformWidth = getUniformLocation( program, "u_width" ); + uniformHeight = getUniformLocation( program, "u_height" ); + uniformTbo = getUniformLocation( program, "u_tbo" ); + uniformPalette = getUniformLocation( program, "u_palette" ); + + ComputerCraft.log.info( "Loaded monitor shader." ); + return true; + } + catch( Exception e ) + { + ComputerCraft.log.error( "Cannot load monitor shaders", e ); + return false; + } + } + + private static int loadShader( int kind, String path ) throws IOException + { + InputStream stream = TileEntityMonitorRenderer.class.getClassLoader().getResourceAsStream( path ); + if( stream == null ) throw new IllegalArgumentException( "Cannot find " + path ); + byte[] contents = IOUtils.toByteArray( new BufferedInputStream( stream ) ); + ByteBuffer buffer = BufferUtils.createByteBuffer( contents.length ); + buffer.put( contents ); + buffer.position( 0 ); + + int shader = OpenGlHelper.glCreateShader( kind ); + + OpenGlHelper.glShaderSource( shader, buffer ); + OpenGlHelper.glCompileShader( shader ); + + boolean ok = OpenGlHelper.glGetShaderi( shader, GL20.GL_COMPILE_STATUS ) != 0; + String log = OpenGlHelper.glGetShaderInfoLog( shader, Short.MAX_VALUE ).trim(); + if( !Strings.isNullOrEmpty( log ) ) + { + ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log ); + } + + if( !ok ) throw new IllegalStateException( "Cannot compile shader " + path ); + return shader; + } + + private static int getUniformLocation( int program, String name ) + { + int uniform = OpenGlHelper.glGetUniformLocation( program, name ); + if( uniform == -1 ) throw new IllegalStateException( "Cannot find uniform " + name ); + return uniform; + } +} diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index db7f7b785..405a36a29 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -8,23 +8,28 @@ package dan200.computercraft.client.render; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; +import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.OpenGlHelper; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.EnumFacing; import net.minecraft.util.math.BlockPos; import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL15; +import org.lwjgl.opengl.GL31; import javax.annotation.Nonnull; +import java.nio.ByteBuffer; +import static dan200.computercraft.client.gui.FixedWidthFontRenderer.*; import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_MARGIN; public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer @@ -97,8 +102,8 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer Date: Tue, 5 May 2020 21:17:52 +0100 Subject: [PATCH 215/711] Finish off documentation for the commands API --- doc/stub/commands.lua | 73 ++++++++++++++++++- .../lua/rom/apis/command/commands.lua | 12 +++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/doc/stub/commands.lua b/doc/stub/commands.lua index 89b0f604b..e1001230e 100644 --- a/doc/stub/commands.lua +++ b/doc/stub/commands.lua @@ -1,6 +1,77 @@ +--- Execute a specific command. +-- +-- @tparam string command The command to execute. +-- @treturn boolean Whether the command executed successfully. +-- @treturn { string... } The output of this command, as a list of lines. +-- @treturn number|nil The number of "affected" objects, or `nil` if the command +-- failed. The definition of this varies from command to command. +-- @usage Set the block above the command computer to stone. +-- +-- commands.exec("setblock ~ ~1 ~ minecraft:stone") function exec(command) end + +--- Asynchronously execute a command. +-- +-- Unlike @{exec}, this will immediately return, instead of waiting for the +-- command to execute. This allows you to run multiple commands at the same +-- time. +-- +-- When this command has finished executing, it will queue a `task_complete` +-- event containing the result of executing this command (what @{exec} would +-- return). +-- +-- @tparam string command The command to execute. +-- @treturn number The "task id". When this command has been executed, it will +-- queue a `task_complete` event with a matching id. +-- @usage Asynchronously sets the block above the computer to stone. +-- +-- commands.execAsync("~ ~1 ~ minecraft:stone") +-- @see parallel One may also use the parallel API to run multiple commands at +-- once. function execAsync(commad) end + +--- List all available commands which the computer has permission to execute. +-- +-- @treturn { string... } A list of all available commands function list() end + +--- Get the position of the current command computer. +-- +-- @treturn number This computer's x position. +-- @treturn number This computer's y position. +-- @treturn number This computer's z position. +-- @see gps.locate To get the position of a non-command computer. function getBlockPosition() end -function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end + +--- Get some basic information about a block. +-- +-- The returned table contains the current name, metadata and block state (as +-- with @{turtle.inspect}). If there is a tile entity for that block, its NBT +-- will also be returned. +-- +-- @tparam number x The x position of the block to query. +-- @tparam number y The y position of the block to query. +-- @tparam number z The z position of the block to query. +-- @treturn table The given block's information. +-- @throws If the coordinates are not within the world, or are not currently +-- loaded. function getBlockInfo(x, y, z) end + +--- Get information about a range of blocks. +-- +-- This returns the same information as @{getBlockInfo}, just for multiple +-- blocks at once. +-- +-- Blocks are traversed by ascending y level, followed by z and x - the returned +-- table may be indexed using `x + z*width + y*depth*depth`. +-- +-- @tparam number min_x The start x coordinate of the range to query. +-- @tparam number min_y The start y coordinate of the range to query. +-- @tparam number min_z The start z coordinate of the range to query. +-- @tparam number max_x The end x coordinate of the range to query. +-- @tparam number max_y The end y coordinate of the range to query. +-- @tparam number max_z The end z coordinate of the range to query. +-- @treturn { table... } A list of information about each block. +-- @throws If the coordinates are not within the world. +-- @throws If trying to get information about more than 4096 blocks. +function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua index 7f5c4b824..b54495c18 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/command/commands.lua @@ -12,6 +12,9 @@ -- [mc]: https://minecraft.gamepedia.com/Commands -- -- @module commands +-- @usage Set the block above this computer to stone: +-- +-- commands.setblock("~", "~1", "~", "minecraft:stone") if not commands then error("Cannot load command API on normal computer", 2) @@ -65,4 +68,13 @@ for _, sCommandName in ipairs(tCommands) do end end end + +--- A table containing asynchronous wrappers for all commands. +-- +-- As with @{commands.execAsync}, this returns the "task id" of the enqueued +-- command. +-- @see execAsync +-- @usage Asynchronously sets the block above the computer to stone. +-- +-- commands.async.setblock("~", "~1", "~", "minecraft:stone") env.async = tAsync From 44062ebd525ec3782668ddb16709bcd152903b1e Mon Sep 17 00:00:00 2001 From: Lupus590 Date: Fri, 8 May 2020 16:07:33 +0100 Subject: [PATCH 216/711] Allow lua REPL to warn about using local variables (#367) `local varname = value` results in `varname` being inaccessible in the next REPL input. This is often unintended and can lead to confusing behaviour. We produce a warning when this occurs. --- src/main/resources/assets/computercraft/lua/bios.lua | 5 +++++ .../assets/computercraft/lua/rom/programs/lua.lua | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 687c9c798..cef90b633 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -932,6 +932,11 @@ settings.define("motd.path", { description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]], type = "string", }) +settings.define("lua.warn_against_use_of_local", { + default = true, + description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessable on the next input.]], + type = "boolean", +}) if term.isColour() then settings.define("bios.use_multishell", { default = true, diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 5eea4dd81..b746240b9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -67,6 +67,13 @@ while bRunning do if s:match("%S") and tCommandHistory[#tCommandHistory] ~= s then table.insert(tCommandHistory, s) end + if settings.get("lua.warn_against_use_of_local") and s:match("^%s*local%s+") then + if term.isColour() then + term.setTextColour(colours.yellow) + end + print("local variables from the previous input are inaccessible afterwards. If you want to be able to use a variable across multiple inputs then remove the local keyword.") + term.setTextColour(colours.white) + end local nForcePrint = 0 local func, e = load(s, "=lua", "t", tEnv) From 376d628cf0afd3834e34433fd1153a82852debbd Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 9 May 2020 08:30:55 +0100 Subject: [PATCH 217/711] Make the local Lua message a little shorter Co-authored-by: exerro --- illuaminate.sexp | 4 +--- .../resources/assets/computercraft/lua/rom/programs/lua.lua | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index b1bf17f31..631a9eb58 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -70,14 +70,12 @@ ;; Suppress warnings for currently undocumented modules. (at - (/doc/stub/commands.lua - /doc/stub/fs.lua + (/doc/stub/fs.lua /doc/stub/http.lua /doc/stub/os.lua /doc/stub/redstone.lua /doc/stub/term.lua /doc/stub/turtle.lua - /src/main/resources/*/computercraft/lua/rom/apis/command/commands.lua /src/main/resources/*/computercraft/lua/rom/apis/io.lua /src/main/resources/*/computercraft/lua/rom/apis/window.lua /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua) diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index b746240b9..d6e04ded0 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -71,7 +71,7 @@ while bRunning do if term.isColour() then term.setTextColour(colours.yellow) end - print("local variables from the previous input are inaccessible afterwards. If you want to be able to use a variable across multiple inputs then remove the local keyword.") + print("To access local variables in later inputs, remove the local keyword.") term.setTextColour(colours.white) end From 6b3773a8624d9efcdec504bc75a9e5e355ccd6c5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 11 May 2020 15:41:39 +0100 Subject: [PATCH 218/711] Run tests with coverage - Use jacoco for Java-side coverage. Our Java coverage is /terrible (~10%), as we only really test the core libraries. Still a good thing to track for regressions though. - mcfly now tracks Lua side coverage. This works in several stages: - Replace loadfile to include the whole path - Add a debug hook which just tracks filename->(lines->count). This is then submitted to the Java test runner. - On test completion, we emit a luacov.report.out file. As the debug hook is inserted by mcfly, this does not include any computer startup (such as loading apis, or the root of bios.lua), despite they're executed. This would be possible to do (for instance, inject a custom header into bios.lua). However, we're not actually testing any of the behaviour of startup (aside from "does it not crash"), so I'm not sure whether to include it or not. Something I'll most likely re-evaluate. --- .github/workflows/main-ci.yml | 3 + build.gradle | 10 ++ .../core/ComputerTestDelegate.java | 24 ++- .../computercraft/core/LuaCoverage.java | 158 ++++++++++++++++++ src/test/resources/test-rom/mcfly.lua | 50 ++++++ .../test-rom/spec/apis/peripheral_spec.lua | 2 +- .../test-rom/spec/apis/textutils_spec.lua | 2 +- .../resources/test-rom/spec/base_spec.lua | 2 + .../test-rom/spec/modules/cc/expect_spec.lua | 2 +- 9 files changed, 249 insertions(+), 4 deletions(-) create mode 100644 src/test/java/dan200/computercraft/core/LuaCoverage.java diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 0aee2ef4f..615f24f30 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -32,6 +32,9 @@ jobs: name: CC-Tweaked path: build/libs + - name: Upload Coverage + run: bash <(curl -s https://codecov.io/bash) + lint-lua: name: Lint Lua runs-on: ubuntu-latest diff --git a/build.gradle b/build.gradle index df2375cc5..2c93873ee 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ buildscript { plugins { id "checkstyle" + id "jacoco" id "com.github.hierynomus.license" version "0.15.0" id "com.matthewprenger.cursegradle" version "1.3.0" id "com.github.breadmoirai.github-release" version "2.2.4" @@ -251,6 +252,15 @@ test { } } +jacocoTestReport { + reports { + xml.enabled true + html.enabled true + } +} + +check.dependsOn jacocoTestReport + license { mapping("java", "SLASHSTAR_STYLE") strictCheck true diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index a3410f04e..ee1d5ebaa 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -30,12 +30,14 @@ import org.opentest4j.AssertionFailedError; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.io.BufferedWriter; import java.io.File; import java.io.IOException; import java.io.Writer; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; @@ -58,6 +60,8 @@ import static dan200.computercraft.api.lua.ArgumentHelper.getType; */ public class ComputerTestDelegate { + private static final File REPORT_PATH = new File( "test-files/luacov.report.out" ); + private static final Logger LOG = LogManager.getLogger( ComputerTestDelegate.class ); private static final long TICK_TIME = TimeUnit.MILLISECONDS.toNanos( 50 ); @@ -77,6 +81,7 @@ public class ComputerTestDelegate private final Condition hasFinished = lock.newCondition(); private boolean finished = false; + private Map> finishedWith; @BeforeEach public void before() throws IOException @@ -84,6 +89,8 @@ public class ComputerTestDelegate ComputerCraft.logPeripheralErrors = true; ComputerCraft.log = LogManager.getLogger( ComputerCraft.MOD_ID ); + if( REPORT_PATH.delete() ) ComputerCraft.log.info( "Deleted previous coverage report." ); + Terminal term = new Terminal( 78, 20 ); IWritableMount mount = new FileMount( new File( "test-files/mount" ), 10_000_000 ); @@ -265,6 +272,13 @@ public class ComputerTestDelegate try { finished = true; + if( arguments.length > 0 ) + { + @SuppressWarnings( "unchecked" ) + Map> finished = (Map>) arguments[0]; + finishedWith = finished; + } + hasFinished.signal(); } finally @@ -282,7 +296,7 @@ public class ComputerTestDelegate } @AfterEach - public void after() throws InterruptedException + public void after() throws InterruptedException, IOException { try { @@ -317,6 +331,14 @@ public class ComputerTestDelegate // And shutdown computer.shutdown(); } + + if( finishedWith != null ) + { + try( BufferedWriter writer = Files.newBufferedWriter( REPORT_PATH.toPath() ) ) + { + new LuaCoverage( finishedWith ).write( writer ); + } + } } @TestFactory diff --git a/src/test/java/dan200/computercraft/core/LuaCoverage.java b/src/test/java/dan200/computercraft/core/LuaCoverage.java new file mode 100644 index 000000000..e6e61e8f2 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/LuaCoverage.java @@ -0,0 +1,158 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core; + +import com.google.common.base.Strings; +import dan200.computercraft.ComputerCraft; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import org.squiddev.cobalt.Prototype; +import org.squiddev.cobalt.compiler.CompileException; +import org.squiddev.cobalt.compiler.LuaC; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +class LuaCoverage +{ + private static final Path ROOT = new File( "src/main/resources/assets/computercraft/lua" ).toPath(); + private static final Path BIOS = ROOT.resolve( "bios.lua" ); + private static final Path APIS = ROOT.resolve( "rom/apis" ); + private static final Path SHELL = ROOT.resolve( "rom/programs/shell.lua" ); + private static final Path MULTISHELL = ROOT.resolve( "rom/programs/advanced/multishell.lua" ); + private static final Path TREASURE = ROOT.resolve( "treasure" ); + + private final Map> coverage; + private final String blank; + private final String zero; + private final String countFormat; + + LuaCoverage( Map> coverage ) + { + this.coverage = coverage; + + int max = (int) coverage.values().stream() + .flatMapToDouble( x -> x.values().stream().mapToDouble( y -> y ) ) + .max().orElse( 0 ); + int maxLen = Math.max( 1, (int) Math.ceil( Math.log10( max ) ) ); + blank = Strings.repeat( " ", maxLen + 1 ); + zero = Strings.repeat( "*", maxLen ) + "0"; + countFormat = "%" + (maxLen + 1) + "d"; + } + + void write( Writer out ) throws IOException + { + Files.find( ROOT, Integer.MAX_VALUE, ( path, attr ) -> attr.isRegularFile() && !path.startsWith( TREASURE ) ).forEach( path -> { + Path relative = ROOT.relativize( path ); + String full = relative.toString().replace( '\\', '/' ); + if( !full.endsWith( ".lua" ) ) return; + + Map files = Stream.of( + coverage.remove( "/" + full ), + path.equals( BIOS ) ? coverage.remove( "bios.lua" ) : null, + path.equals( SHELL ) ? coverage.remove( "shell.lua" ) : null, + path.equals( MULTISHELL ) ? coverage.remove( "multishell.lua" ) : null, + path.startsWith( APIS ) ? coverage.remove( path.getFileName().toString() ) : null + ) + .filter( Objects::nonNull ) + .flatMap( x -> x.entrySet().stream() ) + .collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, Double::sum ) ); + + try + { + writeCoverageFor( out, path, files ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + } ); + + for( String filename : coverage.keySet() ) + { + if( filename.startsWith( "/test-rom/" ) ) continue; + ComputerCraft.log.warn( "Unknown file {}", filename ); + } + } + + private void writeCoverageFor( Writer out, Path fullName, Map visitedLines ) throws IOException + { + if( !Files.exists( fullName ) ) + { + ComputerCraft.log.error( "Cannot locate file {}", fullName ); + return; + } + + IntSet activeLines = getActiveLines( fullName.toFile() ); + + out.write( "==============================================================================\n" ); + out.write( fullName.toString().replace( '\\', '/' ) ); + out.write( "\n" ); + out.write( "==============================================================================\n" ); + + try( BufferedReader reader = Files.newBufferedReader( fullName ) ) + { + String line; + int lineNo = 0; + while( (line = reader.readLine()) != null ) + { + lineNo++; + Double count = visitedLines.get( (double) lineNo ); + if( count != null ) + { + out.write( String.format( countFormat, count.intValue() ) ); + } + else if( activeLines.contains( lineNo ) ) + { + out.write( zero ); + } + else + { + out.write( blank ); + } + + out.write( ' ' ); + out.write( line ); + out.write( "\n" ); + } + } + } + + private static IntSet getActiveLines( File file ) throws IOException + { + IntSet activeLines = new IntOpenHashSet(); + try( InputStream stream = new FileInputStream( file ) ) + { + Prototype proto = LuaC.compile( stream, "@" + file.getPath() ); + Queue queue = new ArrayDeque<>(); + queue.add( proto ); + + while( (proto = queue.poll()) != null ) + { + int[] lines = proto.lineinfo; + if( lines != null ) + { + for( int line : lines ) + { + activeLines.add( line ); + } + } + if( proto.p != null ) Collections.addAll( queue, proto.p ); + } + } + catch( CompileException e ) + { + throw new IllegalStateException( "Cannot compile", e ); + } + + return activeLines; + } +} diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 5081447a6..ddd4f46b3 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -483,6 +483,49 @@ local function pending(name) test_stack.n = n - 1 end +local native_co_create, native_loadfile = coroutine.create, loadfile +local line_counts = {} +if cct_test then + local string_sub, debug_getinfo = string.sub, debug.getinfo + local function debug_hook(_, line_nr) + local name = debug_getinfo(2, "S").source + if string_sub(name, 1, 1) ~= "@" then return end + name = string_sub(name, 2) + + local file = line_counts[name] + if not file then file = {} line_counts[name] = file end + file[line_nr] = (file[line_nr] or 0) + 1 + end + + coroutine.create = function(...) + local co = native_co_create(...) + debug.sethook(co, debug_hook, "l") + return co + end + + local expect = require "cc.expect".expect + _G.native_loadfile = native_loadfile + _G.loadfile = function(filename, mode, env) + -- Support the previous `loadfile(filename, env)` form instead. + if type(mode) == "table" and env == nil then + mode, env = nil, mode + end + + expect(1, filename, "string") + expect(2, mode, "string", "nil") + expect(3, env, "table", "nil") + + local file = fs.open(filename, "r") + if not file then return nil, "File not found" end + + local func, err = load(file.readAll(), "@/" .. fs.combine(filename, ""), mode, env) + file.close() + return func, err + end + + debug.sethook(debug_hook, "l") +end + local arg = ... if arg == "--help" or arg == "-h" then io.write("Usage: mcfly [DIR]\n") @@ -648,4 +691,11 @@ if test_status.pending > 0 then end term.setTextColour(colours.white) io.write(info .. "\n") + +-- Restore hook stubs +debug.sethook(nil, "l") +coroutine.create = native_co_create +_G.loadfile = native_loadfile + +if cct_test then cct_test.finish(line_counts) end if howlci then howlci.log("debug", info) sleep(3) end diff --git a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua index 1b11c6552..4fea6ddf0 100644 --- a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -51,7 +51,7 @@ describe("The peripheral library", function() it_modem("has the correct error location", function() expect.error(function() peripheral.call("top", "isOpen", false) end) - :str_match("^peripheral_spec.lua:%d+: bad argument #1 %(number expected, got boolean%)$") + :str_match("^[^:]+:%d+: bad argument #1 %(number expected, got boolean%)$") end) end) diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index bdef2dbd2..94e243afc 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -49,7 +49,7 @@ describe("The textutils library", function() describe("textutils.empty_json_array", function() it("is immutable", function() expect.error(function() textutils.empty_json_array[1] = true end) - :eq("textutils_spec.lua:51: attempt to mutate textutils.empty_json_array") + :str_match("^[^:]+:51: attempt to mutate textutils.empty_json_array$") end) end) diff --git a/src/test/resources/test-rom/spec/base_spec.lua b/src/test/resources/test-rom/spec/base_spec.lua index 2e557e132..85bbf3f98 100644 --- a/src/test/resources/test-rom/spec/base_spec.lua +++ b/src/test/resources/test-rom/spec/base_spec.lua @@ -28,6 +28,8 @@ describe("The Lua base library", function() end) describe("loadfile", function() + local loadfile = _G.native_loadfile or loadfile + local function make_file() local tmp = fs.open("test-files/out.lua", "w") tmp.write("return _ENV") diff --git a/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua index 125e43640..1a30a3db7 100644 --- a/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/expect_spec.lua @@ -27,7 +27,7 @@ describe("cc.expect", function() worker() end - expect.error(trampoline):eq("expect_spec.lua:27: bad argument #1 to 'worker' (expected string, got nil)") + expect.error(trampoline):str_match("^[^:]*expect_spec.lua:27: bad argument #1 to 'worker' %(expected string, got nil%)$") end) end) From 156023b154a8821a3fb44028d50adc7fc619222c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 11 May 2020 16:08:23 +0100 Subject: [PATCH 219/711] Create more work for myself This ensures no lines start with an empty line, and all files finish with exactly one "\n". --- .../shared/command/text/TableFormatter.java | 1 - .../shared/computer/blocks/ComputerState.java | 1 - .../peripheral/speaker/SpeakerPeripheral.java | 1 - .../shared/turtle/items/ItemTurtleLegacy.java | 1 - .../blockstates/wired_modem_full.json | 1 - .../computercraft/lua/rom/help/credits.txt | 1 - .../lua/rom/programs/advanced/bg.lua | 1 - .../lua/rom/programs/advanced/fg.lua | 1 - .../computercraft/lua/rom/programs/alias.lua | 1 - .../computercraft/lua/rom/programs/apis.lua | 1 - .../computercraft/lua/rom/programs/cd.lua | 1 - .../lua/rom/programs/command/commands.lua | 1 - .../lua/rom/programs/command/exec.lua | 1 - .../computercraft/lua/rom/programs/copy.lua | 1 - .../computercraft/lua/rom/programs/eject.lua | 1 - .../lua/rom/programs/fun/adventure.lua | 1 - .../lua/rom/programs/fun/worm.lua | 1 - .../computercraft/lua/rom/programs/gps.lua | 1 - .../lua/rom/programs/http/pastebin.lua | 1 - .../lua/rom/programs/http/wget.lua | 1 - .../computercraft/lua/rom/programs/id.lua | 1 - .../computercraft/lua/rom/programs/label.lua | 1 - .../computercraft/lua/rom/programs/list.lua | 1 - .../computercraft/lua/rom/programs/lua.lua | 1 - .../computercraft/lua/rom/programs/move.lua | 1 - .../lua/rom/programs/programs.lua | 1 - .../lua/rom/programs/rednet/chat.lua | 1 - .../lua/rom/programs/rednet/repeat.lua | 1 - .../lua/rom/programs/redstone.lua | 1 - .../computercraft/lua/rom/programs/type.lua | 2 -- .../treasure/GravityScore/LuaIDE/luaide.lua | 1 - .../dan200/alongtimeago/alongtimeago.lua | 1 - .../test-rom/spec/programs/type_spec.lua | 1 - tools/check-lines.py | 18 +++++++++++++++--- 34 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index 97448af4e..b898c5a57 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -117,4 +117,3 @@ public interface TableFormatter return rowId - table.getId(); } } - diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java index b0fea8a42..38ca9b93b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerState.java @@ -45,4 +45,3 @@ public enum ComputerState implements IStringSerializable return ordinal < 0 || ordinal >= VALUES.length ? ComputerState.Off : VALUES[ordinal]; } } - diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 23deb5f5e..adffad5eb 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -148,4 +148,3 @@ public abstract class SpeakerPeripheral implements IPeripheral return true; } } - diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java index b0bcfd577..ab1200924 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtleLegacy.java @@ -88,4 +88,3 @@ public class ItemTurtleLegacy extends ItemTurtleBase return 0; } } - diff --git a/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json b/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json index d2f6fb31c..701bccab4 100644 --- a/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json +++ b/src/main/resources/assets/computercraft/blockstates/wired_modem_full.json @@ -6,4 +6,3 @@ "modem=true,peripheral=true": { "model": "computercraft:wired_modem_full_on_peripheral" } } } - diff --git a/src/main/resources/assets/computercraft/lua/rom/help/credits.txt b/src/main/resources/assets/computercraft/lua/rom/help/credits.txt index cc01b8eaf..6625cb806 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/credits.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/credits.txt @@ -1,4 +1,3 @@ - ComputerCraft was created by Daniel "dan200" Ratcliffe, with additional code by Aaron "Cloudy" Mills. Thanks to nitrogenfingers, GopherATL and RamiLego for program contributions. Thanks to Mojang, the Forge team, and the MCP team. diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua index 907e9f7aa..ccb03ffce 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/bg.lua @@ -1,4 +1,3 @@ - if not shell.openTab then printError("Requires multishell") return diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua index efc7832eb..0e87ca495 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/advanced/fg.lua @@ -1,4 +1,3 @@ - if not shell.openTab then printError("Requires multishell") return diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua b/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua index d35eb7707..79ebedc1f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/alias.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if #tArgs > 2 then print("Usage: alias ") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua b/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua index 801477650..3fd56c80f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/apis.lua @@ -1,4 +1,3 @@ - local tApis = {} for k, v in pairs(_G) do if type(k) == "string" and type(v) == "table" and k ~= "_G" then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua b/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua index 6f05a98ac..d1a3e86c1 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/cd.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if #tArgs < 1 then print("Usage: cd ") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua b/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua index dacc5626d..fe2b20ec2 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/command/commands.lua @@ -1,4 +1,3 @@ - if not commands then printError("Requires a Command Computer.") return diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua b/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua index b50c8ec20..67c9446f9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/command/exec.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if not commands then printError("Requires a Command Computer.") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua index d50132f82..49d58a0b9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/copy.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if #tArgs < 2 then print("Usage: cp ") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua b/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua index 635c2f4e8..b15e2f20f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/eject.lua @@ -1,4 +1,3 @@ - -- Get arguments local tArgs = { ... } if #tArgs == 0 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua index 0f08b59be..d13f2cf60 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/adventure.lua @@ -1,4 +1,3 @@ - local tBiomes = { "in a forest", "in a pine forest", diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua index fe753b032..eaaa54869 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/fun/worm.lua @@ -1,4 +1,3 @@ - -- Display the start screen local w, h = term.getSize() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua index 9e1ff0538..c0194443b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/gps.lua @@ -1,4 +1,3 @@ - local function printUsage() print("Usages:") print("gps host") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua index a45ea1a2a..15ad89f36 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/pastebin.lua @@ -1,4 +1,3 @@ - local function printUsage() print("Usages:") print("pastebin put ") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua index dbfa3aeb7..7b5c7654e 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/http/wget.lua @@ -1,4 +1,3 @@ - local function printUsage() print("Usage:") print("wget [filename]") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/id.lua b/src/main/resources/assets/computercraft/lua/rom/programs/id.lua index dda736612..964503e24 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/id.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/id.lua @@ -1,4 +1,3 @@ - local sDrive = nil local tArgs = { ... } if #tArgs > 0 then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/label.lua b/src/main/resources/assets/computercraft/lua/rom/programs/label.lua index d0e712a05..f857dac5c 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/label.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/label.lua @@ -1,4 +1,3 @@ - local function printUsage() print("Usages:") print("label get") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/list.lua b/src/main/resources/assets/computercraft/lua/rom/programs/list.lua index 759130bb6..ec281938d 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/list.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/list.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } -- Get all the files in the directory diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index d6e04ded0..7ab9bda42 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if #tArgs > 0 then print("This is an interactive Lua prompt.") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua index 0ebc5f7f7..3273b1ba9 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if #tArgs < 2 then print("Usage: mv ") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua b/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua index 015264d94..ca987596a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/programs.lua @@ -1,4 +1,3 @@ - local bAll = false local tArgs = { ... } if #tArgs > 0 and tArgs[1] == "all" then diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua index c632104b1..1bf5582b2 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/chat.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } local function printUsage() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua index b9a9bcb94..dfd9ca907 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rednet/repeat.lua @@ -1,4 +1,3 @@ - -- Find modems local tModems = {} for _, sModem in ipairs(peripheral.getNames()) do diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua index 35fae9f04..65d6c5e1f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/redstone.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } local function printUsage() diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/type.lua b/src/main/resources/assets/computercraft/lua/rom/programs/type.lua index ec0ebc0c5..ccbaf0dd8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/type.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/type.lua @@ -1,4 +1,3 @@ - local tArgs = { ... } if #tArgs < 1 then print("Usage: type ") @@ -15,4 +14,3 @@ if fs.exists(sPath) then else print("No such path") end - diff --git a/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua b/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua index 7ec78c299..b75383fb1 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/GravityScore/LuaIDE/luaide.lua @@ -1,4 +1,3 @@ - -- -- Lua IDE -- Made by GravityScore diff --git a/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua b/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua index dc1672f70..b9ed27c3c 100644 --- a/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua +++ b/src/main/resources/assets/computercraft/lua/treasure/dan200/alongtimeago/alongtimeago.lua @@ -1,4 +1,3 @@ - local filmText = '2\n\n\n\n\n\n\n\n\n\n\n\n\n\n15\n\n\n\n\n WWW.ASCIIMATION.CO.NZ\n\n\n presents\n\n\n\n\n\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n .......... @@@@@ @@@@@.......\n ......... @ @ @ @.......\n ........ @@@ @ @........\n ....... @@ @ @ .......\n ...... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@.........\n ......... @ @ @ @.........\n ........ @@@ @ @ .........\n ....... @@ @ @ .........\n ....... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ........ @@@ @ @ .........\n ....... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .......\n .... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ .......\n ..... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ .........\n ....... @@ @ @ .......\n ...... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ..\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ .........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ......\n ...... @@@@@@@ @@@@@ th ......\n ...... ----------------------- ....\n ..... C E N T U R Y ...\n .... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ...........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ......... @@@ @ @ .........\n ........ @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ........ @@@ @ @ ..........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ .........\n .......... @ @ @ @ .........\n ......... @@@ @ @ .........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n .... ----------------------- ........\n ... C E N T U R Y .......\n .. ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ......\n .......... @ @ @ @ .......\n ........ @@@ @ @ ........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- ........\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ............. @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- ........\n ..... C E N T U R Y .......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n............ @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ........ ----------------------- ........\n ....... C E N T U R Y .......\n ..... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n.......... @@@@@ @@@@@ .......\n.......... @ @ @ @ ........\n .......... @@@ @ @ ........\n ........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- .......\n ...... C E N T U R Y ......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n....... @@@@@ @@@@@ .........\n........ @ @ @ @ .........\n......... @@@ @ @ .........\n ......... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th ........\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ........\n...... @ @ @ @ ........\n....... @@@ @ @ ........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- .....\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ...........\n...... @ @ @ @ ..........\n....... @@@ @ @ .........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ...........\n...... @ @ @ @ ..........\n....... @@@ @ @ .........\n........ @@ @ @ .......\n ........ @@@@@@@ @@@@@ th ......\n ....... ----------------------- ......\n ...... C E N T U R Y ....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ..........\n...... @ @ @ @ ..........\n....... @@@ @ @ ........\n........ @@ @ @ .......\n ........ @@@@@@@ @@@@@ th ......\n ....... ----------------------- ......\n ...... C E N T U R Y ....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n....... @@@@@ @@@@@ ..........\n........ @ @ @ @ .........\n........ @@@ @ @ .........\n ........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- ......\n ..... C E N T U R Y ....\n .... ----------------------- ...\n ... @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n......... @@@@@ @@@@@ ...........\n......... @ @ @ @ ...........\n ......... @@@ @ @ ..........\n ........ @@ @ @ .........\n ........ @@@@@@@ @@@@@ th .......\n ...... ----------------------- ......\n ..... C E N T U R Y ....\n .... ----------------------- ...\n ... @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........ @@@@@ @@@@@ ...........\n ........ @ @ @ @ ...........\n ....... @@@ @ @ ..........\n ........ @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ...........\n ......... @ @ @ @ ...........\n ........ @@@ @ @ ..........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@...........\n ......... @ @ @ @..........\n ........ @@@ @ @...........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@........\n ......... @ @ @ @........\n ........ @@@ @ @.........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@.......\n ......... @ @ @ @.......\n ........ @@@ @ @........\n ...... @@ @ @ .......\n ..... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@.........\n ........ @ @ @ @.........\n ....... @@@ @ @ .........\n ...... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th .......\n .... ----------------------- ......\n ... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ........ @@@ @ @ .........\n ....... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .......\n .... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ .......\n ..... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- ......\n ... C E N T U R Y .....\n .. ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ......... @@@@@ @@@@@ ..........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ .........\n ....... @@ @ @ .......\n ...... @@@@@@@ @@@@@ th ......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ..\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ .........\n ......... @ @ @ @ .........\n ......... @@@ @ @ ........\n ....... @@ @ @ ......\n ...... @@@@@@@ @@@@@ th ......\n ...... ----------------------- ....\n ..... C E N T U R Y ...\n .... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n .......... @@@@@ @@@@@ ...........\n ......... @ @ @ @ ..........\n ........ @@@ @ @ ........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th .......\n ..... ----------------------- .....\n .... C E N T U R Y ....\n ... ----------------------- ...\n .. @@@@@ @@@@@ @ @ @@@@@ ..\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ......... @@@ @ @ .........\n ........ @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .....\n ... ----------------------- ....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ...........\n .......... @ @ @ @ ..........\n ........ @@@ @ @ ..........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- .......\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ .........\n .......... @ @ @ @ .........\n ......... @@@ @ @ .........\n ....... @@ @ @ ........\n ...... @@@@@@@ @@@@@ th ........\n .... ----------------------- ........\n ... C E N T U R Y .......\n .. ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ........... @@@@@ @@@@@ ......\n .......... @ @ @ @ .......\n ........ @@@ @ @ ........\n ....... @@ @ @ .........\n ...... @@@@@@@ @@@@@ th ........\n ..... ----------------------- ........\n .... C E N T U R Y .......\n ... ----------------------- .....\n .. @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n ............. @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- ........\n ..... C E N T U R Y .......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n............ @@@@@ @@@@@ ......\n ........... @ @ @ @ .......\n .......... @@@ @ @ ........\n ......... @@ @ @ .........\n ........ @@@@@@@ @@@@@ th ........\n ........ ----------------------- ........\n ....... C E N T U R Y .......\n ..... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n.......... @@@@@ @@@@@ .......\n.......... @ @ @ @ ........\n .......... @@@ @ @ ........\n ........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th ........\n ....... ----------------------- .......\n ...... C E N T U R Y ......\n .... ----------------------- .....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n....... @@@@@ @@@@@ .........\n........ @ @ @ @ .........\n......... @@@ @ @ .........\n ......... @@ @ @ ........\n ....... @@@@@@@ @@@@@ th ........\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ........\n...... @ @ @ @ ........\n....... @@@ @ @ ........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- .....\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n1\n..... @@@@@ @@@@@ ...........\n...... @ @ @ @ ..........\n....... @@@ @ @ .........\n........ @@ @ @ ........\n ........ @@@@@@@ @@@@@ th .......\n ....... ----------------------- ......\n ...... C E N T U R Y .....\n ..... ----------------------- ....\n ... @@@@@ @@@@@ @ @ @@@@@ ...\n == @ @ @ @ @ ==\n __||__ @ @@@@ @ @ __||__\n | | @ @ @ @ @ | |\n_________|______|_____ @ @@@@@ @ @ @ _____|______|_________\n10\n\n\n\n\n\n\n\n\n\n\n\n\n\n30\n\n\n\n\n A long time ago in a galaxy far,\n far away....\n\n\n\n\n\n\n\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n40\n\n 8888888888 888 88888\n 88 88 88 88 88 88\n 8888 88 88 88 88888\n 88 88 888888888 88 88\n 88888888 88 88 88 88 888888\n\n 88 88 88 888 88888 888888\n 88 88 88 88 88 88 88 88\n 88 8888 88 88 88 88888 8888\n 888 888 888888888 88 88 88\n 88 88 88 88 88 8888888\n\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n8\n\n\n\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n8\n\n\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n8\n\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n8\n\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n8\n\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n8\n\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n8\n\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n\n8\n\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n8\n\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n\n8\n\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n8\n\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n8\n\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n8\n E p i s o d e I V\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n8\n\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n8\n\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n8\n A N E W H O P E\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n8\n\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n8\n\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n\n8\n I t i s a p e r i o d o f c i v i l w a r.\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n8\n\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n\n8\n R e b e l s p a c e s h i p s , s t r i k i n g\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n8\n\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n\n8\n f r o m a h i d d e n b a s e , h a v e w o n\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n8\n\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n\n8\n t h e i r f i r s t v i c t o r y a g a i n s t\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n8\n\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n\n8\n t h e e v i l G a l a c t i c E m p i r e.\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n8\n\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n\n8\n\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n8\n D u r i n g t h e b a t t l e , R e b e l\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n\n8\n\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n8\n s p i e s m a n a g e d to s t e a l s e c r e t\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n8\n\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n8\n p l a n s t o t h e E m p i r e \' s\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n8\n\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n8\n u l t i m a t e w e a p o n , t h e D E A T H\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n8\n\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n8\n S T A R , a n a r m o r e d s p a c e\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n8\n\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n8\n s t a t i o n w i t h e n o u g h p o w e r to\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n8\n\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n8\n d e s t r o y a n e n t i r e p l a n e t.\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n8\n\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n8\n\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n8\n\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n8\n P u r s u e d b y t h e E m p i r e \' s\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n8\n\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n8\n s i n i s t e r a g e n t s , P r i n c e s s\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n8\n\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n8\n L e i a r a c e s h o m e a b o a r d h e r\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n8\n\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n8\n s t a r s h i p , c u s t o d i a n o f t h e\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n8\n\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n8\n s t o l e n p l a n s t h a t c a n s a v e\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n8\n\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n8\n h e r p e o p l e a n d r e s t o r e\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n\n8\n\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n\n\n8\n f r e e d o m t o t h e g a l a x y. . . .\n\n\n\n\n\n\n\n\n\n\n\n\n11\n\n\n\n\n\n\n\n\n\n\n\n\n\n8\n . . . . . .\n .\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n2\n .\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n1\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n1\n . 8888888\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n . .\n2\n 88888888888 . . .\n . 8888888888888\n 888888888888888 . . .\n 888888888888888\n . 8888888888888 . . .\n . 88888888888\n . 8888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n2\n . 88888888888888\n 8888888888888888 . . .\n 8888888888888888\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n2\n 8888888888888888 . . .\n 8888888888888888\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n2\n 8888888888888888\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n2\n . 88888888888888 . . .\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n2\n . 8888888888\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n2\n . 888888 . . .\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n2\n . . .\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n\n2\n . . .\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n\n\n2\n . . . .\n\n . . .\n\n . .\n\n\n\n\n\n\n\n\n2\n . . .\n\n . .\n\n\n\n\n\n\n\n\n\n\n2\n\n . .\n\n\n\n\n\n\n\n\n\n\n\n2\n . .\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<8\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=O\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=O<\n\n\n\n1\n\n\n\n\n\n\n\n\n\n O=<88>=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O-\n O=<88>=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O______ ) _____\n / \\__/_________\\ /-\\ / __|\n . |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n . |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n . |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n .|====__ _________ |(O)|===|__\n. \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . . .\n\n\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n. _\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n . ___\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n .\n .\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n. .\n\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n.\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n. / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n . __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n .__ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____| .\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n . \\__/ \\_________/ \\-/ \\_____|\n <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __. _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n .\\__/ \\_________/ \\-/ \\_____|\n. <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ . _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . . .\n\n . _____\n __ . _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n\n . _____\n __ ._<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n\n . \'__\n __ _<>______ ) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n ,\n . \'._\n __ _<>______ `) _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ \\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . . .\n ; \' ,\n. . \'\n __ _<>______ : * _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n .\n . . , . . .\n \' ,\n. . : * ,\n __ _<>______" *** _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . \' \'\n . \' ; \' . . .\n *\n. . ; , ***, \'\n __ _<>______ ***** _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . \' "\n . * \'. . .\n " * * ,\n. . , * * "\n __ _<>______ * ** _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . *\n " . . . .\n\n. . * * \'\n __ _<>______ _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n1\n . \'\n . . . .\n \'\n. .\n __ _<>______ _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n17\n .\n . . . .\n\n. .\n __ _<>______ _____\n . / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__\n \\__/ .\\_________/ \\-/ \\_____|\n . <>\n .\n . .\n . .\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_________________[_]_[_]_[_]________/_]_[_\\________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_______________[_]_[_]_[_]________/_]_[_\\__________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_________________[_]_[_]_[_]________/_]_[_\\________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n_______________[_]_[_]_[_]________/_]_[_\\__________________________\n7\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n15\n /~\\\n |oo ) Did you hear that?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n1\n /~\\\n ( oo| They\'ve shut down\n _\\=/_ the main reactor.\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n15\n /~\\\n ( oo| They\'ve shut down\n _\\=/_ the main reactor.\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\ #\n / ()\\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n15\n /~\\\n |oo ) We\'re doomed!\n _\\=/_\n ___ # / _ \\ #\n /() \\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n . .\n . . .\n .\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n______| . |__________________\n . . .\n .\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n======| . |==================\n______| . . |__________________\n .\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . |\n======| . . |==================\n______| |__________________\n . . . .\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . |\n | . . |\n======| |==================\n______| . . |__________________\n .\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . ## ## |\n | . . |\n | |\n======| . . |==================\n______| . |__________________\n .\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . ## ## |\n | ## . . ## |\n | |\n | . . |\n======| . |==================\n______| |__________________\n . __ _<>______ . _____\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . ## ## |\n | ## . . ## |\n | ## ## |\n | . . |\n | . |\n======| |==================\n______| . __ _<>______ . _____ |__________________\n / \\__/_________\\ /-\\ / __|\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n1\n | . ## ## |\n | ## . . ## |\n | ## ## |\n | . ## ## . |\n | . |\n | |\n======| . __ _<>______ . _____ |==================\n______| / \\__/_________\\ /-\\ / __| |__________________\n |====__ _________ |(O)|===|__ .\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n | . #### #### |\n | ## . . ## |\n | ## ## |\n | . ## ## . |\n | ## . ## |\n | |\n | . __ _<>______ . _____ |\n======| / \\__/_________\\ /-\\ / __| |==================\n______| |====__ _________ |(O)|===|__ |__________________\n . \\__/ \\_________/ \\-/ \\_____| .\n . <>\n . .\n . .\n2\n _________________________________________\n | #### . . #### |\n | ## ## |\n | . ## ## . |\n | ## . ## |\n | ## ## |\n | . __ _<>______ . _____ |\n | / \\__/_________\\ /-\\ / __| |\n======| |====__ _________ |(O)|===|__ |==================\n______| \\__/ \\_________/ \\-/ \\_____| |__________________\n . <>\n . .\n . .\n2\n\n _________________________________________\n | #### #### |\n | . ## ## . |\n | ## . ## |\n | ## ## |\n | . __ ##_<>______ . ##_____ |\n | / \\__/_________\\ /-\\ / __| |\n | |====__ _________ |(O)|===|__ |\n======| \\__/ \\_________/ \\-/ \\_____| |==================\n______| . <> |__________________\n . .\n . .\n2\n\n\n _________________________________________\n | . #### #### . |\n | ## . ## |\n | ## ## |\n | . __ ##_<>______ . ##_____ |\n | / \\_##_________\\ /-\\## __| |\n | |====__ _________ |(O)|===|__ |\n | \\__/ \\_________/ \\-/ \\_____| |\n======| . <> |==================\n______| . |__________________\n . .\n14\n\n\n\n _________________________________________\n | #### . #### |\n | ## ## |\n | . __ ##_<>______ . ##_____ |\n | / \\_##_________\\ /-\\## __| |\n | |====_##_________ |(O)##==|__ |\n | \\__/ \\_________/ \\-/ \\_____| |\n | . <> |\n======| . |==================\n______| . .|__________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n15\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // _____ \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // __*__ \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\____*____// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // _***_ \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\___***___// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // ***** \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\__*****__// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // ******* \\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\_*******_// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | //*********\\\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\\\*********// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | || / \\ || | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | || \\_____/ || | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | |* / \\ *| | | |\n | | | || | \\ / | || | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | || | / \\ | || | | |\n | | | |* \\_____/ *| | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | |* / \\ *| | | |\n | | | |* | \\ / | *| | | |\n | | | || | | || | | |\n | | | || | | || | | |\n | | | |* | / \\ | *| | | |\n | | | |* \\_____/ *| | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n2\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | /***********\\ | | |\n | | | |* / \\ *| | | |\n | | | |* | \\ / | *| | | |\n | | | |* | | *| | | |\n | | | |* | | *| | | |\n | | | |* | / \\ | *| | | |\n | | | |* \\_____/ *| | | |\n | | | \\***********/ | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | ********* | | |\n | | | . ************* . | | |\n | | | ** / \' \\ ** | | |\n | | | .** | \\ / | ** | | |\n | | | . ** | . \'| ** : | | |\n | | | ** | | ** | | |\n | | | . ** | / . \\ | ** . | | |\n | | | ** \\_____/ ** | | |\n | | | . ************* . | | |\n | | |__________***********__________| | |\n |_| / \\ |_|\n / / / . . \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | " ********* | | |\n | | | ************* \' . | | |\n | | | " *************** | | |\n | | | ***| " |*** . " | | |\n | | | \' ***| " |*** | | |\n | | | ***| |*** . | | |\n | | | ,***| \' |*** " | | |\n | | | " *************** | | |\n | | | " ************* " | | |\n | | |__________***********__________| | |\n |_| / \'. \\ |_|\n / / / " \' " \\ \\ \\\n1\n \\_\\ \\ ____#____*************#________ / /_/\n | | | * _________ * | | |\n | | | # * ************* * " | | |\n | | | . * * # * * # | | |\n | | | * * . # "* *. | | |\n | | | \' * * " * * #| | |\n | | | # .* * \' * *. | | |\n | | | * * . \' * * " | | |\n | | | " * * # * * | | |\n | | | # * ************* * | | |\n | | |_________*____________*__"__#__| | |\n |_| / # ************ \\ |_|\n / / / \' \'\' # \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ # . | . | |\n | | # | . /***********\\ # | |\n | | | * * | | |\n | | . | # . * | | |\n | | | * * | | |\n | | | . * * |# . | |\n | | #| * . * . | | |\n | | | . * * | | |\n | | | \\**********#/ | . | |\n | | . |_______________________________| | |\n |_| /# # #\\ |_|\n / / / . # . . \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | # // \\\\ . | | |\n | | # | || || | | |\n | | | || || | # | |\n | | | . || || | | |\n | | | || || | | |\n | | . | || || # | \' | |\n | | | || || | | |\n | | | \\\\_________// | | |\n | | # |_________________________#_____| | |\n |_| / \\ # |_|\n / / # / \' # \\ \\ \\\n1\n \\_\\ \\ _#_____________________________ / /_/\n | | | _________ . | | |\n | | | // \\\\ | | |\n | | \' | || || | | |\n | | | || || | | |\n #| | | || || | | |\n | | | || || | # | |\n | | | || || | .| |\n | | | || || | | |\n | | | . \\\\_________// | # | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / /# # \\ # \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | . || || . | | |\n | | | || || | | |\n | | | || || | | |\n # | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | \\\\_________// #| |#|\n | | . |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n # | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / # \\ |_|\n / / / \\ \\ \\\n1\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / # \\ \\ \\\n4\n \\_\\ \\ _______________________________ / /_/\n | | | _________ | | |\n | | | // \\\\ | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | || || | | |\n | | | \\\\_________// | | |\n | | |_______________________________| | |\n |_| / \\ |_|\n / / / \\ \\ \\\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | //| __ |\\\\ | |\n | | || |/ \\| \\\\ | |\n | | || [][][] \\\\ | |\n | | || |\\ /| \'| | |\n | | \'] |_||_| | |\n | | [I [ ][ ] | |\n | \\_____I_|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | //| ()\\|| | |\n | | || |/ \\ | | |\n | | || [][][\\/ | |\n | | || |\\ /| | |\n | | \'] |_||_| | |\n | | [I [ ][ ] | |\n | \\_____I_|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=O\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=*\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ | |\n | | ||/***|| | |\n | | | / *\\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / *** \\ | |\n | | ||*****| | |\n | | | /*** | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ | |\n | | ||/***|| | |\n | | | / *\\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=*\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=O\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ | |\n | | ||/=*\\|| | |\n | | | / \\ | | |\n | | \\/][][\\/ | |\n | | |\\ /| | |\n | | |_||_| | |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ | |\n | | ||/***|| || |\n | | | / *\\ | || |\n | | \\/][][\\/ || |\n | | |\\ /| \'| |\n | | |_||_| [| |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / *** \\ | |\n | | ||*****| || |\n | | | /*** | || |\n | | \\/][][\\/ || |\n | | |\\ /| \'| |\n | | |_||_| [| |\n | | [ ][ ] | |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / * \\ /| |\n | | ||/***|| | | |\n | | | / *\\ | ||| |\n | | \\/][][\\/ ||| |\n | | |\\ /| \']| |\n | | |_||_| [I| |\n | | [ ][ ] I| |\n | \\_______|_||_|______/ |\n | |\n1\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| | |\n | | (_/\\_) | |\n | | / \\ /| |\n | | ||/=*\\|| | | |\n | | | / \\ | ||| |\n | | \\/][][\\/ ||| |\n | | |\\ /| \']| |\n | | |_||_| [I| |\n | | [ ][ ] I| |\n | \\_______|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| || |\n | | (_/\\_) (| |\n | | / \\ / | |\n | | ||/=O\\|| | || |\n | | | / \\ | |||| |\n | | \\/][][\\/ ||[| |\n | | |\\ /| \']|| |\n | | |_||_| [I|| |\n | | [ ][ ] I[| |\n | \\_______|_||_|______/ |\n | |\n2\n | ___________________ |\n | / /__\\ \\ |\n | | |<><>| |<| |\n | | (_/\\_) (_| |\n | | / \\ / | |\n | | ||/=O\\|| | | | |\n | | | / \\ | |||/| |\n | | \\/][][\\/ ||[]| |\n | | |\\ /| \']|\\| |\n | | |_||_| [I|_| |\n | | [ ][ ] I[ | |\n | \\_______|_||_|_____|/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | | |<><>| |<>| |\n | | (_/\\_) (_/| |\n | | / \\ / | |\n | | ||/=*\\|| | | _| |\n | | | / \\ | |||/ | |\n | | \\/][][\\/ ||[][| |\n | | |\\ /| \']|\\ | |\n | | |_||_| [I|_|| |\n | | [ ][ ] I[ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | | |<><>| |<>| |\n | | (_/\\_) (_/| |\n | | / * \\ / | |\n | | ||/***|| | | _| |\n | | | / *\\ | |||/ | |\n | | \\/][][\\/ ||[][| |\n | | |\\ /| \']|\\ | |\n | | |_||_| [I|_|| |\n | | [ ][ ] I[ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | | |<><>| |<>| |\n | | (_/\\_) (_/| |\n | |\\ / *** \\ / | |\n | || ||*****| ||/=| |\n | || | /*** | | / | |\n | |/ \\/][][\\/ \\/][| |\n | | |\\ /| |\\ | |\n | | |_||_| |_|| |\n | | [ ][ ] [ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | || |<><>| |<>| |\n | |) (_/\\_) (_/| |\n | | \\ / * \\ / | |\n | ||| ||/***|| ||/=| |\n | | | | / *\\ | | / | |\n | |\\/ \\/][][\\/ \\/][| |\n | || |\\ /| |\\ | |\n | || |_||_| |_|| |\n | |] [ ][ ] [ ]| |\n | \\_______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | / /__\\ /\\ |\n | |>| |<><>| |<>| |\n | |_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |\\|| ||/=*\\|| ||/=| |\n | |\\ | | / \\ | | / | |\n | | \\/ \\/][][\\/ \\/][| |\n | |/| |\\ /| |\\ | |\n | |_| |_||_| |_|| |\n | | ] [ ][ ] [ ]| |\n | \\|______|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /\\ /__\\ /\\ |\n | |<>| |<><>| |<>| |\n | |\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |O\\|| ||/=O\\|| ||/*| |\n | | \\ | | / \\ | | / | |\n | |][\\/ \\/][][\\/ \\/][| |\n | | /| |\\ /| |\\ | |\n | ||_| |_||_| |_|| |\n | |[ ] [ ][ ] [ ]| |\n | \\_|_____|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /_\\ /__\\ /\\ |\n | |><>| |<><>| |<>| |\n | |/\\_) (_/\\_) (_/| |\n | | \\ / \\ / *| |\n | |=*\\|| ||/=O || ||**| |\n | | \\ | | / \\ | | /*| |\n | |[][\\/ \\/][][\\/ \\/][| |\n | | /| |\\ /| |\\ | |\n | |||_| |_||_| |_|| |\n | |][ ] [ ][ ] [ ]| |\n | \\|_|____|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | * \\ / \\ / | |\n | |/***|| ||/=* || ||/*| |\n | |/ *\\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | *** \\ / * \\ / | |\n | |*****| ||/***|| ||/O| |\n | |/*** | | / *\\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | * \\ / *** \\ / | |\n | |/***|| ||*****| ||/*| |\n | |/ *\\ | | /*** | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / * \\ / *| |\n | |/=* || ||/***|| ||**| |\n | |/ \\ | | / *\\ | | /*| |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |/=O || ||/=*\\|| ||/*| |\n | |/ \\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |/=O || ||/=O\\|| ||/=| |\n | |/ \\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | \\ / \\ / | |\n | |/=* || ||/=O\\|| ||/=| |\n | |/ \\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | * \\ / \\ / | |\n | |/***|| ||/=*\\|| ||/=| |\n | |/ *\\ | | / \\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n1\n | ___________________ |\n | /__\\ /__\\ /\\ |\n | |<><>| |<><>| |<>| |\n | |_/\\_) (_/\\_) (_/| |\n | | *** \\ / * \\ / | |\n | |*****| ||/***|| ||/=| |\n | |/*** | | / *\\ | | / | |\n | |][][\\/ \\/][][\\/ \\/][| |\n | |\\ /| |\\ /| |\\ | |\n | |_||_| |_||_| |_|| |\n | | ][ ] [ ][ ] [ ]| |\n | \\_|_|___|_||_|____|_/ |\n | |\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | |\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\| | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | |\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==* -- | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | ---\n / \\ / \\ | |\n //__ __*\\\\ | |\n \\--([=*** \\ -----\n | * \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ _***\\ | |\n \\--([*****\\ | |-----\n | *** \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __* \\ | |\n \\--([=***\\\\ | | -----\n | * \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==* \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | | -----\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | |\n _\\ -/_ | *--\n / \\ / \\ | |\n //__ __|\\\\ | |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | .* \'\n _\\ -/_ | ***\n / \\ / \\ | *\n //__ __|\\\\ | | \' ----\n \\--([==* -- | | -\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ |: * # \'\n /_/- -| | ***\n _\\ -/_ | *****\n / \\ / \\ |# *** .\n //__ __*\\\\ | * # -----\n \\--([=***\\\\----- | \'\n | * \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ \' | * #\n /_/- -| | *** \'\n _\\ o/_ \' *****\n / \\ / \\ | *** \'\n //__ _***\\ # * -----\n \\--([*****\\ | .-----\n | *** \\\\ | | #\n |====| \')| . | \'\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ \' | *\n /_/0 0| | */|\\* \' \'\n _\\ o/_ |*|\\|| *\n / \\ / \\ \' | *\\|/*\n //__ __*\\\\ | * -----\n \\--([=***\\\\ | | ----- \'\n | * #\\ | |\n |====| \')| | \'\n | || | |\' | #\n____________________( )( )___._| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /*\\ \'\n _\\ -/_ | |*|*\n / \\ / \\ | \\*/\n //__ __|\\\\ | | -----\n \\--([==* \\\\ | | -----\n | | \\\\ | |\n |====| \')| | \'\n | || |# | |\n____________________( )( )_____| |\n | || | \\ | #\n |_||_| \\ | \'\n [_][__\\\' \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n //__ __|\\\\ | | -----\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | |# | \\ |\n |_||_| \\ |\n [_][__\\ \\|___________#___________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n //__ __|\\\\ | -----\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ | #\n #[_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n //__ __|\\\\----- |\n \\--([==o \\\\ | | -----\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ | #\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/o o| | /|\\\n _\\ o/_ | | ||\n / \\ / \\ | \\|/\n //__ *---- | |\n \\--([==o \\\\ | | ---\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ | #\n |_||_| \\ |\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/- o| | /|\\\n _\\ O/_ | | ||\n / \\*/ \\ | \\|/\n //__***|\\\\ | |\n \\--([*=o \\\\ | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n___________________( )( )_____| |\n | || | \\ |\n |_||_| \\ | #\n [_][__\\ \\|________________________________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\ O/_ | | ||\n / *** \\ | \\|/\n //_*****\\\\ | |\n \\--(***o \\\\ | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|____________________#__________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\***_ | | ||\n / *****\\ | \\|/\n //*******\\ | |\n \\--***** \\\\ | |\n | ***| \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ | #\n [_][__\\ \\|_______________________________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\ -/_ | | ||\n / *** \\ | \\|/\n //_*****\\\\ | |\n \\--(***o \\\\ | |\n | | \\\\ | |\n |====| \')| |\n | || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|______________________#________\n1\n /~___\\ | |\n /_/x x| | /|\\\n _\\ -/_ | | ||\n / \\*/ \\ | \\|/\n // ***|\\\\ | |\n \\\\ * | \\\\ | |\n \\\\ | \\\\ | |\n [==o=| \')| |\n /| || | | |\n____________________( )( )_____| |\n | || | \\ |\n |_||_| \\ |\n [_][__\\ \\|_______________________#_______\n3\n /~___\\ | |\n /_/x x| | /|\\\n _\\ -/_ | | ||\n / \\ / \\ | \\|/\n // |\\\\ | |\n || | \\\\ | |\n || | | \\\\ | |\n || |====| \')| |\n (\' | || | | |\n____________________( )( )_____| |\n [==o| || | \\ |\n / |_||_| \\ |\n [_][__\\ \\|________________________#______\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n10\n __ /~~\\ __\n /__\\ |<><>| /__\\\n |<><>| /_/\\_\\ |<><>|\n (_/\\_) /\\___/\\ (_/\\_)\n / \\ // [ ]|\\\\ / \\\n ||/(===o ||| [_]| \\\\ //| __ |\\\\\n | / \\ | ||| | \\\\ || |/ \\| \\\\\n \\/][][\\/ |||====| \\\\ || [][][] \\\\\n |\\ /| #/|\\ /I\\ # || |\\ /| \')\n |_||_| / | || I \\ \'] |_||_|\n [ ][ ] / | || | \\ [I [ ][ ]\n | || | / | || | \\ I | || |\n | || | / | || | \\ | || |\n6\n __ /~~\\ __\n /__\\ |<><>| /__\\\n |<><>| /_/\\_\\ |<><>|\n (_/\\_) /\\___/\\ (_/\\_)\n / \\ // [ ]|\\\\ / \\\n ||/(===o ||| [_]| \\\\ ||/(===o\\\n | / \\ | ||| | \\\\ | / \\| \\\\\n \\/][][\\/ |||====| \\\\ \\/][][] \\\\\n |\\ /| #/|\\ /I\\ # |\\ /| \')\n |_||_| / | || I \\ |_||_|\n [ ][ ] / | || | \\ [ ][ ]\n | || | / | || | \\ | || |\n | || | / | || | \\ | || |\n18\n __ /~~\\ __\n /__\\ |<><>| /__\\\n |<><>| /_/\\_\\ |<><>|\n (_/\\_) /\\___/\\ (_/\\_)\n / \\ // [ ]|\\\\ / \\\n ||/(===o //| [_]| \\\\ ||/(===o\n | / \\ | \\\\| | // | / \\||\n \\/][][\\/ \\#====|#/ \\/][][\\/\n |\\ /| /|\\ /I\\ |\\ /|\n |_||_| / | || I \\ |_||_|\n [ ][ ] / | || | \\ [ ][ ]\n | || | / | || | \\ | || |\n | || | / | || | \\ | || |\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n30\n /~~\\\n |<><>| Commander, tear this ship apart\n /_/\\_\\ until you\'ve found those plans.\n /\\___/\\\n // [ ]|\\\\\n //| [_]| \\\\\n \\\\| | //\n \\#====|#/\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n2\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\\n // [ ]|\\\\\n //| [_]| \\\\\n \\\\| | //\n \\#====|#/\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n30\n /~~\\\n |<><>| And bring me the passengers.\n /_/\\_\\ # I want them alive!\n /\\___/\\ //\n // [ ]|\\\\//\n //| [_]| \\/\n \\\\| |\n \\#====|\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n5\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\\n // [ ]|\\\\\n //| [_]| \\\\\n \\\\| | //\n \\#====|#/\n /|\\ /I\\\n / | || I \\\n / | || | \\\n / | || | \\\n / | || | \\\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n /~\\\n |oo )\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n11\n /~\\\n ( oo|\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n11\n /~\\\n |oo )\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n11\n /~\\\n ( oo|\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n \\\\ \\_/ ||\n \\|\\ /| ||\n # _ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n6\n /~\\\n |oo )\n _\\=/_\n / _ \\\n //|/.\\|\\\\\n || \\_/ ||\n || |\\ /| ||\n # \\_ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n6\n /~\\\n R2-D2! |oo )\n Where are you? _\\=/_\n / _ \\\n //|/.\\|\\\\\n || \\_/ ||\n || |\\ /| ||\n # \\_ _/ #\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n9\n /~\\\n R2-D2! |oo )\n Where are you? # _\\=/_ #\n \\\\ / _ \\ //\n \\\\//|/.\\|\\\\//\n \\/ \\_/ \\/\n |\\ /|\n \\_ _/\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n9\n /~\\\n R2-D2! |oo )\n Where are you? # _\\=/_ #\n \\\\ / _ \\ //\n \\\\//|/.\\|\\\\//\n \\/ \\_/ \\/\n |\\ /|\n \\_ _/\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n8\n /~\\\n ( oo|\n # _\\=/_ #\n \\\\ / _ \\ //\n \\\\//|/.\\|\\\\//\n \\/ \\_/ \\/\n |\\ /|\n \\_ _/\n | | |\n | | |\n []|[]\n | | |\n_______________________________/_]_[_\\_____________________________\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n ,===\n (@o o@\n \\ -/\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @ | | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n______________________(_)(__\\______[_]_____[_]_____________________\n11\n ,===\n (@o o@\n \\ -/\n //~ ~~\\ ___\n / ( ) \\ / ()\\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n______________________(_)(__\\______[_]_____[_]_____________________\n8\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n11\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) / ()\\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n7\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n6\n\n ===,\n @o o@)\n / \\-_/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n16\n\n ,===\n (@o o@\n / \\_-/ ___\n /| |) ) /() \\\n | \\ \\/__ _|_____|_\n | \\____@=| | === | |\n | | |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n7\n ===,\n @o o@)\n \\- /\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n1\n ===,\n @o o@)\n \\- /\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ [_] /=\\\n_______________________(_)(__\\_____[_]_____[_]_____________________\n10\n ===,\n @o o@)\n \\- /\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @| | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\ /=\\\n_______________________(_)(__\\_____[_]_[_]_[_]_____________________\n13\n ,===\n (@o o@\n \\ -/\n //~ ~~\\ ___\n / ( ) \\ /() \\\n /_/\\ /\\_| _|_____|_\n \\\\ \\\\ /| || | | === | |\n @ | | | @ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n / | \\ |~ \\___/ ~|\n ~~~~~~~ /=\\ /=\\ /=\\\n_______________________(_)(__\\_____[_]_[_]_[_]_____________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ \\\\ \\_/ ||\n | | === | | \\|\\ /| ||\n |_| O |_| # _ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n20\n /~\\\n |oo ) At last!\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n7\n /~\\\n |oo ) Where have\n _\\=/_ you been?\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo ) Where have\n _\\=/_ you been?\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n9\n /~\\\n |oo ) Where have\n _\\=/_ you been?\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\ #\n /() \\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n /() \\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\ #\n /() \\ \\\\//|/.\\|\\\\//\n _|_____|_ \\/ \\_/ \\/\n | | === | | |\\ /|\n |_| O |_| \\_ _/\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n / ()\\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ # / _ \\\n /() \\ \\\\//|/.\\|\\\\\n _|_____|_ \\/ \\_/ ||\n | | === | | |\\ /| ||\n |_| O |_| \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n21\n /~\\\n |oo ) Secret mission?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n3\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n /() \\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n12\n /~\\\n |oo ) What plans?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo ) What plans?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n8\n /~\\\n |oo ) What plans?\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n6\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /__\\ /__\\\n |<><>| |<><>|\n (_/\\_) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n__________________________/__][_]_________[_][__\\__________________\n3\n /__\\ /__\\\n |<><>| |<><>|\n (_/\\_) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n___________________________/__][_]_________[_][__\\_________________\n3\n /__\\ /__\\\n |><> | |<><>|\n (/\\__) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n____________________________/__][_]_________[_][__\\________________\n3\n /__\\ /__\\\n |><> | |<><>|\n (/\\__) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n_____________________________/__][_]_________[_][__\\_______________\n3\n /__\\ /__\\\n |><> | |<><>|\n (/\\__) (_/\\_)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n______________________________/__][_]_________[_][__\\______________\n3\n /__\\ /__\\\n |><> | |><> |\n (/\\__) (/\\__)\n / \\ / \\\n //| __ |\\\\ ||/(===o\n // |/ \\| \\\\ | / \\ |\n // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n_______________________________/__][_]_________[_][__\\_____________\n3\n /__\\ /__\\\n |><> | |><> |\n (/\\__) (/\\__)\n / \\ / \\\n\\ //| __ |\\\\ ||/(===o\n| // |/ \\| \\\\ | / \\ |\n| // [][][] || \\/][][\\/\n |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n________________________________/__][_]_________[_][__\\____________\n3\n /__\\ /__\\\n |><> | |><> |\n (/\\__) (/\\__)\n\\ / \\ / \\\n \\ //| __ |\\\\ ||/(===o\no| // |/ \\| \\\\ | / \\ |\n|| // [][][] || \\/][][\\/\n@ |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n | || | | || |\n |_||_| |_||_|\n_________________________________/__][_]_________[_][__\\___________\n3\n /__\\ /__\\\n@ |><> | |><> |\n (/\\__) (/\\__)\n~\\ / \\ / \\\n\\ \\ //| __ |\\\\ ||/(===o\n=o| // |/ \\| \\\\ | / \\ |\n || // [][][] || \\/][][\\/\n @ |\' |\\ /| [\' |\\ /|\n |_||_| I] |_||_|\n [ ][ ] I [ ][ ]\n\\ | || | | || |\n~ |_||_| |_||_|\n\\_________________________________/__][_]_________[_][__\\__________\n3\n= /__\\ /__\\\no@ |><> | |><> |\n/ (/\\__) (/\\__)\n~~\\ / \\ / \\\n)\\ \\ //| __ |\\\\ ||/(===o\n==o| // |/ \\| \\\\ | / \\ |\n| || // [][][] || \\/][][\\/\n| @ |\' |\\ /| [\' |\\ /|\n| |_||_| I] |_||_|\n| [ ][ ] I [ ][ ]\n \\ | || | | || |\n~~ |_||_| |_||_|\n_\\_________________________________/__][_]_________[_][__\\_________\n3\n== /__\\ /__\\\n o@ |><> | |><> |\n-/ (/\\__) (/\\__)\n ~~\\ / \\ / \\\n )\\ \\ //| __ |\\\\ ||/(===o\n@==o| // |/ \\| \\\\ | / \\ |\n | || // [][][] || \\/][][\\/\n | @ |\' |\\ /| [\' |\\ /|\n | |_||_| I] |_||_|\n | [ ][ ] I [ ][ ]\n \\ | || | | || |\n~~~ |_||_| |_||_|\n(_\\_________________________________/__][_]_________[_][__\\________\n3\n=== /__\\ /__\\\no o@ |><> | |><> |\n -/ (/\\__) (/\\__)\n ~~\\ / \\ / \\\n_ )\\ \\ //| __ |\\\\ ||/(===o\n/@==o| // |/ \\| \\\\ | / \\ |\n /| || // [][][] || \\/][][\\/\n| | @ |\' |\\ /| [\' |\\ /|\n| | |_||_| I] |_||_|\n| | [ ][ ] I [ ][ ]\n| \\ | || | | || |\n~~~~ |_||_| |_||_|\n)(_\\_________________________________/__][_]_________[_][__\\_______\n3\n,=== /__\\ /__\\\n@o o@ |><> | |><> |\n\\ -/ (/\\__) (/\\__)\n~ ~~\\ / \\ / \\\n__ )\\ \\ //| __ |\\\\ ||/(===o\n_/@==o| // |/ \\| \\\\ | / \\ |\n\\ /| || // [][][] || \\/][][\\/\n | | @ |\' |\\ /| [\' |\\ /|\n | | |_||_| I] |_||_|\n | | [ ][ ] I [ ][ ]\n | \\ | || | | || |\n~~~~~ |_||_| |_||_|\n_)(_\\_________________________________/__][_]_________[_][__\\______\n3\n ,=== /__\\ /__\\\n(@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n/~ ~~\\ / \\ / \\\n\\__ )\\ \\ //| __ |\\\\ ||/(===o\n\\_/@==o| // |/ \\| \\\\ | / \\ |\n\\\\ /| || // [][][] || \\/][][\\/\n| | | @ |\' |\\ /| [\' |\\ /|\n| | | |_||_| I] |_||_|\n| | | [ ][ ] I [ ][ ]\n | \\ | || | | || |\n~~~~~~ |_||_| |_||_|\n(_)(_\\_________________________________/__][_]_________[_][__\\_____\n3\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n//~ ~~\\ / \\ / \\\n \\__ )\\ \\ //| __ |\\\\ ||/(===o\n\\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n/ | \\ | || | | || |\n~~~~~~~ |_||_| |_||_|\n_(_)(_\\_________________________________/__][_]_________[_][__\\____\n2\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\\\\\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n7\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n18\n ,=== /__\\ /__\\\n (@o o@ There\'s one. |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n3\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ //| __ |\\\\ ||/(===o\n \\\\_/@==o| // |/ \\| \\\\ | / \\ |\n |\\ /| || // [][][] || \\/][][\\/\n | | | @ |\' |\\ /| [\' |\\ /|\n | | | |_||_| I] |_||_|\n | | | [ ][ ] I [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n8\n ,=== /__\\ /__\\\n (@o o@ Set for stun! |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ /o===)\\|| ||/(===o\n \\\\_/@==o| // |/ \\ | | / \\ |\n |\\ /| || // [][][\\/ \\/][][\\/\n | | | @ |\' |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n9\n ,=== /__\\ /__\\\n (@o o@ Set for stun! |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ o===)\\|| ||/(===o\n \\\\_/@==o| ||/ \\ | | / \\ |\n |\\ /| || \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n5\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ o===)\\|| ||/(===o\n \\\\_/@==o| ||/ \\ | | / \\ |\n |\\ /| || \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ / \\ / \\\n\\ \\__ )\\ \\ *===)\\|| ||/(===o\n \\\\_/@==*| ||/ \\ | | / \\ |\n |\\ /| || \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ (/\\__) (/\\__)\n //~ ~~\\ | / \\ / \\\n\\ \\__ )\\ \\ | | o===)\\|| ||/(===o\n \\\\_/@=***---- | ||/ \\ | | / \\ |\n |\\ /| *| \\/][][\\/ \\/][][\\/\n | | | @ |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ |><> | |><> |\n \\ -/ | (/\\__) (/\\__)\n //~ ~~* | | / \\ / \\\n\\ \\__ )* * | | | o===)\\|| ||/(===o\n \\\\_/@***** ----- | | ||/ \\ | | / \\ |\n |\\ /|*** | \\/][][\\/ \\/][][\\/\n | | | * |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== /__\\ /__\\\n (@o o@ | |><> | |><> |\n \\ -/ | | (/\\__) (/\\__)\n //~ ~~\\ | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | o===)\\|| ||/(===o\n \\\\_/@=*** ----- | | | ||/ \\ | | / \\ |\n |\\ /| *| | | \\/][][\\/ \\/][][\\/\n | | | @ | |\\ /| |\\ /|\n | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | /__\\ /__\\\n (@o o@ | | |><> | |><> |\n \\ -/ | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | o===)\\|| ||/(===o\n \\\\_/@==*| ----| | | ||/ \\ | | / \\ |\n |\\ /| || | | | \\/][][\\/ \\/][][\\/\n | | | @ | | |\\ /| |\\ /|\n | | | | |_||_| |_||_|\n | | | [ ][ ] [ ][ ]\n / | \\ | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | | /__\\ /__\\\n (@o o@ | | | |><> | |><> |\n \\ -/ | | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | | o===)\\|| ||/(===o\n \\\\_/@==o| | | |---|- | ||/ \\ | | / \\ |\n |\\ /| || | | | | \\/][][\\/ \\/][][\\/\n | | | @ | | | |\\ /| |\\ /|\n | | | | | |_||_| |_||_|\n | | | | [ ][ ] [ ][ ]\n / | \\ | | || | | || |\n ~~~~~~~ |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | | | /__\\ /__\\\n (@o o@ | | | | |><> | |><> |\n \\ -/ | | | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | | | o===)\\|| ||/(===o\n \\\\_/@==o| | | | | | --|-- ||/ \\ | | / \\ |\n |\\ /| || | | | | | \\/][][\\/ \\/][][\\/\n | | | @ | | | | |\\ /| |\\ /|\n | | | | | | |_||_| |_||_|\n | | | | | [ ][ ] [ ][ ]\n / | \\ | | | || | | || |\n ~~~~~~~ | |_||_| |_||_|\n__(_)(_\\_________________________________/__][_]_________[_][__\\___\n1\n ,=== | | | | /__\\ /__\\\n (@o o@ | | | | | |><> | |><> |\n \\ -/ | | | | | | (/\\__) (/\\__)\n //~ ~~\\ | | | | | | | / \\ / \\\n\\ \\__ )\\ \\ | | | | | | | o===)\\|| ||/(===o\n \\\\_/@==o| | | | | | | | ----* \\ | | / \\ |\n |\\ /| || | | | | | | \\/][][\\/ \\/][][\\/\n | | | @ | | | | | |\\ /| |\\ /|\n | | | | | | | |_||_| |_||_|\n | | | | | | [ ][ ] [ ][ ]\n / | \\ | | | | || | | || |\n ~~~~~~~ | | |_||_| |_||_|\n__(_)(_\\____|____________________________/__][_]_________[_][__\\___\n1\n ,=== | | | | | /__\\ /__\\\n (@o o@| | | | | | |><> | |><> |\n \\ -/ | | | | | | | (/\\__) (/\\__)\n //~ ~~| | | | | | | | / \\ / \\\n\\ \\__ )\\|\\ | | | | | | | o=*=)\\|| ||/(===o\n \\\\_/@==|| | | | | | | | |*** \\ | | / \\ |\n |\\ /| || | | | | | | \\/*[][\\/ \\/][][\\/\n | | | | | | | | | |\\ /| |\\ /|\n | | | | | | | | |_||_| |_||_|\n | | | | | | | [ ][ ] [ ][ ]\n / | \\| | | | | || | | || |\n ~~~~~~~| | | |_||_| |_||_|\n__(_)(_\\|___|____________________________/__][_]_________[_][__\\___\n1\n ,|== | | | | | /__\\ /__\\\n (@| -@| | | | | | |><> | |><> |\n \\|-/ | | | | | | | (/\\__) (/\\__)\n //~| ~~| | | | | | | / * \\ / \\\n\\ \\_| )\\|\\ | | | | | | o***)\\|| ||/(===o\n \\\\_|@==|| | | | | | | *****\\ | | / \\ |\n |\\|/| || | | | | | | \\***][\\/ \\/][][\\/\n | | | | | | | | | |* /| |\\ /|\n | | | | | | | | |_||_| |_||_|\n | | | | | | | [ ][ ] [ ][ ]\n / | \\| | | | | || | | || |\n ~~~|~~~| | | |_||_| |_||_|\n__(_|(_\\|___|____________________________/__][_]_________[_][__\\___\n1\n| ,|== | | | | | /__\\ /__\\\n| (@| -@| | | | | | |<><>| |><> |\n| \\|-/ | | | | | | | (_/\\_) (/\\__)\n|//~| ~~| | | | | | | / \\ / \\\n| \\_| )\\|\\ | | | | | | o=*=)\\|| ||/(===o\n|\\\\_|@==|| | | | | | | |*** \\ | | / \\ |\n| |\\|/| || | | | | | | \\/*[][\\/ \\/][][\\/\n| | | | | | | | | | | /| |\\ /|\n| | | | | | | | | |_||_| |_||_|\n| | | | | | | | [ ][ ] [ ][ ]\n|/ | \\| | | | | || | | || |\n|~~~|~~~| | | |_||_| |_||_|\n|_(_|(_\\|___|____________________________/__][_]_________[_][__\\___\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /__\\\n | <><|\n (__/\\)\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n12\n /__\\\n | <><| Inform Lord Vader we have\n (__/\\) a prisoner.\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n7\n /__\\\n |<><>| Inform Lord Vader we have\n (_/\\_) a prisoner.\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n5\n /__\\\n |<><>|\n (_/\\_)\n / \\\n ||/(===o\n | / \\ |\n \\/][][\\/\n | || |\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n____________[_][__\\________________________________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /----------------------\\\n | |oo ) |\n | _\\=/_ |\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n10\n /----------------------\\\n | |oo ) | I\'m going to\n | _\\=/_ | regret this.\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n7\n /----------------------\\\n | ( oo| | I\'m going to\n | _\\=/_ | regret this.\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n7\n /----------------------\\\n | |oo ) | I\'m going to\n | _\\=/_ | regret this.\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n2\n /----------------------\\\n | |oo ) |\n | _\\=/_ |\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n |\\____________________/|\n | _\\=/_ |\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n |\\____________________/|\n | ___ / _ \\ |\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n | / \\ |\n |\\____________________/|\n | / ()\\ //|/.\\|\\\\|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n | _|_____|_ || \\_/ ||\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | \\________/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n || | === | | || |\\ /| ||\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | | || |\n | \\________/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n ||_| O |_| # \\_ _/ #|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | | || |\n | | | |\n | \\_______// |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n | || O || | | | |\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | | || |\n | | _| |\n | |_ / | |\n | \\\\_____/_/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n | ||__*__|| | | | |\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | / \\ |\n | | _| |\n | |_ / | |\n | |)\\ //|| |\n | \\_|___||_/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n ||~ \\___/ ~| []|[] |\n \\----------------------/\n___________________________________________________________________\n1\n /----------------------\\\n | \\ ________ / |\n | / \\ |\n | |_ / | |\n | |)\\ //|| |\n | |__|_ || | |\n | \\_|_|_||_/ |\n | / \\ |\n | / \\ |\n | / \\ |\n |\\____________________/|\n \\----------------------/\n___________________________________________________________________\n10\n /----------------------\\\n | \\ / |\n | \\ ________ / |\n | / /\\ |\n | |)\\ //|| |\n | |__|_ || | |\n | |= | | || || |\n | \\_|_|__#_/ |\n | / \\ |\n | / \\ |\n |/ \\ |\n \\----------------------/\n___________________________________________________________________\n10\n /----------------------\\\n | \\ / |\n | \\ ________ / |\n | / /\\ |\n | |)\\ //|| |\n | |__|_ || | |\n | |= | | || || |\n | \\_|_|_#__/ |\n | / \\ |\n | / \\ |\n |/ \\ |\n \\----------------------/\n___________________________________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ /___ ___\\ /\n / / / \\ / \\ \\ \\\n | / | || | \\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\ | || | / |\n \\ \\ \\___/ \\___/ / /\n / \\__________/ \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ * /___ ___\\ * /\n / / / \\ / \\ \\ \\\n | / | || | \\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\ | || | / |\n \\ \\ \\___/ \\___/ / /\n / * \\__________/ * \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ ** /___ ___\\/** /\n / ** / \\ / \\ ** \\\n | / | || | \\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\ | || | / |\n \\ ** \\___/ \\___/ ** /\n / ** \\__________/ ** \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / __________ \\ / /\n \\ ****___ ___**** /\n /****/ \\ / \\****\\\n | /**| || |**\\ |\n | | \\___/ \\___/ | |\n | | | |\n | | ___ ___ | |\n | | / \\ / \\ | |\n | \\**| || |**/ |\n \\****\\___/ \\___/****/\n / ***\\__________/*** \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ /**_________*\\ / /\n \\ *****__ __***** /\n /***** \\ / *****\\\n | **** || *****|\n | *** \\___/ \\___/ **|\n | | |*|\n | | ___ ___ | |\n | * / \\ / \\ ****|\n |****| || ******|\n \\*****___/ \\___*****/\n / *****________***** \\\n / \\***________*/ \\\n1\n \\ ____________ /\n \\ \\ /******__****\\ / /\n \\ ******* ******* /\n /****** \\ / *******\\\n |******* || *******|\n |******___/ \\___/ ****|\n |** ***|\n |*| ___ ___ ***|\n |**** / \\ / \\*****|\n |****** || *******|\n \\******__/ \\_*******/\n / *******_____****** \\\n / \\*****___****/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ****************** /\n /********************\\\n |******* || *********|\n |******___/ \\_********|\n |***** *******|\n |***** ___ _********|\n |******** \\ /*********|\n |********* ||**********|\n \\********************/\n / ****************** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ****************** /\n /********************\\\n |**********************|\n |**********************|\n |**********************|\n |**********************|\n |**********************|\n |**********************|\n \\********************/\n / ****************** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ****************** /\n /********************\\\n |********* ************|\n |********/ \\ **********|\n |******| \\_/\\_*********|\n |*******|/ \\/ ********|\n |********\\ / **********|\n |********** ***********|\n \\********************/\n / ****************** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /************\\ / /\n \\ ********* .******* /\n /****** ______ ****\\\n |****** / _ _ \\ *****|\n |***** | / \\/ \\ |. ****|\n |***. | \\_/\\_/ | ****|\n |***** | / \\/ \\ | *****|\n |***** | \\_/\\_/ |******|\n |****** \\______/*******|\n \\******* .* *******/\n / ******** ******** \\\n / \\************/ \\\n1\n \\ ____________ /\n \\ \\ /** . *\\ / /\n \\ *** . * /\n /** . * *\\\n |*** .* **|\n |* ---- . *|\n |* . |()()| |\n |. | |. * |\n |* |()()| **|\n |** * .---- ***|\n \\*** . . ***/\n / **** . *** \\\n / \\***____*___*/ \\\n1\n \\ ____________ /\n \\ \\ / . * \\ / /\n \\ * . * /\n / . \\\n |* . |\n | ---- . |\n | . |()()| |\n |. | |. * |\n | |()()| . |\n | .---- |\n \\ * . . /\n / . ** \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / . \\ / /\n \\ . /\n / . * \\\n | . |\n | -- . |\n | . |OO| |\n |. * .|OO| . |\n | -- . |\n | . |\n \\ . . /\n / . \\\n / \\____________/ \\\n1\n \\ ____________ /\n \\ \\ / . \\ / /\n \\ . /\n / . \\\n | . |\n | -- . |\n | . |OO| |\n |. .|OO| . |\n | -- . |\n | . |\n \\ . . /\n / . \\\n / \\____________/ \\\n2\n \\ ____________ /\n \\ \\ / . \\ / /\n \\ . /\n / . \\\n | . |\n | _ . |\n | . (_) |\n |. . . |\n | . |\n | . |\n \\ . . /\n / . \\\n / \\____________/ \\\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | o . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | " . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n5\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n24\n ____________\n / \\ / . \\ / \\\n There goes \\ \\ . / /\n another one. / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n25\n ____________\n / \\ / . \\ / \\\n \\ \\ . / / Hold your fire!\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n2\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n24\n ____________\n / \\ / . \\ / \\\n \\ \\ . / / There\'s no\n / \\ / \\ / \\ life forms.\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n5\n ____________\n / \\ / . \\ / \\\n \\ \\ . / /\n / \\ / \\ / \\\n | . |\n | . |\n | . |\n |. . . |\n | . |\n | . |\n \\ / \\ . ./ \\ /\n / / . \\ \\\n \\ / \\____________/ \\ /\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ____________\n / __________ \\\n /__|O=<88>=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O=O<>| |><> |\n (_/\\_) (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][_] \\________________[_][__\\____\n37\n /__\\ /__\\\n |<><>| Someone was |><> |\n (_/\\_) in the pod. (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][_] \\________________[_][__\\____\n5\n /__\\ /__\\\n |<><>| |><> |\n (_/\\_) (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][_] \\________________[_][__\\____\n6\n /__\\ /__\\\n | <><| Look sir - |><> |\n (__/\\) droids. (/\\__)\n / \\ / \\\n //| __ \\\\ ||/(===o\n // |/ \\| || | / \\ |\n //__[][][] || \\/][][\\/\n ____/|\' |\\ /|.\'| |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][__\\ \\________________[_][__\\____\n34\n /__\\ /__\\\n | <><| Look sir - |><> |\n (__/\\) droids. (/\\__)\n / \\ /O / \\\n //| __ \\\\// ||/(===o\n // |/ \\| \\/ | / \\ |\n //__[][][] \\/][][\\/\n ____/|\' |\\ /|. |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][__\\ \\________________[_][__\\____\n6\n /__\\ /__\\\n | <><| |><> |\n (__/\\) (/\\__)\n / \\ /O / \\\n //| __ \\\\// ||/(===o\n // |/ \\| \\/ | / \\ |\n //__[][][] \\/][][\\/\n ____/|\' |\\ /|. |\\ /|\n ,---,_______ / |_||_| \\ |_||_|\n/|O O| / [ ][ ] \\ [ ][ ]\n |O O| / | || | \\ | || |\n~~~~~ " _______|_||_|_______\\ |_||_|\n " " " " "/ [_][__\\ \\________________[_][__\\____\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n\n\n .\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n\n\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n\n .\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n\n| .\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n\n|\n |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n_\n=|\n/ |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n_\n=| .\n/ |\n _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n__\n =| .\n / |\n/ _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n__\n =|\n / |\n/ _________ .|\n __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n___\n =|\n / |\n / _________ .|\n/ __/ o o o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n____\n =| .\n / |\n / _________ .|\n_/ __/ o o o o \\ .||.\no____________________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n_____\n =| .\n / |\n / _________ .|\n__/ __/ o o o o \\ .||.\noo___________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n_____\n =|\n / |\n / _________ .|\n__/ __/ o o o o \\ .||.\noo___________________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n______\n =|\n] / |\n / _________ .|\n___/ __/ o o o o \\ .||.\nooo__________________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n______\n =| .\n] / |\n / _________ .|\n___/ __/ o o o o \\ .||.\nooo__________________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n_______\n_ =| .\n_] / |\n / _________ .|\n____/ __/ o o o o \\ .||.\n_ooo_________________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n_______\n_ =|\n_] / |\n / _________ .|\n____/ __/ o o o o \\ .||.\n_ooo_________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n________\n _ =|\n[_] / |\n / _________ .|\n_____/ __/ o o o o \\ .||.\n__ooo________________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n_________\n _ =| .\n [_] / |\n / _________ .|\n______/ __/ o o o o \\ .||.\no__ooo_______________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n__________\n _ =| .\n [_] / |\n / _________ .|\n_______/ __/ o o o o \\ .||.\noo__ooo______________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n__________\n _ =|\n [_] / |\n / _________ .|\n_______/ __/ o o o o \\ .||.\noo__ooo______________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n___________\n _ =|\n [_] / |\n / _________ .|\n________/ __/ o o o o \\ .||.\nooo__ooo_____________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n___________\n _ =| .\n [_] / |\n / _________ .|\n________/ __/ o o o o \\ .||.\nooo__ooo_____________________________________|__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n ___________\n| _ =| .\n| [_] / |\n| / _________ .|\n|________/ __/ o o o o \\ .||.\n_ooo__ooo____________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n| _ =|\n| [_] / |\n| / _________ .|\n|________/ __/ o o o o \\ .||.\n_ooo__ooo____________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n__ooo__ooo___________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n__ooo__ooo___________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n___ooo__ooo__________________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n____ooo__ooo_________________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n_____ooo__ooo________________________________|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n_____ooo__ooo________________________________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ __/ o o o o \\ .||.\n______ooo__ooo_______________________________|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo______________________________||__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo______________________________||__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo______________________________||__|__________|__|[]|_\n\n3\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo_____________________________|_|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo_____________________________|_|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo_____________________________|_|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo____________________________|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + __/ o o o o \\ .||.\n______ooo__ooo____________________________|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________________|__||__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________________|__||__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________________|__|_|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________________|__|_|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________________|__|_|__|__________|__|[]|_\n\n4\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________________|__|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________________|__|__|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________________|__|___|__|__________|__|[]|_\n\n1\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________________|__|___|__|__________|__|[]|_\n\n5\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________________|__|___|__|__________|__|[]|_\n\n1\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________________|___|___|__|__________|__|[]|_\n\n6\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________________|___|___|__|__________|__|[]|_\n\n4\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________________|___|___|__|__________|__|[]|_\n\n2\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n4\n\n\n\n\n Luke! Luke!\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n2\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n2\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo______________________|_____|__|__|__________|__|[]|_\n\n4\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_____________________|______|__|__|__________|__|[]|_\n\n6\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_____________________|______|__|__|__________|__|[]|_\n\n6\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo____________________|_______|__|__|__________|__|[]|_\n\n4\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo____________________|_______|__|__|__________|__|[]|_\n\n2\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________|________|__|__|__________|__|[]|_\n\n5\n\n\n\n Tell uncle, if he gets\n a translator...\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________|________|__|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo___________________|________|__|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________|_________|__|__|__________|__|[]|_\n\n4\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________|_________|__|__|__________|__|[]|_\n\n4\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo__________________|_________|__|__|__________|__|[]|_\n\n2\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________|__________|__|__|__________|__|[]|_\n\n6\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________|__________|__|__|__________|__|[]|_\n\n2\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_________________|__________|__|__|__________|__|[]|_\n\n4\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________|___________|__|__|__________|__|[]|_\n\n6\n\n\n\n ...be sure it speaks\n Bocce.\n\n ___________\n | _ =| .\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________|___________|__|__|__________|__|[]|_\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo________________|___________|__|__|__________|__|[]|_\n\n5\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] / |\n | / _________ .|\n |________/ + + __/ o o o o \\ .||.\n______ooo__ooo_______________|____________|__|__|__________|__|[]|_\n\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | \\\\\n || | | | \\\\\n (` |====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n20\n ====\n ~~o o Doesn\'t look like we have\n _\\ -/_ much of a choice...\n / \\ / \\\n //| | |\\\\\n || | | | \\\\\n || | | | \\\\\n (` |====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n3\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | \\\\\n || | | | \\\\\n (` |====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n2\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n \\\\| | | \\\\\n \\\\ | | \\\\\n )====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n31\n ====\n ~~o o ...but I\'ll remind him.\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n \\\\| | | \\\\\n \\\\ | | \\\\\n )====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n6\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n \\\\| | | \\\\\n \\\\ | | \\\\\n )====| \')\n | || |\n (_)(_) ___\n |_||_| / |\n |_||_| / |\n_____________[_][__\\______/ |\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n9\n /~\\ / / / \\\n |oo ) | | | |\n _____ _\\=/_ | | | |\n / \\ / _ \\ \\ \\ \\_____/\n | o o| //|/.\\|\\\\ \\ \\\n _|_____|_ || \\_/ || \\ \\\n | | === | | || |\\ /| || \\ \\ _____\n |_| o |_| # \\_ _/ # \\ \\ / \\\n || o || | | | \\ \\ | |\n ||__*__|| | | | \\ \\ | |\n |~ \\___/ ~| []|[] \\ \\ \\_____/\n /=\\ /=\\ /=\\ | | | \\ \\_____________\n------[_]-[_]-[_]--------/_]-[_\\--------------------\\______________\n6\n /~\\ / / / \\\n ( oo| | | | |\n _____ _\\=/_ | | | |\n / \\ / _ \\ \\ \\ \\_____/\n | o o| //|/.\\|\\\\ \\ \\\n _|_____|_ || \\_/ || \\ \\\n | | === | | || |\\ /| || \\ \\ _____\n |_| o |_| # \\_ _/ # \\ \\ / \\\n || o || | | | \\ \\ | |\n ||__*__|| | | | \\ \\ | |\n |~ \\___/ ~| []|[] \\ \\ \\_____/\n /=\\ /=\\ /=\\ | | | \\ \\_____________\n------[_]-[_]-[_]--------/_]-[_\\--------------------\\______________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n30\n /""\\ ====\n / o o Luke! Take these two o o~~\n _\\ -/_ over to the garage. _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n30\n /""\\ ====\n / o o I want them cleaned o o~~\n _\\ -/_ up before dinner. _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n30\n /""\\ ====\n / o o But I was going o o~~\n _\\ -/_ into Toshi station _\\- /_\n /\\\\ //\\ to pick up some / \\ / \\\n // \\\\// \\\\ power converters. //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n29\n /""\\ ====\n / o o You can waste o o~~\n _\\ -/_ time with your _\\- /_\n /\\\\ //\\ friends later. / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n14\n /""\\ ====\n / o o All right. o o~~\n _\\ -/_ Come on. _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n5\n /""\\ ====\n / o o All right. ~~o o\n _\\ -/_ Come on. _\\ -/_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | |//\n || | | \\\\ \\\\ | //\n \') |===== \') )===(|\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\_________________________________/__][__\\_______\n13\n /""\\ ====\n / o o All right. ~~o o\n _\\ -/_ Come on. _\\ -/_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n3\n /""\\ ====\n / o o ~~o o\n _\\ -/_ _\\ -/_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n6\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n30\n /""\\ ====\n / o o Come on Red! o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n1\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n // \\\\// \\\\ //| | |\\\\\n || | \\/ | \\\\ \\\\| | | \\\\\n || | | \\\\ \\\\ | | \\\\\n \') |===== \') )====| \')\n | \\/ | | || |\n | || | (_)(_)\n | || | |_||_|\n |-||-| |_||_|\n____________[_][__\\__________________________________[_][__\\_______\n9\n / / / \\\n | | | |\n _____ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n6\n / / / \\\n | | | |\n _____ | | | |\n / \\ \\ \\ \\_____/\n |o o | \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n2\n / / / \\\n | | | |\n _____ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n __.__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . / / / \\\n . ** \' | | | |\n *||*_ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . ** \' / / / \\\n **** | | | |\n . **||** | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n **** / / / \\\n ****** | | | |\n **||** | | | |\n . / \\ \' \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n . | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n ** / / / \\\n **** | | | |\n *||*_ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \' \\ \\\n . | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n . ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n ** | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n . || o || \' \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n . /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n * | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \' \\ \\ \\_____/\n. /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . / / / \\\n * | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \' \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n . / / / \\\n . | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]---------\'-------------------------\\______________\n1\n . / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \' \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \' \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \' \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \' \\ \\_____________\n------[_]-[_]-[_]-----------------------------------\\______________\n1\n / / / \\\n | | | |\n _||__ | | | |\n / \\ \\ \\ \\_____/\n | o o| \\ \\\n _|_____|_ \\ \\\n | | === | | \\ \\ _____\n |_| o |_| \\ \\ / \\\n || o || \\ \\ | |\n ||__*__|| \\ \\ | |\n |~ \\___/ ~| \\ \\ \\_____/\n /=\\ /=\\ /=\\ \\ \\_____________\n------[_]-[_]-[_]----------------------------\'------\\______________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | \\\\\n || |\\ /| || || | | | \\\\\n # \\_ _/ # (` |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| Uncle Owen! o o~~\n _\\=/_ This R2 unit has _\\- /_\n / _ \\ a bad motivator. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | \\\\\n || |\\ /| || || | | | \\\\\n # \\_ _/ # (` |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n14\n /~\\ ====\n |oo ) Uncle Owen! o o~~\n _\\=/_ This R2 unit has _\\- /_\n / _ \\ a bad motivator. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | \\\\\n || |\\ /| || || | | | \\\\\n # \\_ _/ # (` |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n |oo ) Uncle Owen! o o~~\n _\\=/_ This R2 unit has _\\- /_\n / _ \\ a bad motivator. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || || | | //\n # \\_ _/ # (` |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n3\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || || | | //\n # \\_ _/ # (` |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n ( oo| Excuse me sir! o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || || | | //\n # \\_ _/ # (` |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n ( oo| Excuse me sir! o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n ( oo| That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n |oo ) That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n |oo ) That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || \\\\| | |//\n // |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n19\n /~\\ ====\n |oo ) That R2 unit is in o o~~\n _\\=/_ prime condition. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || \\\\| | |//\n // |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n7\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || \\\\| | |//\n // |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n20\n\n\n\n ___\n / ()\\\n _|_____|_\n | | === | |\n |_| O |_|\n || O ||\n ||__*__||\n |~ \\___/ ~|\n /=\\ /=\\ /=\\\n________________[_]_[_]_[_]________________________________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n21\n /~\\ ====\n ( oo| Uncle Owen! o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n18\n /~\\ ====\n ( oo| What about o o~~\n _\\=/_ that one? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n12\n /~\\ ====\n |oo ) What about o o~~\n _\\=/_ that one? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n11\n /~\\ ====\n |oo ) What about o o~~\n _\\=/_ that one? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || // | | |//\n || |\\ /| || // | | //\n # \\_ _/ # (\' |===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n7\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || \\\\| | |//\n || |\\ /| || \\| | //\n # \\_ _/ # )===(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n4\n /~\\\n |oo ) Now don\'t you\n _\\=/_ forget this.\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n11\n /~\\\n |oo ) Now don\'t you\n _\\=/_ forget this.\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ // \\_/ ||\n | | === | | // |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n17\n /~\\\n |oo ) Now don\'t you\n _\\=/_ forget this.\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n9\n /~\\\n |oo )\n _\\=/_\n ___ / _ \\\n / ()\\ //|/.\\|\\\\\n _|_____|_ || \\_/ ||\n | | === | | || |\\ /| ||\n |_| O |_| # \\_ _/ #\n || O || | | |\n ||__*__|| | | |\n |~ \\___/ ~| []|[]\n /=\\ /=\\ /=\\ | | |\n________________[_]_[_]_[_]________/_]_[_\\_________________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n /_] [_\\ ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n | | | ====\n /_] [_\\ o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n []|[] ====\n | | | o o~~\n /_] [_\\ _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n | | | ====\n []|[] o o~~\n | | | _\\- /_\n /_] [_\\ ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n | | | ====\n | | | o o~~\n []|[] _\\- /_\n | | | ___ / \\ / \\\n /_] [_\\ / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n # \\_ _/ # ====\n | | | o o~~\n | | | _\\- /_\n []|[] ___ / \\ / \\\n | | | / ()\\ //| | |\\\\\n /_] [_\\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n || |\\ /| || ====\n # \\_ _/ # o o~~\n | | | _\\- /_\n | | | ___ / \\ / \\\n []|[] / ()\\ //| | |\\\\\n | | | _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n || \\_/ || ====\n || |\\ /| || o o~~\n # \\_ _/ # _\\- /_\n | | | ___ / \\ / \\\n | | | / ()\\ //| | |\\\\\n []|[] _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n //|/.\\|\\\\ ====\n || \\_/ || o o~~\n || |\\ /| || _\\- /_\n # \\_ _/ # ___ / \\ / \\\n | | | / ()\\ //| | |\\\\\n | | | _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n / _ \\ ====\n //|/.\\|\\\\ o o~~\n || \\_/ || _\\- /_\n || |\\ /| || ___ / \\ / \\\n # \\_ _/ # / ()\\ //| | |\\\\\n | | | _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n _\\=/_ ====\n / _ \\ Thank the maker! o o~~\n //|/.\\|\\\\ _\\- /_\n || \\_/ || ___ / \\ / \\\n || |\\ /| || / ()\\ //| | |\\\\\n # \\_ _/ # _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n ( oo| ====\n _\\=/_ Thank the maker! o o~~\n / _ \\ _\\- /_\n //|/.\\|\\\\ ___ / \\ / \\\n || \\_/ || / ()\\ //| | |\\\\\n || |\\ /| || _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n /~\\ ====\n ( oo| Thank the maker! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n2\n ====\n /~\\ Thank the maker! o o~~\n ( oo| _\\- /_\n _\\=/_ ___ / \\ / \\\n / _ \\ / ()\\ //| | |\\\\\n //|/.\\|\\\\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n22\n ====\n Thank the maker! o o~~\n /~\\ _\\- /_\n ( oo| ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n3\n ====\n o o~~\n /~\\ _\\- /_\n ( oo| ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n15\n ====\n This oil bath o o~~\n /~\\ is going to _\\- /_\n ( oo| feel so good. ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n12\n ====\n This oil bath o o~~\n /~\\ is going to _\\- /_\n |oo ) feel so good. ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n5\n ====\n o o~~\n /~\\ _\\- /_\n |oo ) ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n1\n ====\n o o~~\n /~\\ _\\- /_\n ( oo| ___ / \\ / \\\n _\\=/_ / ()\\ //| | |\\\\\n / _ \\ _|_____|_ // | | |//\n =================== | | === | | // | | //\n | | |_| O |_|(\' |===(|\n |_________________| || O || | || |\n | | ||__*__|| (_)(_)\n | | |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n______|_________________|_______[_]_[_]_[_]____/__][__\\____________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n31\n ====\n o o~~ Well, my\n _\\- /_ little friend...\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n15\n ====\n o o~~ ...you\'ve got\n _\\- /_ something jammed\n ___ / \\ / \\ in here real good.\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n16\n ====\n o o~~ ...you\'ve got\n _\\- /_ something jammed\n ___ / \\ / \\ in here real good.\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n | | === | | // | | //\n |_| O |_|(\' |===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n4\n ====\n o o~~\n _\\O /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n Help me, o o~~\n Obi-Wan Kenobi! _\\O /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n15\n ====\n You\'re my only o o~~\n hope! _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n Help me, o o~~\n Obi-Wan Kenobi! _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n15\n ====\n You\'re my only o o~~\n hope! _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n1\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__ __|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n1\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__ __|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n14\n ====\n o o~~ Who is she?\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n11\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n8\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ // | | |//\n ,@ | | === | | // | | //\n /=- |_| O |_|(\' |===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n9\n ====\n o o~~ She\'s\n _\\- /_ beautiful!\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n10\n ====\n He says it\'s o o~~\n nothing sir. _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n18\n ====\n He says it\'s o o~~\n nothing sir. _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n28\n ====\n Old data. o o~~\n Pay it no mind. _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n5\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n ,@ | | === | | \\\\ | //\n /=- |_| O |_| (===(|\n || || O || | || |\n || ||__*__|| (_)(_)\n --~~--- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n3\n ====\n o o~~\n _\\o /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| (===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n11\n ====\n o o~~\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| (===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n10\n ====\n o o~~ Where\'d she go?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| (===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n17\n ====\n o o~~ Where\'d she go?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ // | | | \\\\\n | | === | | // | | | \\\\\n |_| O |_|(\' |====| `)\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n8\n ====\n o o~~ Where\'d she go?\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| )===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n9\n ====\n o o~~ Bring her back!\n _\\- /_\n ___ / \\ / \\\n /() \\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| )===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n21\n ====\n o o~~ Bring her back!\n _\\- /_\n ___ / \\ / \\\n / ()\\ //| | |\\\\\n _|_____|_ \\\\| | |//\n | | === | | \\\\ | //\n |_| O |_| )===(|\n || O || | || |\n ||__*__|| (_)(_)\n ------- |~ \\___/ ~| |_||_|\n | | /=\\ /=\\ /=\\ |_||_|\n_________|_____|______[_]_[_]_[_]____/__][__\\______________________\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n1\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n14\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n13\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n3\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n2\n /~\\ ====\n ( oo| See what you o o~~\n _\\=/_ can do with him. _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n8\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] ------- |~ \\___/ ~| |_||_|\n | | | | | /=\\ /=\\ /=\\ |_||_|\n_____/_]_[_\\_________|_____|______[_]_[_]_[_]____/__][__\\__________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\/() //| | |\\\\\n || \\/ |\\/ \\\\| |__|//\n ------------------------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n29\n /""\\ ====\n / o o o o~~ If these new\n _\\ -/_ _\\- /_ droids do work\n /\\\\ //\\ / \\ / \\ out...\n | \\\\// \\/() //| | |\\\\\n || \\/ |\\/ \\\\| |__|//\n ------------------------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n / o o o o~~ ...I want to\n _\\ -/_ _\\- /_ transmit my\n /\\\\ //\\ / \\ / \\ application\n | \\\\// \\/() //| | |\\\\ to the...\n || \\/ |\\/ \\\\| |__|//\n ------------------------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n / o o o o~~ ...I want to\n _\\ -/_ _\\- /_ transmit my\n /\\\\ //\\ / \\ / \\ application\n | \\\\// \\ //| | |\\\\ to the...\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n / o o o o~~ ...Academy\n _\\ -/_ _\\- /_ this year.\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n6\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n16\n /""\\ ====\n But harvest / o o o o~~\n is when I need _\\ -/_ _\\- /_\n you the most! /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\| |__|//\n --------------\\()-------------(---||//-----\n / ||) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n15\n /""\\ ====\n But harvest / o o o o~~\n is when I need _\\ -/_ _\\- /_\n you the most! /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n29\n /""\\ ====\n / o o o o~~ But it\'s a\n _\\ -/_ _\\- /_ whole \'nother\n /\\\\ //\\ / \\ / \\ year!\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n4\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n / \\\n -------------------------------------------------------\n1\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ / \\ / \\\n | \\\\// \\ //| | |\\\\\n || \\/ |\\\\ \\\\__| |//\n --------------\\()-------------(||---//-----\n / || ) \\\n / == \\\n / \\\n / \\\n /\n -------------------------------------------------------\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n41\n /""\\ ====\n / o o Where are o o~~\n _\\ -/_ you going? _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n4\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n31\n /""\\ Looks like I\'m ====\n / o o going nowhere! o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n3\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n30\n /""\\ I have to go finish ====\n / o o cleaning those droids. o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n5\n /""\\ ====\n / o o o o~~\n _\\ -/_ _\\- /_\n /\\\\ //\\ __ / \\ / \\\n | \\\\// \\ || //| | |\\\\\n || \\/ |\\\\ || \\\\| | |//\n -------------------------------==---------- \\\\ | //\n | | )===(|\n | | | || |\n | | (_)(_)\n | | |_||_|\n | | |_||_|\n______|_________________________________________|___/__][__\\_______\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n14\n ====\n ~~o o\n _\\ -/_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n10\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n5\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n2\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\___________________ // | | |//\n \\ \\ // | | //\n \\ \\ *(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ //| | |\\\\\n____\\_______/~\\_________ // | | |//\n \\ \\ // | | //\n \\ \\ *(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n _\\- /_\n\\ / \\ / \\\n \\ /~\\ //| | |\\\\\n____\\______( oo|________ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n _\\- /_\n\\ /~\\ / \\ / \\\n \\ ( oo| //| | |\\\\\n____\\_______\\=/_________ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n o o~~\n /~\\ _\\- /_\n\\ ( oo| / \\ / \\\n \\ _\\=/_ //| | |\\\\\n____\\_____/_____\\_______ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n ====\n /~\\ o o~~\n ( oo| _\\- /_\n\\ _\\=/_ / \\ / \\\n \\ / _ \\ //| | |\\\\\n____\\____//|/_\\|\\\\______ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n1\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n3\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ *(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n30\n /~\\ ====\n ( oo| What are you doing o o~~\n _\\=/_ hiding back there? _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n30\n /~\\ ====\n ( oo| It wasn\'t my fault o o~~\n _\\=/_ sir... _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n30\n /~\\ ====\n ( oo| ...he kept babbling o o~~\n _\\=/_ about his mission. _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n20\n /~\\ ====\n ( oo| Oh no! o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ // | | |//\n \\ \\ // | | //\n \\ \\ -(] |===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n9\n /~\\ ====\n ( oo| Oh no! o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n\\ / _ \\ / \\ / \\\n \\ //|/.\\|\\\\ //| | |\\\\\n____\\___||__\\_/__||_____ \\\\| | |//\n \\ \\ \\| | //\n \\ \\ )===(|\n \\ \\ | || |\n \\ \\ (_)(_)\n___________________\\_____________\\ |_||_|\n | |_||_|\n_____________________________|_____________________/__][__\\________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~\\ ====\n |oo ) ([__])"\n _\\=/_ | \\-/||\n / _ \\ ||\\ /||\n //|/.\\|\\\\ \\/ | \\/\n // \\_/ || | | |\n // |\\ /| || | | |\n # \\_ _/ # |====|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n10\n /~\\ ====\n ( oo| ([__])"\n _\\=/_ | \\-/||\n / _ \\ ||\\ /||\n //|/.\\|\\\\ \\/ | \\/\n // \\_/ || | | |\n // |\\ /| || | | |\n # \\_ _/ # |====|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| ([__])"\n _\\=/_ | \\-/||\n / _ \\ ||\\ /||\n //|/.\\|\\\\ \\/ | \\/\n || \\_/ || | | |\n || |\\ /| || | | |\n # \\_ _/ # |====|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __>_______________. <__\n -- / \\___________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.000.0 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| /|\n --| / |\n -- \\__ / __/\n --- __>__________. | <__\n -- / \\___________________|____\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.010.0 \\______________/\n\n1\n _______________________________________\n / \\\n | ____|\n --| / |\n --| / |\n -- \\__ / __/\n --- __>_____. | <__\n -- / \\___________________|_________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.020.0 \\______________/\n\n1\n _______________________________________\n / \\\n | _________|\n --| / |\n --| / |\n -- \\__ / __/\n --- __>. | <__\n -- / \\___________________|______________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.040.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\|\n -- \\__ / __/\n --- __> | <__\n -- /___________________|___________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.050.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\__ / \\__/\n --- __> | <__\n -- /______________|______________________|_\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.060.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\__ / \\ __/\n --- __> | | <__\n -- /_________|______________________|______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.070.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\__ / \\ __/\n --- __> | | <__\n -- /____|______________________|___________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.080.0 \\______________/\n\n1\n _______________________________________\n / \\\n | __________ |\n --| / \\ |\n --| / \\ |\n -- \\/_ \\ __/\n --- __> | <__\n -- /______________________|________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.090.1 \\______________/\n\n1\n _______________________________________\n / \\\n | ___________ |\n --| \\ |\n --| \\ |\n -- \\__ \\ __/\n --- __> | <__\n -- /_________________|_____________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.100.1 \\______________/\n\n1\n _______________________________________\n / \\\n |_______ |\n --| \\ |\n --| \\ |\n -- \\__ \\ __/\n --- __> | <__\n -- /____________|__________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.110.1 \\______________/\n\n1\n _______________________________________\n / \\\n |__ |\n --| \\ |\n --| \\ |\n -- \\__ \\ __/\n --- __> | <__\n -- /_______|_______________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --|\\ |\n -- \\_\\ __/\n --- __> <__\n -- /__|____________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.130.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.140.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.150.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.160.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.170.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.180.1 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"_[/\n --- __> ]|<__\n -- /__________________________________]|"|[\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.190.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /_____________________________]|"|[_____\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.200.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /________________________]|"|[__________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.210.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /___________________]|"|[_______________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.220.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /______________]|"|[____________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.230.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /_________]|"|[_________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.240.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --| ]|"|[ |\n -- \\__ ]|"|[ __/\n --- __> ]|"|[ <__\n -- /____]|"|[______________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.250.2 \\______________/\n\n1\n _______________________________________\n / " \\\n | |" |\n --| |"| |\n --|]|"|[ |\n -- \\|_|[ __/\n --- __>[ <__\n -- /|"|[___________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.260.2 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> <__\n -- /_______________________________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.270.2 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,<__\n -- /__________________________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.280.2 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,_____<__\n -- /_____________________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.290.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,__________<__\n -- /________________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.300.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,_______________<__\n -- /___________________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.310.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,____________________<__\n -- /______________/ \\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.320.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> ,______________________. <__\n -- /_________/ \\____\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.330.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __> .______________________. <__\n -- /____/ \\_________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.340.3 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __>____________________. <__\n -- / \\______________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.350.0 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ __/\n --- __>_______________. <__\n -- / \\___________________\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.000.0 \\______________/\n\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n |oo ) Pardon me sir... o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n13\n /~\\ ====\n ( oo| Pardon me sir... o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n10\n /~\\ ====\n ( oo| Pardon me sir... o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n ( oo| ...but couldn\'t we o o~~\n _\\=/_ go after him? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n // \\_/ || || | | |//\n // |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n20\n /~\\ ====\n ( oo| ...but couldn\'t we o o~~\n _\\=/_ go after him? _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n9\n /~\\ ====\n ( oo| It\'s too dangerous o o~~\n _\\=/_ with all the _\\- /_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n11\n /~\\ ====\n ( oo| It\'s too dangerous ~~o o\n _\\=/_ with all the _\\ -/_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| It\'s too dangerous o o~~\n _\\=/_ with all the _\\- /_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n8\n /~\\ ====\n ( oo| It\'s too dangerous o o~~\n _\\=/_ with all the _\\- /_\n / _ \\ Sand People around. / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n15\n /~\\ ====\n ( oo| We\'ll have to o o~~\n _\\=/_ wait until morning. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | |//\n || |\\ /| || ||__ | //\n # \\_ _/ # ([__]==(|\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n11\n /~\\ ====\n ( oo| We\'ll have to o o~~\n _\\=/_ wait until morning. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || ||__ | | ||\n # \\_ _/ # ([__]===| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n7\n /~\\ ====\n ( oo| We\'ll have to o o~~\n _\\=/_ wait until morning. _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || ||__ | | ||\n # \\_ _/ # ([__]===| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || ||__ | | ||\n # \\_ _/ # ([__]===| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n____________/_]_[_\\____________________________/__][__\\____________\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n\n\n __________ ___\n / \\ ______________ /\n/ \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n __________ ____\n/ \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n__________ _____\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n1\n\n\n\n\n\n_________ ______\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n1\n\n Look, there\'s a droid\n on the scanner.\n\n\n_________ ______\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n________ _______\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n_______ ________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n_____ __________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n____ ___________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n___ ____________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n__ _____________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n_ ______________\n \\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n _______________\n\\ ______________ /\n \\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n ________________\n ______________ /\n\\________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n _________________\n ______________ /\n________/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n _________________\n ______________ /\n_______/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Look, there\'s a droid\n on the scanner.\n\n\n ___________________\n ______________ /\n______/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n ____________________\n ______________ /\n_____/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _____________________\n ______________ /\n____/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n ______________________\n ______________ /\n___/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n ______________ /\n__/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n ______________ / \\\n_/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n ______________ / \\_\n/ \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n______________ / \\__\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n_____________ / \\___\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n____________ / \\____\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n___________ / \\_____\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n Hit the accelerator!\n\n\n\n _______________________\n__________ / \\______\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_________ / \\_______\n \\ /\n \\______________________/\n =_+_\n_________====\'_____________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n________ / \\________\n \\ /\n \\______________________/\n =_+_\n__________====\'____________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_______ / \\_________\n \\ /\n \\______________________/\n =_+_\n___________====\'___________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n______ / \\__________\n \\ /\n \\______________________/\n =_+_\n____________====\'__________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_____ / \\___________\n \\ /\n \\______________________/\n =_+_\n_____________====\'_________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n____ / \\____________\n \\ /\n \\______________________/\n =_+_\n______________====\'________________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n___ / \\_____________\n \\ /\n \\______________________/\n =_+_\n_______________====\'_______________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n__ / \\______________\n \\ /\n \\______________________/\n =_+_\n________________====\'______________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n_ / \\_______________\n \\ /\n \\______________________/\n =_+_\n_________________====\'_____________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\________________\n\\ /\n \\______________________/\n =_+_\n__________________====\'____________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\_________________\n /\n\\______________________/\n =_+_\n___________________====\'___________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\__________________\n /\n______________________/\n =_+_\n_____________________====\'_________________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\___________________\n /\n_____________________/\n =_+_\n_______________________====\'_______________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\___________________\n /\n____________________/\n =_+_\n_________________________====\'_____________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\_____________________\n /\n___________________/\n =_+_\n___________________________====\'___________________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\______________________\n /\n__________________/\n =_+_\n_____________________________====\'_________________________________\n\n\n1\n\n\n\n\n\n _______________________\n / \\_______________________\n /\n_________________/\n =_+_\n_______________________________====\'_______________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\________________________\n /\n________________/\n =_+_\n_________________________________====\'_____________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\_________________________\n /\n_______________/\n =_+_\n___________________________________====\'___________________________\n\n\n2\n\n\n\n\n\n _______________________\n / \\__________________________\n /\n______________/\n =_+_\n_____________________________________====\'_________________________\n\n\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ Where do you think ====\n ( oo| you\'re going? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n15\n /~\\ Where do you think ====\n ( oo| you\'re going? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ Where do you think ====\n ( oo| you\'re going? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n \\\\ \\_/ // _|_____|_ \\\\| | |//\n \\\\\\ /// | | === | | \\\\ | //\n #_ _# |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n7\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n5\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n16\n /~\\ What\'s wrong with ====\n ( oo| him now? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n17\n /~\\ What\'s wrong with ====\n ( oo| him now? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ (, / \\ / \\ ,)\n //|/.\\|\\\\ / ()\\ \\\\//| | |\\\\//\n || \\_/ || _|_____|_ \\/ | | | \\/\n || |\\ /| || | | === | | | | |\n # \\_ _/ # |_| O |_| |====|\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n1\n /~\\ What\'s wrong with ====\n ( oo| him now? o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n21\n /~\\ There are several ====\n ( oo| creatures... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ ...approaching from ====\n ( oo| the southeast. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n10\n /~\\ ...approaching from ====\n ( oo| the southeast. o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n20\n /~\\ ====\n ( oo| Sand People! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n12\n /~\\ ====\n ( oo| Or worse! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n14\n /~\\ ====\n |oo ) Or worse! o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ || | | | ||\n || |\\ /| || | | === | | || | | | ||\n # \\_ _/ # |_| O |_| (\' |====| \')\n | | | || O || | || |\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____________[_]_[_]_[_]____/__][__\\____________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n10\n\n /\n |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n15\n\n Well there are two /\n Banthas down there... |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n14\n\n Well there are two /\n Banthas down there... |\n /\n\\ /~\\ ==== /\n \\ ( oo| ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n20\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} {}|~~~~~~} <__\n -- /_________||~~||___________||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n16\n\n ...but I don\'t see /\n any... wait a second! |\n /\n\\ /~\\ ==== /\n \\ ( oo| ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n11\n\n ...but I don\'t see /\n any... wait a second! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n6\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} {}|~~~~~~} <__\n -- /_________||~~||___________||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n6\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{}+ {}|~~~~~~} <__\n -- /_________||~~||___|_______||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n15\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} + {}|~~~~~~} <__\n -- /_________||~~||____|______||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n21\n\n They\'re Sand People /\n all right! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n20\n\n I can see one of /\n of them now! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} + {}|~~~~~~} <__\n -- /_________||~~||____|______||~~||_______\\\n --| |\n --| |\n | .-------. |\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| |\n -- \\__ /~~~~\\ ,, ,, /~~~~\\ __/\n --- __> {~~~~~~|{} + {}|~~~~~~} <__\n -- /_________||~~||____|______||~~||_______\\\n --| ############################ |\n --| ############################## |\n | ###########.-------.############ |\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / \\\n | |\n --| |\n --| ############################ |\n -- \\__ ############################## __/\n --- __> ################################<__\n -- /___##################################__\\\n --| #################################### |\n --| ###################################### |\n | ###############.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / ############################## \\\n | ################################ |\n --| ################################## |\n --| #################################### |\n -- \\_######################################/\n --- __>#################################<__\n -- /#######################################\\\n --|#########################################|\n --|#########################################|\n |################.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n / ######################################\\\n | ########################################|\n --|#########################################|\n --|#########################################|\n -- \\#######################################/\n --- __>#################################<__\n -- /#######################################\\\n --|#########################################|\n --|#########################################|\n |################.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n _______________________________________\n /#######################################\\\n |#########################################|\n --|#########################################|\n --|#########################################|\n -- \\#######################################/\n --- __>#################################<__\n -- /#######################################\\\n --|#########################################|\n --|#########################################|\n |################.-------.################|\n \\ _____________/ 0.120.1 \\______________/\n\n1\n\n I can see one of /\n of them now! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n\n\n /~~\\ ,\n1\n\n I can see one of /\n of them now! |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n\n /~~\\ ,\n ( o o| /(*)\n \\\'#\'_// `\n1\n\n /\n |\n /\n\\ /~\\ ==== /\n \\ |oo ) ([__])" ______/\n \\ _\\=/_ | \\-/ | /\n | _______ / _ \\ ||\\ /|| /\n \\____/~~\\ \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n ( o o| /(*)\n _ \'#\'_// `\n /\\-<=>//\n / / // \\\n1\n\n /\n |\n /\n\\ /~\\ ==== /\n \\ /~~\\ , |oo ) ([__])" ______/\n \\ ( o o| /(*) _\\=/_ | \\-/ | /\n | _\\\'#\'_//_` / _ \\ ||\\ /|| /\n \\__/\\-<=>// \\___//|/.\\|\\\\_______\\/_|_\\/_________/\n / / // \\\n \\ \\ //|\\ \\\n \\(//|| \\()\n |//==|\n1\n\n /\n /~~\\ , |\n ( o o| /(*) /\n\\ _\\\'#\'_// ` /~\\ ==== /\n \\ /\\-<=>// |oo ) o o~~ ______/\n \\ / / // \\ _\\=/_ _\\o /_ /\n | \\ \\ //|\\ \\ / _ \\ / \\ / \\ /\n \\___\\(//|| \\()__//|/.\\|\\\\______//|_|_|_\\\\_______/\n |//==|\n // ||\n // / |\n // / |\n2\n /~~\\ ,\n ( o o| /(*) /\n _\\\'#\'_// ` |\n /\\-<=>// /\n\\ / / // \\ /~\\ ==== /\n \\ \\ \\ //|\\ \\ |oo ) o o~~ ______/\n \\ \\(//|| \\() _\\=/_ _\\o /_ /\n | |//==|___ / _ \\ / \\ / \\ /\n \\___// || \\___//|/.\\|\\\\______//|_|_|_\\\\_______/\n // / |\n // / |\n ^/ |\n /________\\\n2\n /~~\\ ,\n ( o o| /(*) /\n _\\\'#\'_ // ` |\n /\\-<=> // /\n\\ | | //\\ /~\\ ==== /\n \\ \\ \\ //\\ \\ |oo ) o o~~ ______/\n \\ \\_(//| \\() _\\=/_ _\\o /_ /\n | | //=|___ / _ \\ / \\ / \\ /\n \\___|// || \\___//|/.\\|\\\\______//|_|_|_\\\\_______/\n // / |\n /// |\n .^ |\n /________\\\n8\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n3\n /~~\\ ,\n ( o o| /(*)\n _\\\'#\'_ || ` _______\n /\\-<=>\\ || / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | `V / || |====| || || |\\-/|\n________________/________\\_______/____(`_[_][_]_(\'______#_[]_[]__()\n7\n /~~\\\n ( o o| ,\n _\\\'#\'_ /(*) _______\n /\\-<=>\\ || ` / \\________________\n / / \\ \\ || /\n / / ||\\ \\ || / ==== /~\\\n /_/ | || \\(|) / x x~~ |-- )\n (\' |====| || | _\\- /_ _\\=/_\n | || || / / \\ / \\ / _ ()\n | / | || | //| | |\\\\ //|/.\\|\n |/ | || / || | | | || || \\_/\n / | || / || |====| || || |\\-/|\n________________/________\\___`V__/____(`_[_][_]_(\'______#_[]_[]__()\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|__|====\'_--+__/\n\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|_~|====\'_--+__/\n\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + ~+=_._ _______________/\n_____________|_____|______|__|====\'_--+__/\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|_~|====\'_--+__/\n\n\n8\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|_~|====\'_--+__/\n\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + +=_._ _______________/\n_____________|_____|______|__|====\'_--+__/\n ~\n\n4\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ________|\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ _______|_\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ______|__\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ _____|___\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ____|____\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ ___|_____\n / \\ + + =_._ _______________/\n_____________|_____|______|_|_====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ __|______\n / \\ + + =_._ _______________/\n_____________|_____|_____|_|__====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ _|_______\n / \\ + + =_._ _______________/\n_____________|_____|____|_|___====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____|___|_|____====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____|__|_|_____====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____|_|_|______====\'_--+__/\n ~\n\n1\n\n ARGHHHHOOOOOOO!!!\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ + + =_._ _______________/\n_____________|_____||_|_______====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\+ + =_._ _______________/\n_____________|_____|_|________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / + + =_._ _______________/\n_____________|____|_|_________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / +\\+ =_._ _______________/\n_____________|___|_|__________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / + =_._ _______________/\n_____________|____||__________====\'_--+__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / +\\ =_._ _______________/\n_____________|___|_|__________====\'_--+__/\n ~\n\n4\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/ +\n ___ |________\n / \\ =_._ _______________/\n_____________|_____|__________====\'_--+__/\n ~\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n10\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / |\n| /| | |\\ | / ==== /\n|| | | | || / x x~~ /\n(\' | | | `) | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n3\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / |\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / x x~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n2\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / x x~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n21\n ==== / ,_____________/\n ("- -) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / x x~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n8\n ==== / ,_____________/\n ("- -) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n1\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n4\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n3\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n7\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n1\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/______________________\n5\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n7\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n5\n ==== / ,_____________/\n ("o o) Hello there. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n21\n ==== / ,_____________/\n ("o o) Oh, don\'t worry... / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n15\n ==== / ,_____________/\n ("o o) ...he\'ll be alright. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ |\n / \\/ \\ / | ()\n| /| | |\\ \\ / ==== /\n|| | | | \\ \\ / - -~~ /\n(\' | | | `() | _\\- /_ /\n | | | / / \\ / \\ |\n | /| | | //| | |\\\\ |\n / || \\ / || | | | || /\n /|_|| \\ | || |====| || |\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_______________________\n25\n ==== / ,_____________/\n ("o o) ...he\'ll be alright. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / - -~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n10\n ==== / ,_____________/\n ("o o) ...he\'ll be alright. / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n10\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n16\n ==== / ,_____________/\n ("o o) Ben? / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n4\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n20\n ==== / ,_____________/\n ("o o) Ben Kenobi? / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n3\n ==== / ,_____________/\n ("o o) / /\n _\\ -/_ _______ / |\n / \\ / \\ / \\______/ | ___\n / \\/ \\ / | /() \\\n| /| | |\\ \\ / ==== / _|_____|_\n|| | | | \\ \\ / o o~~ / | | === | |\n(\' | | | `() | _\\- /_ / |_| O |_|\n | | | / / \\ / \\ | || O ||\n | /| | | //| | |\\\\ | ||__*__||\n / || \\ / || | | | || / |~ \\___/ ~|\n /|_|| \\ | || |====| || | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_____(`_[_][_]_(\'____________/_________[_]_[_]_[_]___\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n32\n\n\n Tell me, young Luke,\n what brings you\n out this far?\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n5\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n Oh, this little droid!\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n32\n\n\n He claims to be the property\n of an Obi-Wan Kenobi.\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n7\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n Obi-Wan Kenobi.\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n16\n\n\n Obi-Wan?\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n7\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n31\n\n Now that\'s a name\n I\'ve not heard\n in a long time.\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n22\n\n A long time.\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n2\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n You know him?\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n3\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n21\n\n\n Of course I know him.\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n21\n\n\n He\'s me!\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n2\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n2\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n6\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n1\n ==== ==== / ,_____________/\n ("o o) ~~o o / /\n _\\ -/_ _ _\\ -/_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | / ()\\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n7\n ==== ==== / ,_____________/\n ("o o) ~~o o / /\n _\\ -/_ _ _\\ -/_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n7\n ==== ==== / ,_____________/\n ("o o) o o~~ / /\n _\\ -/_ _ _\\- /_ / |\n / \\ / \\ / / \\ / \\_____/ | ___\n / \\/ \\ / //| | |\\\\ | /() \\\n| /| | |\\ | / \\\\| | |// / _|_____|_\n|| | | | || / \\\\ | // / | | === | |\n(\' | | | `) | )===(| / |_| O |_|\n | | | / | || | | || O ||\n | /| | | (_)(_) | ||__*__||\n / || \\ / |_||_| / |~ \\___/ ~|\n /|_|| \\ | |_||_| | /=\\ /=\\ /=\\\n_/_[_]|____\\_|_________/__][__\\____________/_________[_]_[_]_[_]___\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n20\n\n\n I think we better get indoors.\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n9\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n16\n\n\n Threepio!\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n1\n\n\n\n\n\n ______________________\n ______________ /\n___/ \\________________________/\n ___ _________\n / \\ =_._ + + _______________/\n_____________|_____|__________====\'_|_|__/\n ~\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |-- )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n5\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n16\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ I must have taken\n || | | | \\\\ |oo ) a bad step.\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n12\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ I must have taken\n || | | | \\\\ ( oo| a bad step.\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n6\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ ( oo|\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n15\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ Leave me.\n || | | | \\\\ ( oo| I\'m done for!\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n11\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\ Leave me.\n || | | | \\\\ |oo ) I\'m done for!\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n6\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n19\n ====\n What kind of ~~o o __\n talk is that! _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n7\n ====\n ~~o o __\n _\\ -/_ ___ ______/\n / \\ / \\ \\_______________________/\n //| | |\\\\\n || | | | \\\\ /~\\\n || | | | \\\\ |oo )\n \') |====| \') _\\=/_\n / | || | / _ ()\n | (_)(_) //|/.\\|\n / |_||_| || \\_/\n / |_||_| || |\\-/| __ _\n_______________/_______[_][__\\________#_[]_[]__()__|_#_____________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n21\n\n\n___\n \\\n \\____\n \\__\n \\ ________\n \\ =_._ / o o o \\__\n______________\\_______________====\'______|_________|__|_______\n \\\n |\n \\\n \\\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n4\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n13\n /~\\ ====\n ( oo| ~~o o You fought\n _\\=/_ _\\ -/_ in the clone wars?\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n9\n /~\\ ====\n ( oo| ~~o o You fought\n _\\=/_ _\\ -/_ in the clone wars?\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n3\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ () \\\\ / \\ / \\\n //|/.\\| |)\\//| | |\\\\\n || \\_/ ||\\/ | | | ||\n || |\\ /| # | | | ||\n # \\_ _/ |====| \')\n | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n10\n ====\n (o o") Yes.\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n12\n ====\n (o o") Yes.\n _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n6\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n19\n ====\n (o o") I was once\n _\\- /_ a Jedi Knight\n ___ / \\ / \\ the same as\n / ()\\ / \\/ \\ your father.\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n26\n ====\n (o o") I was once\n _\\- /_ a Jedi Knight\n ___ / \\ / \\ the same as\n /() \\ / \\/ \\ your father.\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n6\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n3\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n10\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n4\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n3\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n14\n /~\\ ====\n ( oo| ~~o o I wish I\'d\n _\\=/_ _\\ -/_ known him.\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n6\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ \\ / \\ / \\\n //|/.\\|\\\\ //| | |\\\\\n || \\_/ || || | | | ||\n || |\\ /| || || | | | ||\n # \\_ _/ # (\' |====| \')\n | | | | | || |\n | | | (_)(_)\n []|[] |_||_|\n | | | |_||_|\n_______________________/_]_[_\\______/__][__\\_______________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| ===(= | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n25\n ====\n (o o") I have\n _\\- /_ something here\n ___ / \\ / \\ for you.\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| ===(= | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n4\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| ===(= | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n |~ \\___/ ~| / || \\\n /=\\ /=\\ /=\\ / ||_|\\\n_______________[_]_[_]_[_]____________/____|[_]_\\__________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n9\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n5\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || // | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n3\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || // | | | ||\n (\' |====| \') ===(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ // | | | ||\n (\' |====| \')==(= | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n3\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ // | | | ||\n (\' |====| =)==(` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n2\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ // | | | ||\n (\' |====| =)===(` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n What is it? ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || // | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n5\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n14\n ==== ====\n ~~o o (o o") Your father\'s\n _\\ -/_ _\\- /_ lightsabre!\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n12\n ==== ====\n ~~o o (o o") Your father\'s\n _\\ o/_ _\\- /_ lightsabre!\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ o/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n ====\n ~~o o\n _\\ o/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o This is the\n _\\ o/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n4\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===***\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===******\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*********\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n7\n ====\n ~~o o This is the\n _\\ -/_ weapon of a\n / \\ / \\ Jedi Knight.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n5\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n10\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====|=)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n3\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n3\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====|=)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o Not as clumsy\n _\\ -/_ or random as\n / \\ / \\ a blaster.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n14\n ====\n ~~o o An elegant\n _\\ -/_ weapon for a\n / \\ / \\ more civilised\n //| | |\\\\ day.\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o An elegant\n _\\ -/_ weapon for a\n / \\ / \\ more civilised\n //| | |\\\\ day.\n || | | | ||\n || | | | ||\n (\' |====|=)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n5\n ====\n ~~o o An elegant\n _\\ -/_ weapon for a\n / \\ / \\ more civilised\n //| | |\\\\ day.\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n2\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*************\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===**********\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*******\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===****\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===*\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n5\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n20\n ====\n ~~o o How did my\n _\\ -/_ father die?\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n2\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o A young Jedi called\n _\\ -/_ Darth Vader, who was a\n / \\ / \\ pupil of mine until\n //| | |\\\\ he turned to evil,...\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o ...helped the Empire\n _\\ -/_ hunt down and destroy\n / \\ / \\ the Jedi Knights.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n45\n ====\n ~~o o He betrayed and\n _\\ -/_ murdered your father.\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o Vader was seduced\n _\\ -/_ by the Dark side of\n / \\ / \\ the Force.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n36\n ====\n ~~o o The Force?\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o The Force is what\n _\\ -/_ gives the Jedi\n / \\ / \\ his power.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n51\n ====\n ~~o o It\'s an energy field\n _\\ -/_ created by all\n / \\ / \\ living things.\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o It surrounds us and\n _\\ -/_ penetrates us.\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n1\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n49\n ====\n ~~o o It binds the galaxy\n _\\ -/_ together.\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n6\n ====\n ~~o o\n _\\ -/_\n / \\ / \\\n //| | |\\\\\n || | | | ||\n || | | | ||\n (\' |====| =)===\n | || |\n (_)(_)\n |_||_|\n |_||_|\n__________________/__][__\\_________________________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n9\n Now let\'s see if we ====\n can\'t figure out what (o o")\n you are. _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n21\n Now let\'s see if we ====\n can\'t figure out what (o o")\n you are. _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n2\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n / ()\\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n2\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n9\n ====\n I saw part (o o")\n of the message... _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n | | === | | || | | | ||\n |_| O |_| (\' | | | `)\n || O || | | |\n ||__*__|| | |\\ |\n ------- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n11\n ====\n I saw part (o o")\n of the message... _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n ,@ | | === | | || | | | ||\n /=- |_| O |_| (\' | | | `)\n || || O || | | |\n || ||__*__|| | |\\ |\n --~~--- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n30\n I seem to have ====\n found it! (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n ,@ | | === | | || | | | ||\n /=- |_| O |_| (\' | | | `)\n || || O || | | |\n || ||__*__|| | |\\ |\n --~~--- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n4\n ====\n (o o")\n _\\- /_\n ___ / \\ / \\\n /() \\ / \\/ \\\n _|_____|_ | /| | |\\ |\n ,@ | | === | | || | | | ||\n /=- |_| O |_| (\' | | | `)\n || || O || | | |\n || ||__*__|| | |\\ |\n --~~--- |~ \\___/ ~| / || \\\n || || /=\\ /=\\ /=\\ / ||_|\\\n______________||___||______[_]_[_]_[_]_______/____|[_]_\\___________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n69\n\n General Kenobi. Years ago you\n served my father in the Clone\n wars. Now he begs you to help\n him in his struggle against\n the Empire.\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n59\n\n I have placed information vital\n to the survival of the Rebellion\n into the memory systems of this\n R2 unit.\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n55\n\n You must see this droid safely\n delivered to him on Alderaan.\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n36\n\n Help me Obi-Wan Kenobi!\n You\'re my only hope!\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n5\n\n\n\n\n\n\n ,@\n /=-\n ||\n ||\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ||\n ~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n /=-\n ~~\n ~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ,@\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n1\n\n\n\n\n\n\n ~~\n ~~~\n ~~\n ~~~\n --~~---\n || ||\n______________||___||______________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n -------\n || ||\n______________||___||______________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n28\n ==== ====\n ~~o o (o o") You must learn\n _\\ -/_ _\\- /_ the ways of the\n / \\ / \\ / \\ / \\ Force...\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n40\n ==== ====\n ~~o o (o o") ...if you are\n _\\ -/_ _\\- /_ to come with me\n / \\ / \\ / \\ / \\ to Alderaan.\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || / /| | |\\ |\n || | | | || || | | | ||\n (\' |====| =)=== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n . .\n . . .\n . . .\n. . .\n . . . .\n . .\n . . .\n . . .\n . .\n . . . .\n . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . .\n . . . .\n . .\n . . .\n . . .\n . .\n . . . .\n . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . .\n . . . .\n . .\n . . .\n . . .\n . .\n . . . .\n . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . .\n . . . .\n . .\n . . .\n . .\n . .\n . . . .\n. . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n. . . .\n . . . .\n . .\n . . .\n . .\n . .\n . . . .\n . . .\n . . . .\n . . .\n2\n . .\n . . .\n . .\n . . . .\n . . . .\n: . .\n| . . .\n| . .\n: . .\n . . . .\n . . .\n. . . . .\n . . .\n2\n .\n . . .\n . .\n . . . .\n\\ . . .\n.: . .\n_| . . .\n.| . .\n : . .\n/ . . . .\n . . .\n . . . .\n . . .\n2\n .\n . . .\n . .\n\\ . . . .\n:\\ . . .\n..: . .\n__| . . .\n..| . .\n: : . .\n./ . . . .\n/ . . .\n . . . .\n . . .\n2\n .\n . . .\n\\ . .\n.\\ . . . .\n :\\ . . .\n...: . .\n___| . . .\n...| . .\n : : . .\n../ . . . .\n / . . .\n/ . . . .\n . . .\n2\n .\n. . . .\n.\\ . .\n .\\ . . . .\n| :\\ . . .\n....: . .\n____| . . .\n....| . .\n : : . .\n.../ . . .\n / . . .\n./ . . . .\n . . .\n2\n .\n-. . . .\n .\\ . .\n\\ .\\ . . . .\n | :\\ . . .\n/....: . .\n_____| . . .\n.....| . .\n : : . .\n..../ . . .\n. / . . .\n_./ . . . .\n . . .\n2\n .\n\'-. . . .\n_ .\\ . .\n \\ .\\ . . . .\n) | :\\ . . .\n_/....: .\n______| . . .\n......| . .\n: : : . .\n...../ . . .\n . / . . .\n._./ . . . .\n- . . .\n2\n_ .\n.\'-. . . .\n__ .\\ . .\n \\ .\\ . . . .\n() | :\\ . . .\n__/....: .\n_______| . . .\n.......| . .\n : : : . .\n....../ . . .\n . / . . .\n.._./ . . . .\n.- . . .\n2\n__ .\n..\'-. . . .\n.__ .\\ . .\n/ \\ .\\ . . . .\n () | :\\ . . .\n\\__/....: .\n________| . . .\n........| . .\n : : : . .\n......./ . . .\n. . / . . .\n..._./ . . .\n..- . . .\n2\n-__ .\n...\'-. . . .\n .__ .\\ . .\n./ \\ .\\ . . . .\n| () | :\\ . . .\n.\\__/....: .\n_________| . . .\n.........| . .\n : : : . .\n......../ . . .\n . . / . . .\n...._./ . . .\n_..- . . .\n2\n--__ .\n:...\'-. . . .\n: .__ .\\ .\n../ \\ .\\ . . . .\n:| () | :\\ . . .\n..\\__/....: .\n__________| . . .\n..........| . .\n: : : : . .\n........./ . . .\n: . . / . . .\n....._./ . . .\n__..- . . .\n2\n---__ .\n.:...\'-. . . .\n : .__ .\\ .\n.../ \\ .\\ . . . .\n :| () | :\\ . . .\n...\\__/....: .\n___________| . . .\n...........| . .\n : : : : . .\n........../ . . .\n : . . / . . .\n......_./ . . .\n___..- . . .\n2\n_---__ .\n..:...\'-. . . .\n. : .__ .\\ .\n..../ \\ .\\ . . . .\n :| () | :\\ . . .\n....\\__/....: .\n____________| . . .\n............| .\n : : : : . .\n.........../ . . .\n. : . . / . . .\n......._./ . . .\n.___..- . . .\n2\n__---__ .\n...:...\'-. . . .\n . : .__ .\\ .\n...../ \\ .\\ . . . .\n :| () | :\\ . . .\n.....\\__/....: .\n_____________| . . .\n.............| .\n : : : : . .\n............/ . . .\n . : . . / . . .\n........_./ . . .\n..___..- . . .\n2\n __---__ .\n\'...:...\'-. . . .\n . : .__ .\\ .\n....../ \\ .\\ . . . .\n: :| () | :\\ . .\n......\\__/....: .\n______________| . . .\n..............| .\n: : : : : . .\n............./ . . .\n . : . . / . . .\n........._./ . . .\n-..___..- . .\n2\n __---__ .\n-\'...:...\'-. . .\n. . : .__ .\\ .\n......./ \\ .\\ . . . .\n : :| () | :\\ . .\n.......\\__/....: .\n_______________| . . .\n...............| .\n : : : : : . .\n............../ . . .\n. . : . . / . . .\n_........._./ . . .\n -..___..- . .\n2\n __---__ .\n.-\'...:...\'-. . .\n . . : .__ .\\ .\n......../ \\ .\\ . . . .\n : :| () | :\\ . .\n........\\__/....: .\n________________| . . .\n................| .\n : : : : : . .\n.............../ . . .\n . . : . . / . . .\n._........._./ . . .\n -..___..- . .\n2\n __---__ .\n .-\'...:...\'-. . .\n/ . . : .__ .\\ .\n........./ \\ .\\ . . . .\n: : :| () | :\\ . .\n.........\\__/....: .\n_________________| . . .\n.................| .\n: : : : : : . .\n................/ . . .\n . . : . . / . . .\n\\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n .-\'...:...\'-. . .\n / . . : .__ .\\ .\n/........./ \\ .\\ . . . .\n : : :| () | :\\ . .\n..........\\__/....: .\n__________________| . . .\n..................| .\n : : : : : : . .\n................./ . . .\n\\ . . : . . / . . .\n \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . . .\n/ : : :| () | :\\ . .\n...........\\__/....: .\n___________________| . . .\n...................| .\n : : : : : : . .\n\\................./ . .\n \\ . . : . . / . . .\n \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n. .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . . .\n / : : :| () | :\\ . .\n:...........\\__/....: .\n|___________________| . . .\n|...................| .\n: : : : : : : . .\n \\................./ . .\n \\ . . : . . / . . .\n \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . . .\n |...................| .\n : : : : : : : . .\n \\................./ . .\n \\ . . : . . / . . .\n. \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n. \\................./ . .\n \\ . . : . . / . . .\n . \\._........._./ . . .\n -..___..- . .\n2\n __---__ .\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . . .\n . \\._........._./ . . .\n -..___..- . .\n2\n. __---__\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n. /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n2\n . __---__\n . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n2\n . __---__\n. . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n |___________________| . .\n |...................| .\n. : : : : : : : . .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n2\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\ .\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n. |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n . \\._........._./ . . .\n -..___..- . .\n12\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n39\n This station is now /~~\\\n the ultimate power |<><>|\n in the universe. /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n31\n I suggest /~~\\\n we use it! |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n29\n The ability to destroy /~~\\\n a planet is insignificant... |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n4\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n13\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o | o o //|[ ] \\\\\n _\\ -/_ _\\ -/_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n10\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n11\n ...next to the power /~~\\\n of the Force! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n9\n Don\'t try to frighten /~~\\\n us with your sorcerer\'s |<><>|\n ways, Lord Vader... /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n21\n Don\'t try to frighten /~~\\\n us with your sorcerer\'s |<><>|\n ways, Lord Vader... /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n10\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( O O o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - | o o \\\\//|[ ] \\\\\n _\\ o/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ | |//\n | | :: \\ | | ::: | |====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - | o o \\\\//|[ ] \\\\\n _\\ o/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - | o o \\\\//|[ ] \\\\\n _\\ o/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n8\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n5\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( - - o o | \\\\//|[ ] \\\\\n _\\ o/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n11\n /~~\\\n Ugh!!! Ackkkk!!! |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n23\n I find your lack of /~~\\\n faith disturbing. |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( x x | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n16\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ Vader, ==== # /\\___/\\\n ( x x release him! | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n7\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ Vader, ==== # /\\___/\\\n ( o o release him! | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n10\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ Vader, ==== # /\\___/\\\n ( o o release him! | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n1\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o | o o \\\\//|[ ] \\\\\n _\\ -/_ _\\ -/_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n10\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== # /\\___/\\\n ( o o o o | \\\\//|[ ] \\\\\n _\\ -/_ _\\- /_ \\/ |[_] |\\\\\n /"\'() ") /"\'==\'"\\ | |//\n | | \\\\// | | ::: | |====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n1\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'() ") /"\'==\'"\\ \\\\ | |//\n | | \\\\// | | ::: | \\#|====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n3\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ o/_ _\\- /_ // |[_] |\\\\\n /"\'() ") /"\'==\'"\\ \\\\ | |//\n | | \\\\// | | ::: | \\#|====#/\n || | \\/| || | || /|\\ /I\\\n-------------------------------------------------------------------\n\n\n\n4\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ o/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n11\n As you wish. /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n6\n /~~\\\n |<><>|\n /_/\\_\\\n /""\\ ==== /\\___/\\\n ( o o o o | //|[ ] \\\\\n _\\ -/_ _\\- /_ // |[_] |\\\\\n /"\'--\'"\\ /"\'==\'"\\ \\\\ | |//\n | | :: \\ | | ::: | \\#|====#/\n || | |\\\\ || | || /|\\ /I\\\n---------------\\()-------------------------------------------------\n\n\n\n13\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) o o~~ | | | *| .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) o o~~ | | | *| .##\n _\\ -/_ _\\- /_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) o o~~ | | | * .##\n _\\ -/_ _\\- /_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) o o~~ | | | * .##\n _\\ -/_ _\\- /_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) o o~~ | | | *| .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) o o~~ | | | * | .##\n _\\ -/_ _\\- /_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | * ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / \\* ###\n ("o o) ~~o o | | | *| .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | *| ####\n / \\ / \\ / \\/ \\ \\ \\ \\_____* \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / *\\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ **\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\____*/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\___*_/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n1\n ==== ==== / / / * \\ ###\n ("o o) ~~o o | | | * | .##\n _\\ -/_ _\\ -/_ | | | * | ####\n / \\ / \\ / \\/ \\ \\ \\ \\__*__/ \'\'#\n / \\/ \\ //| | |\\\\ | \\ \\ *\n| /| | |\\ \\ || | | | || | |\\ \\ *\n|| | | | \\ \\ || | | | || | | \\ \\ .## _____\n(\' | | | `() (\' |====| \') ~ \\ \\ ####. / \\\n | | | | || | \\ \\ .### | |\n | /| | (_)(_) \\ \\ | ..|\n / || \\ |_||_| \\ \\ \\____##\n /|_|| \\ |_||_| _____\\_\\_____________\n-/_[_]|____\\-----------/__][__\\---------------\\____________________\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n29\n\n It looks like the\n Sand People did this.\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n29\n\n They didn\'t. But we are\n meant to think they did.\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n28\n\n Only Imperial stormtroopers\n are so precise.\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n30\n\n If they traced the\n robots here that would\n lead them...\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n15\n\n\n ...home!\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n2\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_________|_|____ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= ++ |______#_/\n____________\'====_________||_____ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + |______#_/\n____________\'====_________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= ++ |______#_/\n____________\'====________||______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_______|_|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====______|__|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_____|___|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====____|____|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====___|_____|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====__|______|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._= + + |______#_/\n____________\'====_|_______|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _._=+ + |______#_/\n____________\'====|________|______ooo__ooo__________________________\n\n16\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n____________\'====_________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n___________\'====__________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n__________\'====___________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n_________\'====____________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n________\'====_____________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n______\'====_______________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n____\'====_________________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n__\'====___________________|______ooo__ooo__________________________\n\n1\n\n Luke! It\'s too dangerous!\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n _+_= + |______#_/\n\'====_____________________|______ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n+_= + |______#_/\n===_______________________|______ooo__ooo__________________________\n\n1\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n= + |______#_/\n=_________________________|______ooo__ooo__________________________\n\n8\n\n\n\n\n\n\n ___________\n | _ =|\n | [_] /\n | # /\n + |______#_/\n__________________________|______ooo__ooo__________________________\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n_____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n __/ o\\*/o o \\ .||.\n\'____________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n+_ __/ o\\*/o o \\ .||.\n==\'__________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n=_+_ __/ o\\*/o o \\ .||.\n====\'________________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n__====\'______________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n____====\'____________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n______====\'__________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_______====\'_________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n________====\'________________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________====\'_______________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n__________====\'______________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n___________====\'_____________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n____________====\'____________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_____________====\'___________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n______________====\'__________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_______________====\'_________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n________________====\'________________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________====\'_______________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n__________________====\'______________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n___________________====\'_____________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n____________________====\'____________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_____________________====\'___________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n______________________====\'__________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_______________________====\'_________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n________________________====\'________________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n1\n *\n **\n ***\n *****\n *******\n *****\n *****\n ***\n **\n __ * ____ .|\\.\n =_+_ __/ o\\*/o o \\ .||.\n_________________________====\'_______________|__|__________|__|[]|_\n\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n2\n *\n *\n *\n *\n *\n * *\n * *\n * *\n * *\n # # * ___\n ## ## ## / |\n ############# # # / |\n_______####_#######__####_/ |\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . |\n . : : : : : : : . |\n . \\................./ . . |\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . ./\n |...................| . |\n . : : : : : : : . |-\n . \\................./ . . |\n \\ . . : . . / . . \\\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . _\n . |___________________| . /\n |...................| . | \\\n . : : : : : : : . |-{\n . \\................./ . . | /\n \\ . . : . . / . . \\_\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . __\n . |___________________| . /\n |...................| . | \\_\n . : : : : : : : . |-{\n . \\................./ . . | /~\n \\ . . : . . / . .\\__\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . /\n |...................| . | \\_/\n . : : : : : : : . |-{ }\n . \\................./ . . | /~\\\n \\ . . : . . / . \\___\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\\n |...................| . | \\_/\n . : : : : : : : . |-{ }-\n . \\................./ . . | /~\\\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\.\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : . |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/.\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : .|-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . ___\n . |___________________| . / \\ .\n |...................| . | \\_/ |\n . : : : : : : : |-{ }-|\n . \\................./ . . | /~\\ |\n \\ . . : . . / . \\___/ .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . __\n . |___________________| . / \\ .\n |...................| . |_\\/_|\n . : : : : : : : | /\\ |\n . \\................./ . . \\__/\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: . __\n . |___________________| . / \\ .\n |...................| . |_\\/_|\n . : : : : : : : | /\\ |\n . \\................./ . . \\__/\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . -- .\n |...................| . |\\/|\n . : : : : : : : |/\\| .\n . \\................./ . . --\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . -- .\n |...................| . |\\/|\n . : : : : : : : |/\\| .\n . \\................./ . . --\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . []\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . []\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . "\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . "\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| . \'\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\'\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \'\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \'.\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| \' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n1\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................|\' .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n5\n . __---__\n . . .-\'...:...\'-. . .\n / . . : .__ .\\\n . /........./ \\ .\\ . . .\n / : : :| () | :\\ . .\n :...........\\__/....: .\n . |___________________| . .\n |...................| .\n . : : : : : : : .\n . \\................./ . .\n \\ . . : . . / . .\n. . \\._........._./ . . .\n -..___..- . .\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~\\\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n16\n / \\ ===,\n And now your | | @o o@)\n highness... | | \\- /\n | | /~~ ~\\\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n And now your | | @o o@)\n highness... | | \\- /\n | | /~~ ~\\\\\n | \'| / ( ) \\\n | =| /_/\\ /\\_|\n | \'| \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n And now your | | @o o@)\n highness... | | \\- /\n | /| /~~ ~\\\\\n | \'-| / ( ) \\\n | ==| /_/\\ /\\_|\n | \' | \\\\ \\ // ||\n | \\| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | | \\- /\n your hidden | / | /~~ ~\\\\\n Rebel base. | \'--| / ( ) \\\n | ===| /_/\\ /\\_|\n | \' o| \\\\ \\ // ||\n | \\ | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | _| \\- /\n your hidden | / | /~~ ~\\\\\n Rebel base. | \'--|| / ( ) \\\n | ====| /_/\\ /\\_|\n | \' o | \\\\ \\ // ||\n | \\ _| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __| \\- /\n your hidden | / _| /~~ ~\\\\\n Rebel base. | \'--| | / ( ) \\\n | =====| /_/\\ /\\_|\n | \' o | \\\\ \\ // ||\n | \\ __| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\- /\n your hidden | / __| /~~ ~\\\\\n Rebel base. | \'--| "| / ( ) \\\n | ======| /_/\\ /\\_|\n | \' o || \\\\ \\ // ||\n | \\ __ | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\- /\n your hidden | / __\\| /~~ ~\\\\\n Rebel base. | \'--| ""| / ( ) \\\n | =======| /_/\\ /\\_|\n | \' o |_| \\\\ \\ // ||\n | \\ __ /| @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\'| / ( ) \\\n | ========| /_/\\ /\\_|\n | \' o |_\'| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=-| \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n2\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n1\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=* | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n1\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== * | /_/\\ /\\_|\n | \' o |_\'+***| \\\\ \\ // ||\n | \\ __ / * | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n1\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=* | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n17\n / \\ ===,\n...we will discuss | | @o o@)\n the location of | __ | \\o /\n your hidden | / __\\ | /~~ ~\\\\\n Rebel base. | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n3\n / \\ ===,\n | | @o o@)\n | __ | \\o /\n | / __\\ | /~~ ~\\\\\n | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n6\n / \\ ===,\n | | @o o@)\n | __ | \\- /\n | / __\\ | /~~ ~\\\\\n | \'--| ""\' | / ( ) \\\n | ======== | /_/\\ /\\_|\n | \' o |_\'+=- | \\\\ \\ // ||\n | \\ __ / | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n_________________________|_____________|________/__)(_)____________\n15\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n + |______#_/ . +\n__________________________|______ooo__ooo_____<^"..|_|_____________\n ~~\'`\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n + |______#_/ . +\n__________________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n + |______#_/ . +\n\'_________________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n+_ + |______#_/ . +\n==\'_______________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n=_+_ + |______#_/ . +\n====\'_____________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n__====\'___________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n____====\'_________________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n______====\'_______________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_______====\'______________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n________====\'_____________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_________====\'____________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n__________====\'___________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n___________====\'__________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n____________====\'_________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_____________====\'________|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n______________====\'_______|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n_______________====\'______|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n________________====\'_____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_+_ + |______#_/ . +\n________________====\'_____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'|____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'|____|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'_|___|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'_|___|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to come with\n you to Alderaan.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n There is nothing for\n me here now.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n I want to learn the\n ways of the Force...\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n1\n\n ...and become a Jedi\n like my father.\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n3\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n2\n\n\n\n\n\n\n ___________\n | _ =| .\n | [_] / .\n | # / .\n =_._ + + |______#_/ . +\n________________====\'__|__|______ooo__ooo_____<^"._|_|_____________\n ~~\'\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n25\n\n\n\n =_._ + + Mos Eisley Spaceport.\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n1\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n36\n\n\n You will never find a\n =_._ + + more wretched hive of\n______________====\'___|_|_ scum and villainy.\n \\\n |\n /\n /\n |\n |\n |\n |\n1\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n26\n\n\n\n =_._ + + We must be cautious.\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n4\n\n\n\n =_._ + +\n______________====\'___|_|_\n \\\n |\n /\n /\n |\n |\n |\n |\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n\'___/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n_ |~~| | | o o o o | | O O O O |__ o o| o o\n=\'__/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n+_ |~~| | | o o o o | | O O O O |__ o o| o o\n==\'_/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n_+_ |~~| | | o o o o | | O O O O |__ o o| o o\n===\'/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n=_+_ |~~| | | o o o o | | O O O O |__ o o| o o\n====/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =_+_|~~| | | o o o o | | O O O O |__ o o| o o\n_===/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =_+|~~| | | o o o o | | O O O O |__ o o| o o\n__==/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =_|~~| | | o o o o | | O O O O |__ o o| o o\n___=/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n =|~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|_ | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\\'|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|+_| | o o o o | | O O O O |__ o o| o o\n____/|[]|\\=\'___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|_+_ | o o o o | | O O O O |__ o o| o o\n____/|[]|\\==\'__|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~|=_+_ | o o o o | | O O O O |__ o o| o o\n____/|[]|\\===\'_|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| =_+_ | o o o o | | O O O O |__ o o| o o\n____/|[]|\\====\'|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| =_+_| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_====|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| |=_+| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|===|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | =_| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|_==|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | =| o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|__=|_________|_____|___________|__|____________|_||____\n7\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|\'____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|=\'___|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |+_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|==\'__|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |_+_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|===\'_|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o |=_+_ | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|====\'|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =_+_| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_====|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =_+| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|__===|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =_| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|___==|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | =| O O O O |__ o o| o o\n____/|[]|\\_|___|_________|____=|___________|__|____________|_||____\n12\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|\'___________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |=_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|=\'__________|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |_=_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|==\'_________|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__=_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|===\'________|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|====\'_______|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|_====\'______|_||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|__====\'_____|_||____\n7\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n Let me see your\n identification.\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n26\n\n\n\n\n\n You don\'t need to\n see his identification.\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n We don\'t need to see his\n identification.\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n\n\n\n These aren\'t the\n droids you\'re looking for.\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n These aren\'t the droids\n we\'re looking for.\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n26\n\n\n\n\n\n Move along.\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n25\n\n\n Move along! Move along!\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'____|_||____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o | o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'_____|_|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ o| o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'______||____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|___====\'_______|____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|____====\'______|____\n2\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_____====\'_____|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|______====\'____|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_______====\'___|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|________====\'__|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_________====\'_|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_ | o o\n____/|[]|\\_|___|_________|_____|___________|__|__________====\'|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+_| o o\n____/|[]|\\_|___|_________|_____|___________|__|___________====|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_+| o o\n____/|[]|\\_|___|_________|_____|___________|__|____________===|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =_| o o\n____/|[]|\\_|___|_________|_____|___________|__|_____________==|____\n1\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ =| o o\n____/|[]|\\_|___|_________|_____|___________|__|______________=|____\n5\n\n\n\n\n\n\n\n\n\n { ........ ....... ....\n | | \\.. ./ \\. |\n |~~| | | o o o o | | O O O O |__ | o o\n____/|[]|\\_|___|_________|_____|___________|__|_______________|____\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n29\n ==== ====\nI can\'t understand ~~o o (o o")\n how we got by _\\ -/_ _\\- /_\n those troops. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n2\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n8\n ==== ====\n ~~o o (o o") The Force can\n _\\ -/_ _\\- /_ have a strong\n / \\ / \\ / \\ / \\ influence...\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n17\n ==== ====\n ~~o o (o o") The Force can\n _\\ -/_ _\\- /_ have a strong\n / \\ / \\ / \\ / \\ influence...\n //| | |\\\\ / \\/ \\\n \\\\| | | || | /| | |\\ |\n \\\\ | | || || | | | ||\n )====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n19\n ==== ====\n ~~o o (o o") ...on the\n _\\ -/_ _\\- /_ weak minded.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | || | /| | |\\ |\n \\\\ | | || || | | | ||\n )====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n7\n ==== ====\n ~~o o (o o") ...on the\n _\\ -/_ _\\- /_ weak minded.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n29\n ==== ====\n Do you really ~~o o (o o")\n think we\'re _\\ -/_ _\\- /_\n going to find... / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n8\n ==== ====\n ...a pilot here ~~o o (o o")\n to take us to _\\ -/_ _\\- /_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | || | /| | |\\ |\n || | | | || || | | | ||\n (\' |====I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ...a pilot here ~~o o (o o")\n to take us to _\\ -/_ _\\- /_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | || | /| | |\\ |\n \\\\ | | || || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n8\n ==== ====\n ...a pilot here ~~o o (o o")\n to take us to _\\ -/_ _\\- /_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | \\\\ | /| | |\\ |\n \\\\ | | \\\\ || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n20\n ==== ====\n ...a pilot here ~~o o ("o o)\n to take us to _\\ -/_ _\\ -/_\n Alderaan. / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | \\\\ | /| | |\\ |\n \\\\ | | \\\\ || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n3\n ==== ====\n ~~o o ("o o)\n _\\ -/_ _\\ -/_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | | \\\\ | /| | |\\ |\n \\\\ | | \\\\ || | | | ||\n \')===I \') ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ~~o o ("o o)\n _\\ -/_ _\\ -/_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n32\n ==== ====\n ~~o o ("o o) Most of the best\n _\\ -/_ _\\ -/_ freighter pilots\n / \\ / \\ / \\ / \\ can be found here.\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n6\n ==== ====\n ~~o o (o o") Most of the best\n _\\ -/_ _\\- /_ freighter pilots\n / \\ / \\ / \\ / \\ can be found here.\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n1\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n31\n ==== ====\n ~~o o (o o") Only watch your\n _\\ -/_ _\\- /_ step.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n34\n ==== ====\n ~~o o (o o") This place can\n _\\ -/_ _\\- /_ be a little rough.\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n ==== ====\n ~~o o (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n \\\\| | |// | /| | |\\ |\n \\\\ | // || | | | ||\n \')===) ( | | | `)\n | || I | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n____________________/__][__\\________/____|[_]_\\____________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n == // | |\\\\ / === \\\n || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n == // | |\\\\ / === \\\n {\\---/} || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n {\\---/} == // | |\\\\ / === \\\n {<><> } || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { . . }\n \\ / | |\n {\\---/} /-===-\\ _\\!^!/_\n {<><> } == // | |\\\\ / === \\\n \\ - / || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n7\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n {<><> } /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n1\n / _\\ /\\_/\\\n | (__) { }\n {\\---/} \\ / | |\n {<><> } /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n {<><> } /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n6\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n.---------------. \\\\ | | \\\\ .--//---|_|------.\n\'-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n__|___________|______[_][__]______|_____________|__________________\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n---------------. \\\\ | | \\\\ .--//---|_|------.\n-. .-\' =\\)=== () \'- {} .-\'\n | | | || | | |\n | | ( )| ) | |\n | | | || | | |\n | | | || | | |\n_|___________|______[_][__]______|_____________|___________________\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n--------------. \\\\ | | \\\\ .--//---|_|------.\n. .-\' =\\)=== () \'- {} .-\'\n| | | || | | |\n| | ( )| ) | |\n| | | || | | |\n| | | || | | |\n|___________|______[_][__]______|_____________|___________________/\n2\n / _\\ /\\_/\\\n | (__) { . . }\n {\\---/} \\ / | |\n { <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | ||\n-------------. \\\\ | | \\\\ .--//---|_|------. (\n .-\' =\\)=== () \'- {} .-\'\n | | || | | |\n | ( )| ) | | (\n | | || | | | |\n | | || | | | |\n___________|______[_][__]______|_____________|___________________/_\n2\n / _\\ /\\_/\\\n | (__) { . . }\n{\\---/} \\ / | |\n{ <><>} /-===-\\ _\\!^!/_\n \\ - / == // | |\\\\ / === \\\n | | || \\\\ | | \\\\ //| | | || /\n------------. \\\\ | | \\\\ .--//---|_|------. (\n .-\' =\\)=== () \'- {} .-\' \\\n | | || | | | -\n | ( )| ) | | (\n | | || | | | |_\n | | || | | | |\n__________|______[_][__]______|_____________|___________________/__\n2\n / _\\ /\\_/\\\n | (__) { . . }\n\\---/} \\ / | |\n<><> } /-===-\\ _\\!^!/_\n\\ - / == // | |\\\\ / === \\ _\n | | || \\\\ | | \\\\ //| | | || //\n-----------. \\\\ | | \\\\ .--//---|_|------. (\n .-\' =\\)=== () \'- {} .-\' \\\n | | || | | | -=\n | ( )| ) | | (\n | | || | | | |__\n | | || | | | |\n_________|______[_][__]______|_____________|___________________/___\n2\n / _\\ /\\_/\\\n | (__) { . . }\n---/} \\ / | |\n><> } /-===-\\ _\\!^!/_\n - / == // | |\\\\ / === \\ __\n| | || \\\\ | |// //| | | || //\\\n----------. \\\\ | // .--//---|_|------. (\n .-\' =\\)==) \'- {} .-\' \\\n | | || | | | -==\n | ( )| ) | | ( _\n | | || | | | |___\n | | || | | | |\n________|______[_][__]______|_____________|___________________/____\n2\n / _\\ /\\_/\\\n | (__) { }\n--/} \\ / | |\n<> } /-===-\\ _\\!^!/_\n- / == // | |\\\\ / === \\ __\n | || \\\\ | |// //| | | || //\\\\\n---------. \\\\ | // .--//---|_|------. ( O\n .-\' =\\)==) \'- {} .-\' \\ /\n | | || | | | -==-\n | ( )| ) | | ( __\n | | || | | | |____\n | | || | | | |\n_______|______[_][__]______|_____________|___________________/_____\n2\n / __\\ /\\_/\\\n | (___) { . . }\n-/} \\ / | |\n> } /-===-\\ _\\!^!/_\n / == // | |\\\\ / === \\ __\n| || \\\\ | |// //| | | || //\\\\\n--------. \\\\ | // .--//---|_|------. ( O!\n .-\' =\\)==) \'- {} .-\' \\ /\'\n | | || | | | -==-/\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n______|______[_][__]______|_____________|___________________/______\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n/} \\ / | |\n } /-===-\\ _\\!^!/_\n/ == // | |\\\\ / === \\ __\n || \\\\ | |// //| | | || //\\\\\n-------. \\\\ | // .--//---|_|------. ( O!\n .-\' =\\)==) \'- {} .-\' \\ /\'/\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n_____|______[_][__]______|_____________|___________________/______\\\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n} \\ / | |\n} /-===-\\ _\\!^!/_\n == // | |\\\\ ( === \\ __\n || \\\\ | |// \\\\/{ } || //\\\\\n------. \\\\ | // .-----\\/|_|------. ( O!\n .-\' =\\)==) \'- .-\' \\ /\'/(\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n____|______[_][__]______|_____________|___________________/______\\_\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n \\ / | |\n /-===-\\ _\\===/_\n == // | |\\\\ ( { } \\ __\n || \\\\ | |// \\\\//_| || //\\\\\n-----. \\\\ | // .-----\\/---------. ( O!\n .-\' =\\)==) \'- .-\' \\ /\'/()\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n___|______[_][__]______|_____________|___________________/______\\__\n2\n /___\\ /\\_/\\\n |(___)| { . . }\n \\ / | |\n /-===-\\ _\\===/_\n== // | |\\\\ ( { } \\ __\n|| \\\\ | |// \\\\//_| || //\\\\\n----. \\\\ | // .-----\\/---------. ( O! .\n .-\' =\\)==) \'- .-\' \\ /\'/()\'\n | | || | | | -==-//\n | ( )| ) | | ( __/\n | | || | | | |____|\n | | || | | | | |\n__|______[_][__]______|_____________|___________________/______\\___\n2\n / __\\ /\\_/\\\n | (___| { }\n \\ / | |\n /-===-\\ _\\===/_\n= // | |\\\\ ( { } \\ __\n| \\\\ | |// \\\\//_| || //\\\\\n---. \\\\ | // .-----\\/---------. ( O! .-\n .-\' =\\)==) \'- .-\' \\ /\'/()\'-\n | | || | | | -==-// |\n | ( )| ) | | ( __/ |\n | | || | | | |____| |\n | | || | | | | | |\n_|______[_][__]______|_____________|___________________/______\\___|\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\===/_\n // | |\\\\ ( { } \\ __\n \\\\ | |// \\\\//_| || //\\\\\n--. \\\\ | // .-----\\/---------. ( O! .--\n.-\' =\\)==) \'- .-\' \\ /\'/()\'--\n| | || | | | -==-// |\n| ( )| ) | | ( __/ |\n| | || | | | |____| |\n| | || | | | | | |\n|______[_][__]______|_____________|___________________/______\\___|_\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __\n \\\\ | |// \\\\/{ } || //\\\\\n-. \\\\ | // .-----\\/|_|------. ( O! .---\n-\' =\\)==) \'- .-\' \\ /\'/()\'---\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n______[_][__]______|_____________|___________________/______\\___|__\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __\n \\\\ | |// \\\\/{ } || //\\\\\n. \\\\ | // .-----\\/|_|------. ( O! .----\n\' =\\)==) \'- .-\' \\ /\'/()\'----\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n_____[_][__]______|_____________|___________________/______\\___|___\n2\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __\n \\\\ | |// \\\\ | | || //\\\\\n \\\\ | // .-----\\\\|_|------. ( O! .-----\n =\\)==) \'- \\{} .-\' \\ /\'/()\'-----\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n____[_][__]______|_____________|___________________/______\\___|____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ =\n \\\\ | |// \\\\ | | || //\\\\ (\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ (|\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==/\n \\\\ | |// \\\\ | | || //\\\\ (|/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { }\n \\ / | |\n /-===-\\ _\\!^!/_ /\n // | |\\\\ ( === \\ __ ==//\n \\\\ | |// \\\\ | | || //\\\\ (|/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | | /\n /-===-\\ _\\!^!/_ //\n // | |\\\\ ( === \\ __ ==//\n \\\\ | |// \\\\ | | || //\\\\ (|/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_ /\n // | |\\\\ ( === \\ __ == //\n \\\\ | |// \\\\ | | || //\\\\ ||)/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ == /\n \\\\ | |// \\\\ | | || //\\\\ ||()/\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ || ()\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ || (\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n4\n / _\\ /\\_/\\\n | (__| { . . }\n \\ / | |\n /-===-\\ _\\!^!/_\n // | |\\\\ ( === \\ __ ==\n \\\\ | |// \\\\ | | || //\\\\ ||\n \\\\ | // .-----\\\\|_|------. ( O! .------\n =\\)==) \'- \\{} .-\' \\ /\'/()\'------\n | || | | | -==-// |\n ( )| ) | | ( __/ |\n | || | | | |____| |\n | || | | | | | |\n___[_][__]______|_____________|___________________/______\\___|_____\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()____() |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n1\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | ()____()| \\(I)/|\n ===>__/ (:::::::) ==I===\n | || | .=======. | I| |\n | || | |_|| ||_| | || |\n |_||_| [ ]| |[ ] |_||_|\n___________[_][__\\__________---------_________/__][__\\_____________\n2\n / \\ / \\\n ( ) ___ ( )\n (O O) / \\ (O O)\n (/=\\) ( ) (/=\\)\n // I \\ (O O) // I \\\\\n || I/~\\| (/^\\) || I ||\n \\\\ > # ) //---\\\\ \\\\ I //\n |\\(> O | |()___()| |\\(I)/\n ===>__/ (:::::::) ===I==\n | || | .=======. | |I |\n | || | |_|| ||_| | || |\n |_||_|_ [ ]| |[ ] |_||_|\n___________[_][__/__________---------_________/__][__\\_____________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ o/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n |oo ) ~~o o\n _\\=/_ _\\ o/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n5\n /~\\ ====\n |oo ) o o~~\n _\\=/_ _\\o /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n6\n /~\\ ====\n |oo ) ~~o o\n _\\=/_ _\\ o/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n |oo ) ~~o o\n _\\=/_ _\\ -/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n5\n /~\\ ====\n |oo ) ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n8\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n6\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n /~\\ ====\n ( oo| ~~o o Hey! We don\'t\n _\\=/_ _\\ -/_ serve their\n / _ \\ ___ / \\ / \\ kind here!\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n ( oo| ~~o o\n _\\=/_ _\\ -/_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ ====\n ( oo| ~~o o Your droids!\n _\\=/_ _\\ -/_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n14\n /~\\ ====\n ( oo| ~~o o Your droids!\n _\\=/_ _\\ -/_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n11\n /~\\ ====\n ( oo| ~~o o Your droids!\n _\\=/_ _\\ -/_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n4\n /~\\ ====\n ( oo| o o~~ Your droids!\n _\\=/_ _\\- /_ They\'ll have to\n / _ \\ ___ / \\ / \\ wait outside.\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n6\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n5\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n1\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n19\n /~\\ Why don\'t you ====\n ( oo| wait... o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n7\n /~\\ ...out by ====\n ( oo| the speeder. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n20\n /~\\ ...out by ====\n ( oo| the speeder. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ / ()\\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ...out by ====\n ( oo| the speeder. o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n2\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ // | | |//\n || |\\ /| || | | === | | // | | //\n # \\_ _/ # |_| O |_|(\' |===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n4\n /~\\ ====\n ( oo| o o~~\n _\\=/_ _\\- /_\n / _ \\ ___ / \\ / \\\n //|/.\\|\\\\ /() \\ //| | |\\\\\n || \\_/ || _|_____|_ \\\\| | |//\n || |\\ /| || | | === | | \\\\ | //\n # \\_ _/ # |_| O |_| )===(I\n | | | || O || | || I\n | | | ||__*__|| (_)(_)\n []|[] |~ \\___/ ~| |_||_|\n | | | /=\\ /=\\ /=\\ |_||_|\n____________/_]_[_\\_____[_]_[_]_[_]____/__][__\\____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n16\n """" / \\ ====\n ( o,o) ( (O ~~~~\n _\\ =/_ ~# | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """"*******. ====\n No blasters! ( o,o)*******. (o o")\n No blasters! _\\ =/_*******. _\\- /_\n / \\--/ \\*******. / \\ / \\\n //| | |\\\\******. / \\/ \\\n-------------------\\\\| | |-\\\\****\\--/ /| | |\\ |------------------\n \\\\ | | \\o===\\\\// | | | ||\n )===== #\' (> | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """"*********. ====\n No blasters! ( O,O)********. (o o")\n No blasters! _\\ =/**********. _\\- /_\n / \\--***********. / \\ / \\\n //| | **********. / \\/ \\\n-------------------\\\\| | |**********/ /| | |\\ |------------------\n \\\\ | |``*****\\\\// | | | ||\n )===== ```` (> | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """"*******. ====\n No blasters! ( O,O)*******. (o o")\n No blasters! _\\ o/_*******. _\\- /_\n / \\--/()*******. / \\ / \\\n //| | | .******. / \\/ \\\n-------------------\\\\| | |-\\\\****\\--/ /| | |\\ |------------------\n \\\\ | | \\\\ \\\\// | | | ||\n )===== o=== (> | | | `)\n | || | #\' | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" `*. ====\n No blasters! ( O,O) `*. (o o")\n No blasters! _\\ o/_ `*. _\\- /_\n / \\--/() `*. / \\ / \\\n //| | | `*. / \\/ \\\n-------------------\\\\| | |-----`*\\--/ /| | |\\ |------------------\n \\\\ | | \\\\ \\\\// | | | ||\n )===== \\\\ (> | | | `)\n | || | o=== | | |\n | )| ) #\' | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n No blasters! ( O,O) (o o")\n No blasters! _\\ o/_ *. _\\- /_\n / \\--/() `*. / \\ / \\\n //| | | `*. / \\/ \\\n-------------------\\\\| | |-----`*\\--/ /| | |\\ |------------------\n \\\\ | | \\\\ \\\\// | | | ||\n )===== \\\\ (> | | | `)\n | || | o=== | | |\n | )| ) #\' | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n No blasters! ( O,O) (o o")\n No blasters! _\\ o/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | *. / \\/ \\\n-------------------\\\\| | |-----`*\\--/ /| | |\\ |------------------\n \\\\ | | \\\\// | | | ||\n )===== \\\\ (> | | | `)\n | || | o=== | | |\n | )| ) #\' | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n No blasters! ( o,o) (o o")\n No blasters! _\\ o/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |------o\\--/ /| | |\\ |------------------\n \\\\ | | \\\\// | | | ||\n )===== (> | | | `)\n | || | \\\\ | | |\n | )| ) o=== | |\\ |\n | || | #\' / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n ( o,o) (o o")\n _\\ o/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) \\\\ | |\\ |\n | || | o=== / || \\\n |_||_| #\' / ||_|\\\n_____________________[_][__\\_________/____|[_]_\\___________________\n1\n """" ====\n ( o,o) (o o")\n _\\ =/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | \\\\ / || \\\n |_||_| o=== / ||_|\\\n_____________________[_][__\\__#\'_____/____|[_]_\\___________________\n1\n """" ====\n ( o,o) (o o")\n _\\ =/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| \\\\ / ||_|\\\n_____________________[_][__\\__#\'==___/____|[_]_\\___________________\n7\n """" ====\n ( o,o) (o o")\n _\\ =/_ _\\- /_\n / \\--/() / \\ / \\\n //| | | / \\/ \\\n-------------------\\\\| | |----------/ /| | |\\ |------------------\n \\\\ | | || | | | ||\n )===== ===(= | | | `)\n | || | | | |\n | )| ) | |\\ |\n | || | / || \\\n |_||_| / ||_|\\\n_____________________[_][__\\_=#\'==___/____|[_]_\\___________________\n9\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== ==== ####\n ~~o o ("o o) {o o"}\n _\\ -/_ _\\ -/_ {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n10\n ==== ==== ####\n ~~o o ("o o) Chewbacca here {o o"}\n _\\ -/_ _\\ -/_ is first mate on {= }\n / \\ / \\ / \\ / \\ a ship... {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n23\n ==== ==== ####\n ~~o o ("o o) Chewbacca here {o o"}\n _\\ -/_ _\\ -/_ is first mate on {= }\n / \\ / \\ / \\ / \\ a ship... {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ \\ {} {// } {}\n \\\\ | // || | | | \\ \\ {} // } {}\n )====) (\' | | | `() {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n11\n ==== ==== ####\n ~~o o ("o o) ...that might {o o"}\n _\\ -/_ _\\ -/_ suit us. {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ \\ {} {// } {}\n \\\\ | // || | | | \\ \\ {} // } {}\n )====) (\' | | | `() {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n10\n ==== ==== ####\n ~~o o ("o o) ...that might {o o"}\n _\\ -/_ _\\ -/_ suit us. {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n6\n ==== ==== ####\n ~~o o ("o o) {o o"}\n _\\ -/_ _\\ -/_ {= }\n / \\ / \\ / \\ / \\ {~~ //~}\n //| | \\\\ / \\/ \\ {{~{ //}~}}\n \\\\| | // | /| | |\\ | {} {// } {}\n \\\\ | // || | | | || {} // } {}\n )====) (\' | | | `) {} H{{}}} {}\n | || I | | | @ H"||"} @\n (_)(_) | /| | {"||"}\n |_||_| / || \\ {"||"}\n |_||_| /|_|| \\ {"||"}\n_________[_][__\\____/_[_]|____\\_____________________[_][_]_________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n35\n Han Solo. I\'m captain\n of the Millennium Falcon.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n2\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n35\n Chewie here tells me\n you\'re looking for passage\n to the Alderaan system.\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n32\n Yes, indeed.\n If it\'s a fast ship.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n Yes, indeed.\n If it\'s a fast ship.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n12\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n4\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ _\\- /_\n {~~ //~} /| || |\\.__ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\._/\') / \\/ \\ / | \\\n -------------||----------------------| /------\\ |-----------------\n (\' || ||\n (\' \')\n\n13\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n2\n It\'s the ship that made\n the Kessel run in less than\n twelve parsecs!\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ -\\- /-\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n3\n She\'s fast enough for\n you, old man.\n\n\n #### -=== ==== ====\n {"o o} ""o o ("o o) o o~~\n { =} _\\ -/_ _\\ -/_ -\\- /-\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n2\n She\'s fast enough for\n you, old man.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ -\\- /-\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n27\n She\'s fast enough for\n you, old man.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n30\n Docking bay\n ninety-four.\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n1\n\n\n\n\n #### -=== ==== ====\n {"o o} ""o o (o o") o o~~\n { =} _\\ -/_ _\\- /_ _\\- /_\n {~~ //~} /| || |\\ / \\ / \\ / \\ / \\\n {{~{ //}~}} //| || |\\\\ / \\/ \\ / | \\\n -------------||--------\\\\------------| /------\\ |-----------------\n (\' () || ||\n (\' \')\n\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n29\n\n This could really\n save my neck.\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n\n\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n10\n\n Get back to the ship\n and get her ready.\n\n #### ===-\n {"o o} o o""\n { =} _\\- /_\n {~~ //~} /| || |\\\n {{~{ //}~}} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n Get back to the ship\n and get her ready.\n ####\n {"o o} ===-\n { =} o o""\n {~~ //~} _\\- /_\n {{~{ //}~}} /| || |\\\n {} {// } {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n Get back to the ship\n #### and get her ready.\n {"o o}\n { =} ===-\n {~~ //~} o o""\n {{~{ //}~}} _\\- /_\n {} {// } {} /| || |\\\n {} // } {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n1\n\n #### Get back to the ship\n {"o o} and get her ready.\n { =}\n {~~ //~} ===-\n {{~{ //}~}} o o""\n {} {// } {} _\\- /_\n {} // } {} /| || |\\\n {} H{{}}} {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n4\n ####\n {"o o} Get back to the ship\n { =} and get her ready.\n {~~ //~}\n {{~{ //}~}} ===-\n {{~{// } }} o o""\n {} // } {} _\\- /_\n {} H{{}}} {} /| || |\\\n {} H"||"} {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n3\n ####\n {"o o}\n { =}\n {~~ //~}\n {{~{ //}~}} ===-\n {{~{// } }} o o""\n {} // } {} _\\- /_\n {} H{{}}} {} /| || |\\\n {} H"||"} {} //| || |\\\\\n--------------------------------||--------||-----------------------\n (\' \')\n\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n31\n -=== `"\',\n ""o o O O|) Going somewhere,\n _\\ -/_ _\\o/ _ Solo?\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n30\n -=== `"\',\n Yes Greedo! ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n30\n -=== `"\',\n I was just ""o o O O|)\n going to see _\\ -/_ _\\o/ _\n your boss. /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n31\n -=== `"\',\n Tell Jabba ""o o O O|)\n I have his _\\ -/_ _\\o/ _\n money. /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n31\n -=== `"\',\n ""o o O O|) He may only take\n _\\ -/_ _\\o/ _ your ship.\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n32\n -=== `"\',\n Over my dead ""o o O O|)\n body! _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n30\n -=== `"\',\n ""o o O O|) I\'ve been looking\n _\\ -/_ _\\o/ _ forward to this\n /| || |\\ /|\\ / |\\ for a long time!\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n26\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n || | || | \\\\ // | | | ||\n || |/ \\| \\\\ -==# | | | ||\n |! |====| \') \'\\ |====| /#\n =] |/|| | | || | "\n I ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n /| || |\\ /|\\ / |\\\n //| || |\\\\ //| | |\\\\\n \\\\| || | \\\\ // | | | ||\n \\o===\\| \\\\ -==# | | | ||\n |#\'==| \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n || || |\\ /|\\ / |\\\n \\\\ || |\\\\ //| | |\\\\\n \\\\o=== \\\\ // | | | ||\n |\\(#\'| \\\\ -==# | | | ||\n |====| \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n || || |\\ /|\\ / |\\\n \\\\ || |\\\\ //| | |\\\\\n \\\\o===*** // | | | ||\n |\\(#\'| \\\\ -==# | | | ||\n |====| \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_ _\\o/ _\n || || |* /|\\ / |\\\n \\\\ || *** //| | |\\\\\n \\\\o=*********** // | | | ||\n |\\(#\'***\\\\ -==# | | | ||\n |====|* \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n I\'ll bet you ""o o O O|)\n have! _\\ -/_* _\\o/ _\n || || *** /|\\ / |\\\n \\\\ ||***** //| | |\\\\\n \\\\o******************// | | | ||\n |\\(#*****\\ -==# | | | ||\n |====*** \') \'\\ |====| /#\n |/|| |* | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\o/ _\n || || |* /|\\ / |\\\n \\\\ || *** //| | |\\\\\n \\\\o=*********************** | ||\n |\\(#\'***\\\\ -==# | |" | ||\n |====|* \') \'\\ |====| /#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\O/ _\n || || |\\ /|\\ / |\\\n \\\\ || |*\\ //| *. |\\\\\n \\\\o==*********************** | ||\n |\\(#\'|* \\\\ -==# |\'* \'| ||\n |====| \') \'\\ |====| /#\n |/|| | | ||"| "\n ( )( ) | || |\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o O O|)\n _\\ -/_ _\\O/ _\n || || |\\ /|* / .\\\n \\\\ || |\\\\ //|*** |\\\\\n \\\\o=== \\\\ *****************| ||\n |\\(#\'| \\\\ -==# **** | ||\n |====| \') \'\\ .|====|\'/#\n |/|| | | || | "\n ( )( ) | || |\n |-||-| | || |"\n | || | | || |\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `"\',\n ""o o X X|)\n _\\ -/_ _\\** _ \'\n || || |\\ /***** \\\n \\\\ || |\\\\ /*******\\\\\n \\\\o=== \\\\ ***********| ||\n |\\(#\'| \\\\ -==# ******* ||\n |====| \') \'\\ *****| /#\n |/|| | |*** | "\n ( )( ) \' | || | \'\n |-||-| | || |\n | || | | || |\n________________[_][__\\________________/__)(_)_"___________________\n1\n -=== `"\',\n ""o o ***** \'\n _\\ -/_ ********\n || || |\\ *********\n \\\\ || |\\\\ **********\n \\\\o=== \\\\ *********||\n |\\(#\'| \\\\ -==#*********||\n |====| \') \'\\ ********/#\n |/|| | |***** "\n ( )( ) | || |\n |-||-| \' | || | \'\n | || | | || | "\n________________[_][__\\________________/__)(_)_____________________\n1\n -=== `**,\n ""o o *****\n _\\ -/_ ******** \'\n || || |\\ *********\n \\\\ || |\\\\ **********\n \\\\o=== \\\\ ***********|\n |\\(#\'| \\\\ -==#**********|\n |====| \') \'\\ *********#\n |/|| | |****** "\n ( )( ) | |**|\n |-||-| | || |\n | || | \' | || | \'\n________________[_][__\\________________/__)(_)______"______________\n1\n -=== `**,\n ""o o *****\n _\\ -/_ ********\n || || |\\ *********\n \\\\ || |\\\\ ********** \'\n \\\\o=== \\\\ ***********|\n |\\(#\'| \\\\ -==#**********|\n |====| \') \'\\ *********#\n |/|| | |****** "\n ( )( ) | |**|\n |-||-| | || |\n | || | | || |\n________________[_][__\\_________\'______/__)(_)_______"\'____________\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | :/----I-----\n__\\|________\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|\\ \\ |-O-| | | |\n | || \\ | \\_/___|_________|__|\n | | \\ | :/----I-----\n__\\|________\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|+ \\ |-O-| | | |\n | ||+| \\ | \\_/___|_________|__|\n | | | \\ | :/----I-----\n__\\|________\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / + \\ |-O-| | | |\n | ||+|+\\ | \\_/___|_________|__|\n | | |+| \\ | :/----I-----\n__\\|__|_____\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / + \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | + + +\\ | :/----I-----\n__\\|_|_|_|__\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / + \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | + + + | :/----I-----\n__\\|__|_|_|_\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | + \\ | \\_/___|_________|__|\n | | ||+ +\\+ | :/----I-----\n__\\|___|_|_|\\|________________________________________/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + + + +| :/----I-----\n__\\|_||_|_|_||________________________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + +\\+ + :/----I-----\n__\\|__||_|_|_|________________________________________/_____===____\n1\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + +\\+ + :/----I-----\n__\\|__||_|_|_|________________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + + +|+ :/----I-----\n__\\|__|_|_|_|||_______________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | +\\+ + + :/----I-----\n__\\|___|_|_|_|_|______________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | + +|+ + :/----I-----\n__\\|____|_|_|||_|_____________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\+ + + + :/----I-----\n__\\|_____|_|_|_|_|____________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ +|+ + + :/----I-----\n__\\|______|_|||_|_|___________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ + + + + :/----I-----\n__\\|_______|_|_|_|_|__________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ |+ + + + :/----I-----\n__\\|________|_|_|_|_|_________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ \' + + + + :/----I-----\n__\\|________\\|_|_|_|_|________________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\||_|_|_|_|_______________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_|_|_|_|_|______________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|__|_|_|_|_|_____________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|___|_|_|_|_|____________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|____|_|_|_|_|___________________________/_____===____\n2\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_____|_|_|_|_|__________________________/_____===____\n1\n\n\n\n\n What a piece\n of junk! _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|______|_|_|_|_|_________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + |/----I-----\n__\\|________\\|______|_|_|_|_|_________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + |/----I-----\n__\\|________\\|_______|_|_|_|_|________________________/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + |/----I-----\n__\\|________\\|_______|_|_|_|_|________________________/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|________|_|_|_|_|______________________|/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________|_|_|_|_|_____________________|/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________|_|_|_|_|____________________|_/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|__________|_|_|_|_|___________________|_/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|___________|_|_|_|_|_________________|__/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|____________|_|_|_|_|________________|__/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|____________|_|_|_|_|_______________|___/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_____________|_|_|_|_|______________|___/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________|_|_|_|_|____________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_______________|_|_|_|_|___________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|________________|_|_|_|_|__________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________________|_|_|_|_|_________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|__________________|_|_|_|_|________|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|___________________|_|_|_|_|_______|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|____________________|_|_|_|_|______|____/_____===____\n2\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_____________________|_|_|_|_|_____|____/_____===____\n1\n\n\n She\'ll make point\n five past light-speed!\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________________|_|_|_|_|____|____/_____===____\n10\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________________|_|_|_|_|____|____/_____===____\n6\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|______________________|_|_|_|_|____|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_______________________|_|_|_|_|___|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|________________________|_|_|_|_|__|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + + :/----I-----\n__\\|________\\|_________________________|_|_|_|_|_|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + ++ :/----I-----\n__\\|________\\|__________________________|_|_|_|_||____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|___________________________|_|_|_|_|____/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + +++ :/----I-----\n__\\|________\\|____________________________|_|_|_|||___/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_____________________________|_|_|_|_|__/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + +++ + :/----I-----\n__\\|________\\|______________________________|_|_|||_|_/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + + :/----I-----\n__\\|________\\|_______________________________|_|_|_|_|/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | +++ + |/----I-----\n__\\|________\\|________________________________|_|||_|_/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + :/----I-----\n__\\|________\\|_________________________________|_|_|_|/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | ++ + |/----I-----\n__\\|________\\|__________________________________|||_|_/_____===____\n3\n\n\n If you\'ll just get on\n board we\'ll get out of here.\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + + :/----I-----\n__\\|________\\|___________________________________|_|_|/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + |/----I-----\n__\\|________\\|___________________________________||_|_/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + + :/----I-----\n__\\|________\\|___________________________________|_|_|/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + |/----I-----\n__\\|________\\|___________________________________|__|_/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|___________________________________|___|/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|___________________________________|___|/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + |/----I-----\n__\\|________\\|___________________________________|____/_____===____\n3\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|____________________________________|___/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ /+\\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /__\\ /__\\ /~~\\\n |<><>| |<><>| (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\ |\n \\/][][\\/ // [][][] || // |\\ / | ||\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n20\n /__\\ /__\\ /~~\\\n |<><>| |<><>| Which way? (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\ |\n \\/][][\\/ // [][][] || // |\\ / | ||\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n12\n /__\\ /__\\ /~~\\\n |<><>| |<><>| Which way? (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\.\\\n \\/][][\\/ // [][][] || // |\\ / | \\\\\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n6\n /__\\ /__\\ /~~\\\n |<><>| |<><>| (O^O)\\\n (_/\\_) (_/\\_) / //, \\\\\n / \\ / \\ / //, \\\n ||/(===o //| __ |\\\\ / O\' \\\n | / \\ | // |/ \\| \\\\ /./| /|\\.\\\n \\/][][\\/ // [][][] || // |\\ / | \\\\\n |\\ /| |\' |\\ /| [\' (# | | | \')\n |_||_| |_||_| I] | | |\n [ ][ ] [ ][ ] I | | |\n | || | | || | / | \\\n |_||_| |_||_| / _| \\\n______[_][_]_________[_][_]_________________________/__[_]_____\\___\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n7\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n2\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|\\ \\ |-O-| | | |\n | || \\ | \\_/___|_________|__|\n | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /|o \\ |-O-| | | |\n | ||o| \\ | \\_/___|_________|__|\n | | | \\ | + :/----I-----\n__\\|________\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / o \\ |-O-| | | |\n | ||o|o\\ | \\_/___|_________|__|\n | | |o| \\ | + :/----I-----\n__\\|__|_____\\|_____________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /oo \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | o o o\\ | + :/----I-----\n__\\|_|_|_|__\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ /oo \\ |-O-| | | |\n | | || \\ | \\_/___|_________|__|\n | | o o o | + :/----I-----\n__\\|__|_|_|_\\|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | oo \\ | \\_/___|_________|__|\n | | ||o o\\o | + :/----I-----\n__\\|___|_|_|\\|_____________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | oo o o o| + :/----I-----\n__\\|_||_|_|_||_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | oo o\\o o + :/----I-----\n__\\|__||_|_|_|_____________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o o o|o + :/----I-----\n__\\|__|_|_|_|||____________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o\\o o o + :/----I-----\n__\\|___|_|_|_|_|___________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o o|o o + :/----I-----\n__\\|____|_|_|||_|__________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o\\o o o o + :/----I-----\n__\\|_____|_|_|_|_|_________________________________|__/_____===____\n2\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | o o|o o o + :/----I-----\n__\\|______|_|||_|_|________________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\o o o o o + :/----I-----\n__\\|_______|_|_|_|_|_______________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ o|o o o o + :/----I-----\n__\\|________|_|_|_|_|______________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ o o o o o + :/----I-----\n__\\|________\\|_|_|_|_|_____________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ o o o o o* + :/----I-----\n__\\|________\\|_|_|_|_|_____________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ |o o o o o --- + :/----I-----\n__\\|________\\||_|_|_|_|____________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- + :/----I-----\n__\\|________\\|_|_|_|_|_|__________________________*|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- --- + :/----I-----\n__\\|________\\|__|_|_|_|_|__________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- --- + :/----I-----\n__\\|________\\|__|_|_|_|_|__________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o o --- * + :/----I-----\n__\\|________\\|___|_|_|_|_|_________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . \' \\_/___|_________|__|\n | | \\ | o o o o.*--- \'. \' + :/----I-----\n__\\|________\\|____|_|_|_|_|________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o.o . . .+ :/----I-----\n__\\|________\\|_____|_|_|o|_____________________.___|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o + :/----I-----\n__\\|________\\|_____|_|_|o|__.________________._____|._/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o* + :/----I-----\n__\\|________\\|______|_|_|_|________________________|__/_____===____\n1\n\n\n Stop that ship!\n\n Blast em!\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o --- + :/----I-----\n__\\|________\\|_______|_|o|_|_______________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o --- + :/----I-----\n__\\|________\\|_______|_|o|_|______________________*|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o ---* + :/----I-----\n__\\|________\\|_______|_|o|_|_______________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o o --- :. .+ :/----I-----\n__\\|________\\|_______|_|o|_|_______________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | .\\_/___|_________|__|\n | | \\ | o o o o --- . + :/----I-----\n__\\|________\\|_______|_|o|_|________________.__.__.|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . . . \\_/___|_________|__|\n | | \\ | o o o *-- + :/----I-----\n__\\|________\\|_______|_|o|_|______________.________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . \\_/___|_________|__|\n | | \\ | o o o * . + :/----I-----\n__\\|________\\|_______|_|o|_|_._____________________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | .o o o + :/----I-----\n__\\|________\\|_______|_|o|_o__________.____________|__/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o *+ :/----I-----\n__\\|________\\|_____._|_|o|_o________________________|_/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o --- + :/----I-----\n__\\|________\\|_______|_|o|_o_________________________|/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o* --- |/----I-----\n__\\|________\\|_______|_|o|_o__________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o --- --- :/----I-----\n__\\|________\\|_______|_|o|_o__________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o o --- --- :/----I-----\n__\\|________\\|_______|_|o|_o__________________________/_____===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o *- --- ----I-----\n__\\|________\\|_______|_|o|_o________________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \' \\_/___|_________|__|\n | | \\ | o o * . --- ----I-----\n__\\|________\\|_______|_|o|_o________________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | . \\_/___|_________|__|\n | | \\ | o o --*----I-----\n__\\|________\\|_______|_|oo_o_.______________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | . o o : ***---I-----\n__\\|________\\|_______|_|oo_o__________________________\'___"_===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o *---I-----\n__\\|________\\|____.__|_|oo_o_______________________"_.____._===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | . o o ----I-----\n__\\|________\\|_______|_|oo_o______________________._________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o . ----I-----\n__\\|________\\|__.____|_|oo_o________________________________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o ----I-----\n__\\|________\\|_._____|_|oo_o____________________.___________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o ----I-----\n__\\|________\\|_._____|_|oo_o___________________.____________===____\n1\n\n\n\n\n\n _\n ________|_\n _______ _ ___ -------------\n / \\______\\ / \\ | | |\n |\\ / \\ \\ |-O-| | | |\n | | \\ | \\_/___|_________|__|\n | | \\ | o o ----I-----\n__\\|________\\|_._____|_|oo_o__________________._____________===____\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_____|_|_|_____________|__|__|____________________\n3\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\______|_|_|____________|__|__|____________________\n10\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n\n\n\n ___________-----_O________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n\n\n _ ____-----_O___\n ____(_)====[ ]======____\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n\n _ ____-----_O___\n (_)====[ ]======\n _______~~~~-----~~~~~_____\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ________^____^____^_______\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n _ ____-----_O___\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n (_)====[ ]======\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n ~~~~-----~~~~~\n ^ ^ ^\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n1\n ^ ^ ^\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n6\n\n\n\n\n\n\n\n __________________________\n_ |--------------------------\n_|__ I | o o o o\n \\ .I. |\nO O |-. |I| o o o | __\n_____|_|____/[_]\\_______|_|_|___________|__|__|____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| . .\n . . : : : : : : :\n . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n. . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| . .\n . . : : : : : : :\n . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| .\n . . : : : : : : :\n. . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| .\n . . : : : : : : :\n . . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| .\n . . : : : : : : :\n . . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n2\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . .\n. / :| () |: : :\\\n8 . :....\\__/...........: .\n8 . . |___________________|\n\' |...................| .\n . . : : : : : : :\n . . \\................./ .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n. -..___..- .\n2\n . . __---__ .\n. . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . . /. / \\.........\\ . .\n8. / :| () |: : :\\\n88 . :....\\__/...........: .\n88 . . |___________________|\n8\' |...................| .\n . . : : : : : : :\n . . \\................./ .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n. . . . /. / \\.........\\ . .\n88. / :| () |: : :\\\n888 . :....\\__/...........: .\n888 . . |___________________|\n88\' |...................| .\n\' . . : : : : : : :\n . . \\................./ .\n. . \\ . . : . . / .\n . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n.. . . . /. / \\.........\\ . .\n888. / :| () |: : :\\\n8888 . :....\\__/...........: .\n8888 . . |___________________|\n888\' |...................|\n\'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n .. . . . /. / \\.........\\ . .\n8888. / :| () |: : :\\\n88888 . :....\\__/...........: .\n88888 . . |___________________|\n8888\' |...................|\n \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n. . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n. . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n .. . . . /. / \\.........\\ . .\n.8888. / :| () |: : :\\\n888888 . :....\\__/...........: .\n888888 . . |___________________|\n\'8888\' |...................|\n \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . . .-\'...:...\'-. .\n . / .__. : . . \\\n .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........: .\n 888888 . . |___________________|\n \'8888\' |...................|\n \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . -..___..- .\n2\n . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n. .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........: .\n 888888 . . |___________________|\n \'8888\' |...................|\n. \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n. . -..___..- .\n2\n . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........: .\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . . -..___..-\n2\n. . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n 888888 . :....\\__/...........:\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n. . . \\ . . : . . / .\n . . . . \\._........._./ . .\n . . -..___..-\n2\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n. 888888 . :....\\__/...........:\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n. . . . . \\._........._./ .\n . . -..___..-\n1\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n . 888888 . :....\\__/...........:\n 888888 . . |___________________|\n \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n . . . . . \\._........._./ .\n . . -..___..-\n1\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n . 888888 . :....\\__/...........:\n 888888 . . |___________________|\n. \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n . . . . . \\._........._./ .\n . . -..___..-\n7\n . . . __---__ .\n . . . . . .-\'...:...\'-.\n. . / .__. : . . \\\n . .. . . . /. / \\.........\\ . .\n .8888. / :| () |: : :\\\n . 888888 . :....\\__/...........:\n 888888 . . |___________________|\n . \'8888\' |...................|\n . \'\' . . : : : : : : :\n . . \\................./ .\n . . . \\ . . : . . / .\n . . . . . \\._........._./ .\n . . -..___..-\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n4\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n20\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n We\'ve | |\n entered | |\n the | .@@. |\n Alderaan | @@@@ |\n system. | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n6\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n23\n I grow tired /~~\\\n ==== of asking this ===, |<><>|\n | o o so it will @o o@) /_/\\_\\\n _\\ -/_ be the last time. \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n12\n I grow tired /~~\\\n ==== of asking this ===, |<><>|\n | o o so it will @o o@) /_/\\_\\\n _\\ -/_ be the last time. \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| |// /_/\\ /\\_| \\\\ | |//\n \\(| )/ || \\\\ // || \\#|====#/\n |-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| |// /_/\\ /\\_| \\\\ | |//\n \\(| )/ || \\\\ // || \\#|====#/\n |-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n22\n Where is the /~~\\\n ==== Rebel Base? ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| |// /_/\\ /\\_| \\\\ | |//\n \\(| )/ || \\\\ // || \\#|====#/\n |-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n8\n Where is the /~~\\\n ==== Rebel Base? ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n11\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n30\n /~~\\\n ==== Dantooine. ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n4\n /~~\\\n ==== They\'re on ===, |<><>|\n | o o Dantooine. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n28\n /~~\\\n ==== They\'re on ===, |<><>|\n | o o Dantooine. @- -@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n4\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n4\n You see, Lord /~~\\\n ==== Vader, she can ===, |<><>|\n | o o be reasonable. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n | /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n |||| | \\\\ /_/\\ /\\_| \\\\ | |//\n |||| | () || \\\\ // || \\#|====#/\n ()|-==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n7\n You see, Lord /~~\\\n ==== Vader, she can ===, |<><>|\n | o o be reasonable. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n22\n You see, Lord /~~\\\n ==== Vader, she can ===, |<><>|\n | o o be reasonable. @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n2\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n28\n Proceed with /~~\\\n ==== the ===, |<><>|\n | o o demonstration! @o o@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n Proceed with /~~\\\n ==== the ===, |<><>|\n | o o demonstration! @O O@) /_/\\_\\\n _\\ -/_ \\- / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n1\n Proceed with /~~\\\n ==== the ===, |<><>|\n | o o demonstration! @O O@) /_/\\_\\\n _\\ -/_ \\o / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n3\n /~~\\\n ==== ===, |<><>|\n | o o @o o@) /_/\\_\\\n _\\ -/_ \\o / /\\___/\\\n /"\'==\'"\\ /~~ ~~\\ //|[ ] \\\\\n / /|:::|\\\\ / ( ) \\ // |[_] |\\\\\n \\\\|| | \\\\ /_/\\ /\\_| \\\\ | |//\n \\\\| | () || \\\\ // || \\#|====#/\n \')==-| @ | | | @ /|\\ /I\\\n |----| | | | / | || I \\\n | || | | | | / | || | \\\n | || | / | \\ / | || | \\\n | || | ~~~~~~~~~ / | || | \\\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n33\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n You | |\n may fire | .@@. |\nwhen ready.| @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n31\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | | What!\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_, q q | / \\ |\n_[__|__|__ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n2\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_, q q | / \\ |\n_[_|__|___ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n3\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_,q q | / \\ |\n_[|__|____ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | |\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | | ......\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | | ............\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | ..................\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | | ........................\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ...........................***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | .....................***...***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ...............***...***...***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | .........***...***...****..***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ...***...***...****..*****.***\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | | **\n | | | ***|..***...****..*****..*****\n | | | | | **\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | | ******\n | | | **...****..*****..************\n | | | | | ******\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | ****** *******\n | | | *..*****..********************\n | | | | ****** *******\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | |****** ****************\n | | | .*****************************\n | | | |****** ****************\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | |****************\n | | | ******************************\n | | | |****************\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | ******** |\n | | | ******************************\n | | | ******** |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n2\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ******************************\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | ..|.........|................\n | | | ******************************\n | | | \'\'|\'\'\'\'\'\'\'\'\'|\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\'\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\..........|..............\n_[|__|____ | | ****************************\n | | | ******************************\n | | | ****************************\n | | \\.___./\'\'\'\'\'\'\'\'\'\'|\'\'\'\'\'\'\'\'\'\'\'\'\'\'\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / ***************************\n_[|__|____ | | *****************************\n | | | ******************************\n | | | *****************************\n | | \\.___.***************************\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. ***************************\n_.q q | / ****************************\n_[|__|____ | | *****************************\n | | | ******************************\n | | | *****************************\n | | \\.___.****************************\n | | / ***************************\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / *************************\n_[|__|____ | | *****************************\n | | | ******************************\n | | | *****************************\n | | \\.___.*************************\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\..........|......\n_[|__|____ | | **********************\n | | | ******************************\n | | | **********************\n | | \\.___./\'\'\'\'\'\'\'\'\'\'|\'\'\'\'\'\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n1\n ---------------------\n |. ./\' |\n | \\ ./\' |\n | \'\\ .___. /\' |\n_.q q | / \\ |\n_[|__|____ | | | |\n | | | ******************************\n | | | | |\n | | \\.___./ |\n | | / \\. |\n | | /\' \'\\. |\n | |\' \'\\. |\n | ---------------------|\n5\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ |\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ ----|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ --------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ ------------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @@@@ ----------------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .@@. |\n | @**--------------------|\n | `@@\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n4\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .**. |\n | ****-------------------|\n | `**\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .**. |\n | ****--------------- |\n | `**\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | .**. |\n | ****----------- |\n | `**\' |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | ** |\n | **** |\n | ******------ |\n | **** |\n | ** |\n `-_____ _____-\'\n ----____ ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | \' ** \' |\n | \' *****# |\n | :******** " |\n | **#******* |\n | ******** |\n | \' ****#* \' |\n `-_____ " ** _____-\'\n ----____ \' " ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | \' |\n | " ** \'# |\n | \' \' ****** \' |\n | ******** \' |\n | \' #********** |\n | ******** |\n | \' : ****** \' |\n `-_____ " ** " _____-\'\n ----____ \' # ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | \' " # |\n | " \' ** |\n | ****** \' |\n | ******** \' |\n | \' # **** **** |\n | ******** |\n | \' ****** |\n `-_____ : " ** \' _____-\'\n ----____ \' : " ____----\n ----______----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | \' * * |\n | " * ** * \' |\n | * ****** * |\n | * ** ** * \' |\n | \' # * ** ** * |\n | * ** ** * |\n | * ****** * |\n `-_____: " * ** * \' _____-\'\n ----____ * * " ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | " * * |\n | * * |\n | * **** * |\n | * ** ** * \' |\n |\' # * ** ** * |\n | * ** ** * |\n | * **** * |\n `-_____" * * _____-\'\n ----____ * * ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | * * |\n | * ** * |\n | * **** * \'|\n | # * ** ** * |\n | * **** * |\n | * ** * |\n `-_____ * * _____-\'\n ----____ ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | * * |\n | * \' " * |\n | * ** * |\n | * **** * |\n | * ** * |\n | * " * |\n `-_____ : _____-\'\n ----____ ____----\n ----_____-----\n1\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | . . |\n | |\n | |\n | |\n | ** |\n | |\n | |\n `-_____ . _____-\'\n ----____ : ____----\n ----_____-----\n9\n ______----______\n __---------| | | | | |---------__\n .|__|__|__|__|__|__|____|__|__|__|__|__|__|.\n | |\n | |\n | |\n | |\n | |\n | |\n | |\n `-_____ _____-\'\n ----____ ____----\n ----_____-----\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n3\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n2\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n3\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n3\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ .....\\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ / /| | |\\ |\n || | | | \\\\ || | | | ||\n (\' |====| =)== (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ ..... \\_/ _\\- /_\n / \\ / \\ / \\ / \\\n //| | |\\\\ / \\/ \\\n || | | | \\\\ /0 / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ -/_ ..... \\_/ _\\- /_\n / \\ / \\ . / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ /*\' / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o . /o\\ (o o")\n _\\ -/_ ..... .*\' \\_/ _\\- /_\n / \\ / \\ .*\' / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ /*\' / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== .* _ ====\n ~~O O .*\' /o\\ (o o")\n _\\ o/_. .*\' \\_/ _\\- /_\n / \\ / \\ .*\' / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ /*\' / /| | |\\ |\n || | | | \\\\// || | | | ||\n (\' |====| <) (` | | | `)\n | || | | | |\n (_)(_) | |\\ |\n |_||_| / || \\\n |_||_| / ||_|\\\n___________/__][__\\___________________________________/____|[_]_\\__\n1\n ==== _ ====\n ~~o o /o\\ (o o")\n _\\ o/_ .* \\_/ _\\- /_\n / \\ / \\ .*\' / \\ / \\\n //| | |\\\\ .*\' / \\/ \\\n || | | | \\\\ .*\' / /| | |\\ |\n || | | | \\\\ /*\' || | | | ||\n (\' |====| /)/ (` | | | `)\n | || | <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n14\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( /> <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n10\n ####\n I told you {o o"}\n I\'d outrun {= }\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( /> <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( /> <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n3\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} __o____O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {{{@ /> <\\ ) | | === | |\n {} H{{}}} \\___________/ |_| O |_|\n @ H"||"} \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {{{@ >\\ <\\ ) | | === | |\n {} H{{}}} \\___________/ |_| O |_|\n @ H"||"} \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n I told you {"o o}\n I\'d outrun { =}\n them. {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n14\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | |-=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) | --=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) |---=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) ----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ ) -----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o___O___ /() \\\n {} {// } {} / =- /\\ \\ _|_____|_\n {} // } {} ( >\\ <\\ )------=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n ####\n {"o o} Now be\n { =} careful R2.\n {~~ //~} ___\n {{~{ //}~}} ___o__O____ /() \\\n {} {// } {} / =- >\\ \\ _|_____|_\n {} // } {} ( >\\ /\\ )------=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ___o__O____ /() \\\n {} {// } {} / =- >\\ \\ _|_____|_\n {} // } {} ( >\\ /\\ ) -----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ___o_O_____ /() \\\n {} {// } {} / =--> \\ _|_____|_\n {} // } {} ( >\\/< ) ----=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ____oO_____ /() \\\n {} {// } {} / -/=> \\ _|_____|_\n {} // } {} ( />/\\ ) |---=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} o ___\n {{~{ //}~}} ___/\\O_____ /() \\\n {} {// } {} / /> > \\ _|_____|_\n {} // } {} ( /\\ ) | --=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} \\--o ___\n {{~{ //}~}} __/_\\O_____ /() \\\n {} {// } {} / | \\ _|_____|_\n {} // } {} ( / \\ ) | |-=== | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =} ,\n {~~ //~} \\--o ___\n {{~{ //}~}} ___>\\O/____ /() \\\n {} {// } {} / | \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"O O}\n { =} ,\n {~~ //~} \\--o ___\n {{~{ //}~}} ___>\\O/____ /() \\\n {} {// } {} / | \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} ____\\O/____ /() \\\n {} {// } {} / >-|o \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>-\\o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~-~o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>~\\~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~-~o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>~\\~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~-~o____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___>~\\~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n1\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___~~~~____/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n6\n ####\n {"o o}\n { =}\n {~~ //~} ___\n {{~{ //}~}} _____O_____ /() \\\n {} {// } {} / /|\\ \\ _|_____|_\n {} // } {} ( / \\ ) | | === | |\n {} H{{}}} {} \\___________/ |_| O |_|\n @ H"||"} @ \\ / || O ||\n {"||"} | | ||__*__||\n {"||"} | | |~ \\___/ ~|\n {"||"} | | /=\\ /=\\ /=\\\n_______________[_][_]________/_______\\_____[_]_[_]_[_]_____________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n _-=-. ====\n ((___) (o o")\n _\\ -/_ _\\- /_\n / \\ / \\ _ / \\ / \\\n //| | |\\\\ /o\\ / \\/ \\\n || | | | \\\\ \\_/ / /| | |\\ |\n || | | | \\\\ /o || | | | ||\n (\' |====| /)/ (` | | | `)\n | || | =<| .\n .| . . .\n | .\n | .\n | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . . .\n | . . .\n | .\n|>=<| .\n . | . . .\n | .\n | .\n .| .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . . .\n | . . .\n\\ | .\n-|>=<| .\n/ . | . . .\n | .\n | .\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . . .\n_ | . . .\n\'\\ | .\nO-|>=<| .\n_/. | . . .\n | .\n | .\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . |. . .\n _ | . . .\n/\'\\ | .\n-O-|>=<| .\n\\_/ | . . .\n | .\n | .\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . | . .\n _ | . . .\n /\'\\ | .\n|-O-|>=<| .\n \\_/ | . . .\n | .\n |.\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . .| . .\n _ | . . .\n /\'\\ | .\n<|-O-|>=<| .\n \\_/ | . . .\n | .\n |\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . . | . .\n _ | . . .\n /\'\\ | .\n=<|-O-|>=<| .\n .\\_/ | . . .\n | .\n .|\n . | .\n . . . .\n1\n . . . .\n. .\n .\n | . O\n . . | . .\n _ | . . .\n /\'\\ | .\n>=<|-O-|>=<| .\n . \\_/ | . . .\n | .\n . |\n . | .\n . . . .\n1\n . . . .\n. .\n .\n| | . O\n| . . | . .\n| _ | . . .\n| /\'\\ | .\n|>=<|-O-|>=<| .\n| . \\_/ | . . .\n| | .\n| . |\n| . | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n |. . | . .\n | _ | . . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n |. \\_/ | . . .\n | | .\n | . |\n | . | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n | . | . .\n | _ |. . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n | \\_/ | . . .\n | |.\n | . |\n |. | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n .| . | . .\n | _ | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n .| \\_/ | . . .\n | |\n | . |\n | | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . | . | . .\n | _ .| . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | .|\n | . |\n .| | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . | . | . .\n | _ . | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | . |\n | . |\n . | | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . | . | . .\n | _ . | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | . |\n | . |\n . | | .\n . . . .\n1\n . . . .\n. .\n .\n | | . O\n . |. | . .\n | _ . | . .\n | /\'\\ | .\n |>=<|-O-|>=<| .\n . | \\_/ | . . .\n | . |\n | . |\n . | | .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n | . | . .\n | | .\n |=()=| .\n . | | . . .\n | . |\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n | . | . .\n | | .\n |=()=| .\n . | | . . .\n | . |\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n |. | . .\n | | .\n |=()=| .\n . | | . . .\n |. |\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | | .\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | |.\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | |\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n | .|\n |-O-| .\n . | | . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n |o| .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n * .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n . .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n . .\n . . . .\n .\n .\n . .\n . . . .\n1\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n . .\n . . . .\n .\n .\n . .\n . . . .\n10\n . . . .\n. .\n .\n . O\n . . . .\n . . .\n .\n .\n . . . .\n .\n .\n . .\n . . . .\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n11\n ==== #### He\'s heading for ===- ====\n ~~o o {"o o} that small moon! o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n19\n ==== #### He\'s heading for ===- ====\n ~~o o {"o o} that small moon! o o"" (- -")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n6\n ==== #### ===- ====\n ~~o o {"o o} o o"" (- -")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### That\'s no moon. ===- ====\n ~~o o {"o o} o o"" (- -")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### That\'s no moon. ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n23\n ==== #### That\'s no moon. -=== ====\n ~~o o {"o o} ""o o (o o")\n _\\ -/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n1\n ==== #### -=== ====\n ~~o o {"o o} ""o o (o o")\n _\\ -/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n24\n ==== #### It\'s a -=== ====\n ~~o o {"o o} space station! ""o o (o o")\n _\\ -/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n7\n ==== #### It\'s a -=== ====\n ~~O O {"o o} space station! ""o o (o o")\n _\\ o/_ { =} _\\ -/_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n1\n ==== #### It\'s a ===- ====\n ~~O O {"o o} space station! o o"" (o o")\n _\\ o/_ { =} _\\o /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### It\'s a ===- ====\n ~~o o {"o o} space station! o o"" (o o")\n _\\ o/_ { =} _\\o /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ o/_ { =} _\\o /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n ==== #### ===- ====\n o o~~ {"o o} o o"" (o o")\n _\\- /_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n15\n ==== #### ===- ====\n o o~~ {o o"} o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n14\n . . __---__ .\n . . . .-\'...:...\'-. .\n . / .__. : . . \\\n . . /. / \\.........\\ . . .\n / :| () |: : :\\\n . :....\\__/...........: .\n . . |___________________|\n |...................| . .\n . . : : : : : : :\n . \\................./ . .\n . \\ . . : . . / .\n . . . \\._........._./ . .\n -..___..- .\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== #### ===- ====\n o o~~ {o o"} o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n22\n ==== #### I have a very ===- ====\n o o~~ {o o"} bad feeling o o"" (o o")\n _\\- /_ {= } about this! _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### ===- ====\n o o~~ {o o"} o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n11\n ==== #### Turn the ship ===- ====\n o o~~ {o o"} around. o o"" (o o")\n _\\- /_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n12\n ==== #### Turn the ship ===- ====\n ~~o o {o o"} around. o o"" (o o")\n _\\ -/_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### ===- ====\n ~~o o {o o"} o o"" (o o")\n _\\ -/_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n10\n ==== #### I think you\'re ===- ====\n ~~o o {o o"} right. o o"" (o o")\n _\\ -/_ {= } _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} Full reverse! /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n12\n ==== #### I think you\'re ===- ====\n ~~o o {"o o} right. o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} Full reverse! /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n1\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n9\n ==== #### Chewie, lock in ===- ====\n ~~o o {"o o} the auxiliary o o"" (o o")\n _\\ -/_ { =} power! _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n11\n ==== #### Chewie, lock in ===- ====\n o o~~ {"o o} the auxiliary o o"" (o o")\n _\\- /_ { =} power! _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n6\n ==== #### ===- ====\n o o~~ {"o o} o o"" (o o")\n _\\- /_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### Why are we still ===- ====\n o o~~ {"o o} moving towards o o"" (o o")\n _\\- /_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### Why are we still ===- ====\n o o~~ {"o o} moving towards o o"" (o o")\n _\\o /_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n2\n ==== #### Why are we still ===- ====\n ~~o o {"o o} moving towards o o"" (o o")\n _\\ o/_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n16\n ==== #### Why are we still ===- ====\n ~~o o {"o o} moving towards o o"" (o o")\n _\\ -/_ { =} it? _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n4\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n24\n ==== #### We\'re caught in ===- ====\n ~~o o {"o o} a tractor beam! o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n20\n ==== #### I\'m going to have ===- ====\n ~~o o {"o o} to shut down. o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n6\n ==== #### ===- ====\n ~~o o {"o o} o o"" (o o")\n _\\ -/_ { =} _\\- /_ _\\- /_\n / \\ / \\ {~~ //~} /| || |\\ / \\ / \\\n \\ | || {{~{ //}~}} //| || |\\\\ / \\/ \\/\n \\ | || {} {// } {} // | || |// | /| |/\n \\---------{}--------{}-------------//-------//--------------/\n {} @ (\' (\'\n @\n\n\n\n___________________________________________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _\\\\_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _\\\\_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _||_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n2\n |____________________________________\n |\n |_\n |\n ___(___ |\n ===o====== |\n ^^ ^ |\n |\n |\n _|\n _//_ _||_ |\n __________|----|______|----|________|\n | /______\\ /______\\\n6\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n25\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ==== Yes?\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n5\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n36\n /~~\\ We\'ve captured a\n |<><>| freighter entering\n /_/\\_\\ the remains of the\n /\\___/\\ ==== Alderaan system.\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n40\n /~~\\ Its markings\n |<><>| match those of a\n /_/\\_\\ ship that blasted\n /\\___/\\ ==== its way out of\n // [ ]|\\\\ | o o Mos Eisley!\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\ They must be\n |<><>| trying to return\n /_/\\_\\ the stolen plans\n /\\___/\\ to the Princess. ====\n // [ ]|\\\\ | o o\n //| [_]| \\\\ _\\ -/_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n33\n /~~\\ They must be\n |<><>| trying to return\n /_/\\_\\ the stolen plans\n /\\___/\\ to the Princess. ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n6\n /~~\\ She may yet\n |<><>| be of some use\n /_/\\_\\ to us.\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | // /"\'==\'"\\\n #|====|# | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n14\n /~~\\ She may yet\n |<><>| be of some use\n /_/\\_\\ to us.\n /\\___/\\ # ====\n // [ ]|\\\\// o o |\n //| [_]| \\/ _\\- /_\n \\\\| | /"\'==\'"\\\n #|====| | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n2\n /~~\\ She may yet\n |<><>| be of some use\n /_/\\_\\ to us.\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | \\\\ /"\'==\'"\\\n #|====| # | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n4\n /~~\\\n |<><>|\n /_/\\_\\\n /\\___/\\ ====\n // [ ]|\\\\ o o |\n //| [_]| \\\\ _\\- /_\n \\\\| | \\\\ /"\'==\'"\\\n #|====| # | | ::: |\n /|\\ /I\\ || | ||\n-------------------------------------------------------------------\n\n\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ __|_|___________/_____===____\n | |\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ __|_|___________/_____===____\n | |\n | oooo |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ __|_|___________/_____===____\n | oooo |\n | |||| |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo + O :/----I-----\n____||||_||||___________ oooo __|_|___________/_____===____\n | |||| |\n |------------|\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___________ |||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___________ |||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||__________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||________|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_______|||| __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||______||||_ __|_|___________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_____||||__ __|_|___________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_____||||__ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||____||||___ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n There\'s no one _\n on board sir. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||___||||____ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n There\'s no one _\n on board sir. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||__||||_____ __|__|__________/_____===____\n |------------|\n | |\n17\n\n\n\n There\'s no one _\n on board sir. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n25\n\n\n\n It must be a _\n decoy. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n26\n\n Did you find\n any droids?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n20\n\n\n\n No sir. _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|_|___________/_____===____\n |------------|\n | |\n34\n\n Send a scanning\n crew aboard.\n _\n I want every part ________|_\n of this ship _ ___ -------------\n checked. / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|_|___________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|_|___________/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|__|__________/_____===____\n |------------|\n | |\n19\n\n I sense something...\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n1\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n30\n\n ...A presence I\'ve\n not felt since...\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n oooo oooo oooo + O :/----I-----\n____||||_||||_||||______ __|___|_________/_____===____\n |------------|\n | |\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / \\ |---|\n | | / \\ | |\n ________|---|/ \\|---|___________\n / \\\n / \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / \\ \\|---|___________\n / / \\ \\\n / /____________________________________\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / \\ \\|---|___________\n / / \\ \\\n / /_________________________===-_______\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / \\ \\|---|___________\n / / ===- \\ \\\n / /_________________________o o""______\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / \\ \\ | |\n ________|---|/ / ===- \\ \\|---|___________\n / / o o"" \\ \\\n / /_________________________\\- /_______\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ===- \\ \\ | |\n ________|---|/ / o o"" \\ \\|---|___________\n / / _\\- /_ \\ \\\n / /_________====__________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ===- \\ \\ | |\n ________|---|/ / o o"" \\ \\|---|___________\n / / ==== _\\- /_ \\ \\\n / /________~~o o__________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ===- \\ \\ | |\n ________|---|/ / ==== o o"" \\ \\|---|___________\n / / ~~o o _\\- /_ \\ \\\n / /_________\\ -/__________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n4\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== -=== \\ \\ | |\n ________|---|/ / ~~o o ""o o \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n4\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n2\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== -=== \\ \\ | |\n ________|---|/ / ~~o o ""o o \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n4\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n34\n \\ __\\ It\'s lucky you had /__ /\n | | these compartments. | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n29\n \\ __\\ I use them for /__ /\n | | smuggling. | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n30\n \\ __\\ I never thought /__ /\n | | I\'d be smuggling | |\n |---| myself. |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n2\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n31\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\________/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\__====__/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o o o"" \\ \\|---|___________\n / / _\\ -/_ ==== _\\- /_ \\ \\\n / /_______/__\\ /_\\_("o o)_/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ==== o o"" \\ \\|---|___________\n / / _\\ -/_ ("o o) _\\- /_ \\ \\\n / /_______/__\\ /_\\__\\_-/__/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n1\n \\ __\\ Even if I could /__ /\n | | take off, I\'d never | |\n |---| get past that |---|\n | | tractor beam. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n5\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n25\n \\ __\\ /__ /\n | | Leave that | |\n |---| to me! |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n3\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n35\n \\ __\\ Damn fool! /__ /\n | | I knew that you | |\n |---| were going to |---|\n | | say that. | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n6\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n21\n \\ __\\ /__ /\n | | Who is more foolish? | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n3\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n30\n \\ __\\ /__ /\n | | The fool or the fool | |\n |---| who follows him? |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n6\n \\ __\\ /__ /\n | | | |\n |---| |---|\n | | | |\n |---| |---|\n | | _________________________ | |\n |---| / _______________________ \\ |---|\n | | / / ==== ==== ===- \\ \\ | |\n ________|---|/ / ~~o o ("o o) o o"" \\ \\|---|___________\n / / _\\ -/_ _\\ -/_ _\\- /_ \\ \\\n / /_______/__\\ /_\\/_\\__/_\\/|_||_|\\_____\\ \\\n________/_______________________________________________\\__________\n\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n25\n\n\n The ship\'s\n all yours. _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n6\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n36\n\n\n If the scanners detect\n anything report it _\n immediately. ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ __|==|_____|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ ___|==|____|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ ____|==|___|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ _____|==|__|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o o :/----I-----\n________________________ ______|==|_|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + +o o :/----I-----\n________________________ _______|==||__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + + o :/----I-----\n________________________ ________|==|__|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + o+ o :/----I-----\n________________________ _________|==|_|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n +o +o :/----I-----\n________________________ __________|==||_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n + o :/----I-----\n________________________ ___________|==|_/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o+ o+ :/----I-----\n________________________ ___________||=||/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o +o +:/----I-----\n________________________ ___________|_||=/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ___________|__|=/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o+=:/----I-----\n________________________ ___________|__||/_____===____\n |------------|\n | |\n2\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o |:/----I-----\n________________________ ___________|__|_/_____===____\n |------------|\n | |\n18\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ___________|__|_/_____===____\n |------------|\n | |\n15\n\n Hey down there!\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ___________|__|_/_____===____\n |------------|\n | |\n17\n\n Hey down there!\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|_|_/_____===____\n |------------|\n | |\n3\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|_|_/_____===____\n |------------|\n | |\n20\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|_|_/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o o :/----I-----\n________________________ ____________|__|/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o |:/----I-----\n________________________ _____________|__/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o :/----I-----\n________________________ ______________|_/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n o :/----I-----\n________________________ _______________|/_____===____\n |------------|\n | |\n1\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n |:/----I-----\n________________________ ________________/_____===____\n |------------|\n | |\n5\n\n Could you give us\n a hand with this?\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n :/----I-----\n________________________ ________________/_____===____\n |------------|\n | |\n10\n\n\n\n _\n ________|_\n _ ___ -------------\n / \\ | | |\n |-O-| | | |\n \\_/___|_________|__|\n :/----I-----\n________________________ ________________/_____===____\n |------------|\n | |\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n31\n ==== _________________________\n TK-421. | o o |\\ _____________________ /|\n Why aren\'t you _\\ -/_ | | | |\n at your post? / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n3\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n13\n /__\\\n |<><>|\n (_/\\_)\n / \\\n //| __ |\\\\\n // |/ \\| \\\\\n // [][][] ||\n |\' |\\ /| \'|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n17\n /__\\\n |<><>|\n |, (_/\\_) ,|\n \\\\ / \\ //\n \\\\//| __ |\\\\//\n \\/ |/ \\| \\/\n [][][]\n |\\ /|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n4\n /__\\\n |<><>|\n (_/\\_)\n / \\\n //| __ |\\\\\n // |/ \\| \\\\\n || [][][] ||\n |\' |\\ /| \'|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n4\n /__\\\n |<><>|\n (_/\\_)\n / \\\n //| __ |\\\\\n // |/ \\| \\\\\n || [][][] \\\\\n |\' |\\ /| \'|\n |_||_|\n [ ][ ]\n | || |\n |_||_|\n_____________________________/__][_]_______________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n6\n ==== _________________________\n Take over. | o o |\\ _____________________ /|\n We\'ve got a bad _\\ -/_ | | | |\n transmitter. / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n16\n ==== _________________________\n Take over. o o | |\\ _____________________ /|\n We\'ve got a bad _\\- /_ | | | |\n transmitter. / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n7\n ==== _________________________\n Take over. | o o |\\ _____________________ /|\n We\'ve got a bad _\\ -/_ | | | |\n transmitter. / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n6\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n32\n ==== _________________________\n I\'ll see | o o |\\ _____________________ /|\n what I can do. _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n5\n ==== _________________________\n | o o |\\ _____________________ /|\n _\\ -/_ | | | |\n / / \\ | | | |\n | /| ""|\\\\ | | | |\n |||| | \\\\ | | | |\n |||| | () | |_____________________| |\n ()|-==-| |/_______________________\\|\n |----|\n | || |\n | || |\n |_||_|\n_____________________[_][__\\_______________________________________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n8\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""||| __ | |\n |||| ||| |o=|| |\n |||| ||| |__|| |\n ()|-==-|() | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|*=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n2\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|*=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|____________________________|________________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| | |\n________[_][__\\______|\\__________________________/|________________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | | |\n |_||_| |\\__________________________/|\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | | |\n | || | |\\__________________________/|\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| | |\n | || | |\\__________________________/|\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| | |\n |----| |\\__________________________/|\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_|| |\n ()|-==-| |\\__________________________/|\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=|| |\n |||| | \\()_||\\__________________________/|\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ | |\n |||| | \\\\|o=||\\__________________________/|\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ | |\n | /| ""|\\\\ __ |\\__________________________/|\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ | |\n / / \\ |\\__________________________/|\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o | |\n _\\ -/_ |\\__________________________/|\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | |\n | o o |\\__________________________/|\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== |\\__________________________/|\n | o o | {o o"} |><> | |\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n2\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n2\n ==== | #### /__\\ |\n | O O | {o o"} |><> | |\n _\\ -/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n3\n ==== | #### /__\\ |\n | O O | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n1\n ==== | #### /__\\ |\n | o o | {o o"} |><> | |\n _\\ o/_ | {= } (/\\__) |\n / / \\ | {~~ //~} / \\ |\n | /| ""|\\\\ __ | {{~{ //}~}} ||/(===o |\n |||| | \\\\|o=|| {} {// } {} | / \\ | |\n |||| | \\()_|| {} // } {} \\/][][\\/ |\n ()|-==-| | {} H{{}}} {} |\\ /| |\n |----| | @ H"||"} @ |_||_| |\n | || | | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n________[_][__\\______|____[_][_]________/__][_]___|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n1\n -=== | _______\n | o o | "" / \\ o*oo\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n2\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | |-----\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## | ----- o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ## |----- | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ | ----- | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ -----## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ -/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ ----- | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ ----- | ## | | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\\\ ----- | ## | | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | "\'|\\----- | ## | | o*oo\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | o o | "" / \\ oo*o\n _\\ o/_ | :. | | o**o\n / / \\ | | | *oo*\n // | *---\\ | ## | | o**o\n // || | \\\\ | ## \\_______/\n // || | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | O O | "" / \\ oo*o\n _\\ */_ | :. | | o**o\n / /* \\ | | | *oo*\n // *****\\\\ | ## | | o**o\n // || * | \\\\ | ## \\_______/\n // || * | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n | O*O | "" / \\ oo*o\n . _\\***_. | :. | | o**o\n /.*****\\ | | | *oo*\n //*******\\ | ## | | o**o\n //.|*****.\\\\ | ## \\_______/\n // ||***|.=]==- |______________________\n () |-=*-| #) /\n |----| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=*= | _______\n |.***. . | "" / \\ oo*o\n . ._***** | :. | | o**o\n /******* | | | *oo*\n /*********. | ## | | o*oo\n // *******\\\\ | ## \\_______/\n //. .***** =]==- |______________________\n () |-***|. #) /\n |--*-| |------------------------\n | || | | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n . -=== | _______\n . | X*X | "" / \\ oo*o\n _\\***_ . | :. | | o**o\n . / *****\\ | | | *oo*\n //*******\\ | ## | | o*oo\n // |***** \\\\ . | ## \\_______/\n // ||***| =]==- |______________________\n () |-=*-| #) /\n . |----| |------------------------\n | || | . | (*)\n | || | |\n |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n . | X X | "" / \\ oo*o\n . _\\ * _ | :. | | o**o\n / ***\\\\ . | | | *oo*\n //|*****\\\\ | ## | | o*oo\n . // ||*** \\\\ | ## \\_______/\n // || * | =]==- |______________________\n () |-==-| #) . /\n |----| |------------------------\n | || | | (*)\n . | || | |\n |_||_| . |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n . | X X | "" / \\ oo*o\n _\\ - _ | :. | | o**o\n / /* \\\\ | | | *oo*\n //||*** \\\\ | ## | | o**o\n // || * | \\\\ | ## \\_______/\n // || # | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | . |\n . |_||_| |\n______________[_][__\\_____________________|________________________\n1\n -=== | _______\n . | X X | "" / \\ oo*o\n _\\ - _ | :. | | o**o\n / /# \\\\ | | | *oo*\n //||### \\\\ | ## | | o**o\n // ||###| \\\\ | ## \\_______/\n // || # | =]==- |______________________\n () |-==-| #) /\n |----| |------------------------\n | || | | (*)\n | || | . |\n . |_||_| |\n______________[_][__\\_____________________|________________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n ===- | #### ==== |\n o o"" | {o o"} o o~~ |\n _\\- /_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n4\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n3\n ===- | #### ==== |\n o o"" | {o o"} o o~~ |\n _\\- /_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n1\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n8\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | Between his\n _\\ -/_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n9\n ===- | #### ==== |\n o o"" | {o o"} o o~~ | Between his\n _\\- /_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n7\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | Between his\n _\\ -/_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n7\n ===- | #### ==== |\n o o"" | {o o"} o o~~ | Between his\n _\\- /_ | {= } _\\- /_ | howling and\n / \\ | {~~ //~} / \\ | your blasting\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | everything in\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | sight...\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n1\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n14\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | ...it\'s a\n _\\ -/_ | {= } _\\- /_ | wonder the\n / \\ | {~~ //~} / \\ | whole station\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | doesn\'t know\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | we\'re here!\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n12\n -=== | #### ==== |\n ""o o | {"o o} o o~~ | ...it\'s a\n _\\ -/_ | { =} _\\- /_ | wonder the\n / \\ | {~~ //~} / \\ | whole station\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | doesn\'t know\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | we\'re here!\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n4\n -=== | #### ==== |\n ""o o | {o o"} o o~~ | ...it\'s a\n _\\ -/_ | {= } _\\- /_ | wonder the\n / \\ | {~~ //~} / \\ | whole station\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o | doesn\'t know\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | | we\'re here!\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n1\n -=== | #### ==== |\n ""o o | {o o"} o o~~ |\n _\\ -/_ | {= } _\\- /_ |\n / \\ | {~~ //~} / \\ |\n //| __ |\\\\ __ | {{~{ //}~}} ||/(===o |\n // |/ \\| \\\\ |o=|| {} {// } {} | / \\ | |\n// [][][] || |__|| {} // } {} \\/][][\\/ |\n|\' |\\ /| [# | {} H{{}}} {} |\\ /| |\n |_||_| I] | @ H"||"} @ |_||_| |\n [ ][ ] I | {"||"} [ ][ ] |\n | || | | {"||"} | || | |\n |_||_| | {"||"} |_||_| |\n___/__][_]___________|____[_][_]________/__][_]___|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| We found the | "" / \\ oo*o\n _\\=/_ computer outlet | :. | | o**o\n / \\ sir! ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n2\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\\________\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\\________\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\\________\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\\________\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\\________\n Imperial / /| | |\\ | // |/ \\| \\\\ |*=||\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\\________\n network. || | | | || // [][][] \\\\|__||\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") ~~o o |\n He should be able _\\- /_ _\\ -/_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| \\\\ |o=||\n network. || | | | || // [][][] \\\\|__||\\________\n (\' | | | \') |\' |\\ /| \') |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\\________\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\\________\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\\________\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\\________\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\\________\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|\\________\n13\n ==== ==== |\n Plug in. (o o") o o~~ |\n He should be able _\\- /_ _\\- /_ |\n to interpret / \\ / \\ / \\ |\n the entire / \\/ \\ //| __ |\\\\ __ |\n Imperial / /| | |\\ | // |/ \\| || |o=||\n network. || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / # /\\ \\ *ooo\n _\\=/_ found the main | :. | # / O| | o**o\n / \\ controls to ___ | |###======| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | #____| | o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / ||OO \\ ooo*\n _\\=/_ found the main | :. | ||OO__| o**o\n / \\ controls to ___ | | // ____| o*o*\n //|/.\\|\\\\ the power beam / ()\\ | ## | //##.. | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / ||OO \\ ooo*\n _\\=/_ found the main | :. | ||OO__| o**o\n / \\ controls to ___ | | // ____| o*o*\n //|/.\\|\\\\ the power beam / ()\\ | ## | //##.. | o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | o*o*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" /< \\\\ \\ ooo*\n _\\=/_ found the main | :. | < || | o*o*\n / \\ controls to ___ | |=========| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | OOO> \\\\| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" /< \\\\ \\ ooo*\n _\\=/_ found the main | :. | < || | o*o*\n / \\ controls to ___ | |=========| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | OOO> \\\\| o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found the main | :. | | o*o*\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / | | \\ oo*o\n _\\=/_ found the main | :. |== ====| o*o*\n / \\ controls to ___ | | | |#<> | *o*o\n //|/.\\|\\\\ the power beam / ()\\ | ## |_/ \\___| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o*o*\n / \\ controls to ___ | | | *o*o\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" /_______\\ *o*o\n _\\=/_ found the main | :. |[][][]===| o**o\n / \\ controls to ___ | |_________| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |[][][]===| ***o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" /_______\\ *o*o\n _\\=/_ found the main | :. |[][][]===| o**o\n / \\ controls to ___ | |_________| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |[][][]===| **oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ *o*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | **oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" /--\\ .\\ oo*o\n _\\=/_ found the main | :. | |..\\ . | o**o\n / \\ controls to ___ | | |:: | . | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |=====|. .| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" /--\\ .\\ oo*o\n _\\=/_ found the main | :. | |..\\ . | o**o\n / \\ controls to ___ | | |:: | . | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |=====|. .| o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | o**o\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / || || \\ oo*o\n _\\=/_ found the main | :. |__OO_OO__| o**o\n / \\ controls to ___ | |__ _ __| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | OO OO | oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | o**o\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| He says he\'s | "" / .o. \\ oo*o\n _\\=/_ found the main | :. | o|||o | oooo\n / \\ controls to ___ | | o | o | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |/__/_\\__\\| oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | | oooo\n / \\ controls to ___ | | | *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## | | oo**\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .o. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .*. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .o. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ oo*o\n _\\=/_ found the main | :. | .*. | *ooo\n / \\ controls to ___ | |___ooo___| *oo*\n //|/.\\|\\\\ the power beam / ()\\ | ## |---------| o*oo\n || \\_/ || holding the _|_____|_ | ## \\_______/\n || |\\ /| || ship here. | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .*. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | .o. | *ooo\n / \\ ___ | |___ooo___| *oo*\n //|/.\\|\\\\ / ()\\ | ## |---------| o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n I don\'t think ("o o) o o~~ |\n you boys can help. _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n19\n ==== ==== |\n I don\'t think (o o") o o~~ |\n you boys can help. _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n8\n ==== ==== |\n I must go alone. (o o") o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n15\n ==== ==== |\n I must go alone. ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n25\n ==== I want to ==== |\n ("o o) go with you! o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n4\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n30\n ==== ==== |\n Be patient, Luke. ("o o) o o~~ |\n Stay and watch _\\ -/_ _\\- /_ |\n over the droids. / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n20\n ==== But he can... ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n29\n ==== ==== |\n Your destiny ("o o) o o~~ |\n lies along a _\\ -/_ _\\- /_ |\n different path to / \\ / \\ / \\ |\n mine. / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n2\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n21\n ==== ==== |\n The Force will ("o o) o o~~ |\n be with you... _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n1\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n20\n ==== ==== |\n ("o o) o o~~ |\n ...always! _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n6\n ==== ==== |\n ("o o) o o~~ |\n _\\ -/_ _\\- /_ |\n / \\ / \\ / \\ |\n / \\/ \\ //| __ |\\\\ __ |\n / /| | |\\ | // |/ \\| || |o=||\n || | | | || // [][][] || |__||\n (\' | | | \') |\' |\\ /| \'| |\n | | | |_||_| |\n | |\\ | [ ][ ] |\n / || \\ | || | |\n / ||_|\\ |_||_| |\n__________________/____|[_]_\\______________[_][__\\_______|_________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n17\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n4\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n38\n -=== ####\n Where did ""o o {o o"}\n you dig up _\\ -/_ {= }\n that old / \\ {~~ //~}\n fossil! //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== |\n ~~o o |\n _\\ -/_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n_____________________________________[_][__\\_______|_______________\n3\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n_____________________________________[_][__\\_______|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][__\\_______|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][__\\_______|_______________\n19\n ==== |\n Ben is o o~~ |\n a great man! _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][__\\_______|_______________\n13\n ==== |\n Ben is o o~~ |\n a great man! _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ /() \\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. | | o**o\n / \\ ___ | | | *oo*\n //|/.\\|\\\\ / ()\\ | ## | | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o**o\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ oo*o\n _\\=/_ | :. |__[]_[]__| o**o\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o**o\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\o /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n18\n ==== |\n o o~~ |\n What is it? _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\| || |o=||\n // [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n ==== |\n o o~~ |\n What is it? _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n6\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found her... | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n18\n /~\\ | _______\n ( oo| He says he\'s | "" / \\ ooo*\n _\\=/_ found her... | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n10\n /~\\ | _______\n ( oo| And keeps repeating | "" / \\ ooo*\n _\\=/_ she\'s here. | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n5\n /~\\ | _______\n ( oo| And keeps repeating | "" / \\ ooo*\n _\\=/_ she\'s here. | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n8\n /~\\ | _______\n ( oo| And keeps repeating | "" / \\ ooo*\n _\\=/_ she\'s here. | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n22\n ==== |\n o o~~ |\n Well who... _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n19\n ==== |\n o o~~ |\n who has he found? _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n16\n /~\\ | _______\n ( oo| Princess Leia. | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n4\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n ==== |\n O O~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n3\n ==== |\n O O~~ |\n _\\o /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n11\n ==== |\n o o~~ |\n The princess? _\\- /_ |\n / \\ |\n She\'s here? //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n13\n ==== |\n o o~~ |\n The princess? _\\- /_ |\n / \\ |\n She\'s here? //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n9\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n11\n -=== ####\n ""o o {o o"}\n Princess? _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n10\n -=== ####\n ""o o {"o o}\n Princess? _\\ -/_ { =}\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n5\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ # AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n3\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ # AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| Level 5. | "" / \\ ooo*\n _\\=/_ Detention block | :. |__[]_[]__| o*o*\n / \\ # AA-23. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// / ()\\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ # ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ # termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\// /() \\ | ## | [] [] | o*oo\n || \\_/ \\/ _|_____|_ | ## \\_______/\n || |\\ /| | | === | | |______________________\n # \\_ _/ |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n9\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ /() \\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n7\n /~\\ | _______\n ( oo| I\'m afraid she\'s | "" / \\ ooo*\n _\\=/_ scheduled for | :. |__[]_[]__| o*o*\n / \\ termination. ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n5\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n | | | /=\\ /=\\ /=\\ |\n____/_]_[_\\___________________[_]_[_]_[_]_|________________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n9\n -=== ####\n What are you ""o o {o o"}\n talking _\\ -/_ {= }\n about? # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n9\n -=== ####\n What are you ""o o {"o o}\n talking _\\ -/_ { =}\n about? # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n What are you ""o o {"o o}\n talking _\\ -/_ { =}\n about? / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n |\' [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n5\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n |\' [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n29\n ==== |\n o o~~ |\n She\'s the one _\\- /_ |\n in the message. / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n16\n ==== |\n o o~~ |\n We\'ve got to _\\- /_ |\n help her! / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n17\n ==== |\n o o~~ |\n We\'ve got to _\\- /_ |\n help her! / \\ |\n //| __ |\\\\ __ |\n // |/ \\|// |o=||\n /\' [][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n1\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n // |/ \\|// |o=||\n /\' [][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n8\n -=== ####\n I\'m not ""o o {o o"}\n going anywhere. _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n I\'m not ""o o {"o o}\n going anywhere. _\\ -/_ { =}\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n17\n -=== ####\n I\'m not ""o o {"o o}\n going anywhere. _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n19\n ==== |\n ~~o o |\n _\\ -/_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n5\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n11\n ==== |\n o o~~ |\n She\'s rich... _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n || |/ \\| || |o=||\n || [][][] || |__||\n |\' |\\ /| \'| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n11\n ==== |\n o o~~ |\n She\'s rich... _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n4\n ==== |\n o o~~ |\n _\\- /_ |\n / \\ |\n //| __ |\\\\ __ |\n \\\\|/ \\|// |o=||\n #[][][]# |__||\n |\\ /| |\n |_||_| |\n [ ][ ] |\n | || | |\n |_||_| |\n____________________________________/__][_]________|_______________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n |\' |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n14\n -=== ####\n Rich? ""o o {o o"}\n _\\ -/_ {= }\n # / \\ {~~ //~}\n \\\\//| __ |\\\\ {{~{ //}~}}\n \\/ |/ \\| \\\\ {} {// } {}\n [][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n -=== ####\n Rich? ""o o {o o"}\n _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n3\n -=== ####\n Rich? ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n5\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n What\'s ""o o {o o"}\n your plan? _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n // |/ \\| \\\\ {} {// } {}\n // [][][] || {} // } {}\n # |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n2\n -=== ####\n What\'s ""o o {o o"}\n your plan? _\\ -/_ {= }\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n14\n -=== ####\n What\'s ""o o {"o o}\n your plan? _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n6\n -=== ####\n ""o o {"o o}\n _\\ -/_ { =}\n / \\ {~~ //~}\n //| __ |\\\\ {{~{ //}~}}\n \\\\|/ \\| \\\\ {} {// } {}\n #[][][] || {} // } {}\n |\\ /| [# {} H{{}}} {}\n |_||_| I] @ H"||"} @\n [ ][ ] I {"||"}\n | || | {"||"}\n |_||_| {"||"}\n__________________/__][_]________________[_][_]____________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n -=== #### ====\n ""o o {"o o} o o~~\n _\\ -/_ { =} _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n11\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { =} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o {"O O} I\'m going o o~~\n _\\ -/_ { -} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n2\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { -} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n1\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { O} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n2\n -=== #### ====\n ""o o {"o o} I\'m going O O~~\n _\\ -/_ { O} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\| || {} {// } {} // |/ \\|//\n #[][][] || {} // } {} # [][][]#\n |\\ /| # {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n3\n -=== #### ====\n ""o o {"o o} I\'m going O O~~\n _\\ -/_ { O} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\|//\n #[][][]# {} // } {} # [][][]#\n |\\ /| {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n1\n -=== #### ====\n ""o o {"o o} I\'m going O O~~\n _\\ -/_ { =} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n5\n -=== #### ====\n ""o o {"o o} I\'m going o o~~\n _\\ -/_ { =} to put _\\- /_\n / \\ {~~ //~} these on / \\\n //| __ |\\\\ {{~{ //}~}} you. //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o {"o o} o o~~\n _\\ -/_ { =} _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n10\n -=== #### ====\n ""o o Don\'t worry {"o o} o o~~\n _\\ -/_ Chewie... { =} _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n7\n -=== #### ====\n ""o o Don\'t worry {o o"} o o~~\n _\\ -/_ Chewie... {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n16\n -=== #### ====\n ""o o Don\'t worry {o o"} o o~~\n _\\ -/_ Chewie... {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n2\n -=== #### ====\n ""o o {o o"} o o~~\n _\\ -/_ {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n19\n -=== #### ====\n ""o o I think I {o o"} o o~~\n _\\ -/_ know what {= } _\\- /_\n / \\ he has in {~~ //~} / \\\n //| __ |\\\\ mind. {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\|// {} {// } {} // |/ \\| \\\\\n #[][][]# {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n9\n -=== #### ====\n ""o o I think I {o o"} o o~~\n _\\ -/_ know what {= } _\\- /_\n / \\ he has in {~~ //~} / \\\n //| __ |\\\\ mind. {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| \\\\ {} {// } {} // |/ \\| \\\\\n #[][][] # {} // } {} # [][][] ||\n |\\ /| {} H{{}}} {} [ |\\ /| #\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o I think I {o o"} o o~~\n _\\ -/_ know what {= } _\\- /_\n / \\ he has in {~~ //~} / \\\n //| __ |\\\\ mind. {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| \\\\ {} {// } {} // |/ \\|//\n #[][][] # {} // } {} # [][][]#\n |\\ /| {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n6\n -=== #### ====\n ""o o {o o"} o o~~\n _\\ -/_ {= } _\\- /_\n / \\ {~~ //~} / \\\n //| __ |\\\\ {{~{ //}~}} //| __ |\\\\\n \\\\|/ \\| \\\\ {} {// } {} // |/ \\|//\n #[][][] # {} // } {} # [][][]#\n |\\ /| {} H{{}}} {} [ |\\ /|\n |_||_| @ H"||"} @ [ |_||_|\n [ ][ ] {"||"} [ ][ ]\n | || | {"||"} | || |\n |_||_| {"||"} |_||_|\n____[_][__\\_________________[_][_]__________________/__][_]________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n19\n /~\\ | _______\n ( oo| What should R2 and | "" / \\ ooo*\n _\\=/_ I do if we\'re | :. |__[]_[]__| o*o*\n / \\ discovered ___ | |__ _ __| *oo*\n //|/.\\|\\\\ here? / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n9\n /~\\ | _______\n ( oo| What should R2 and | "" / \\ ooo*\n _\\=/_ I do if we\'re | :. |__[]_[]__| o*o*\n / \\ discovered ___ | |__ _ __| *oo*\n //|/.\\|\\\\ here? / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n6\n /~\\ | _______\n ( oo| | "" / \\ ooo*\n _\\=/_ | :. |__[]_[]__| o*o*\n / \\ ___ | |__ _ __| *oo*\n //|/.\\|\\\\ / ()\\ | ## | [] [] | o*oo\n || \\_/ || _|_____|_ | ## \\_______/\n || |\\ /| || | | === | | |______________________\n # \\_ _/ # |_| O |_| /\n | | | || O || |------------------------\n | | | ||__*__|| | (*)\n []|[] |~ \\___/ ~| |\n |_| | /=\\ /=\\ /=\\ |\n____/_ _[_\\___________________[_]_[_]_[_]_|________________________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n ===- ==== |\n o o"" o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n20\n ===- ==== |\n o o"" Lock the o o~~ |\n _\\- /_ door. _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n7\n ===- ==== |\n o o"" Lock the o o~~ |\n _\\- /_ door. _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // // |/ \\|// |o=||\n # [][][]# # [][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n2\n ===- ==== |\n o o"" o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // // |/ \\|// |o=||\n # [][][]# # [][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n2\n ===- ==== |\n o o"" o o~~ |\n _\\- /_ _\\- /_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n16\n ===- ==== |\n And hope o o"" o o~~ |\n they don\'t _\\- /_ _\\- /_ |\n have / \\ / \\ |\n blasters. //| __ |\\\\ //| __ |\\\\ __ |\n // |/ \\ // \\\\|/ \\|// |o=||\n # [][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n3\n ===- ==== |\n And hope o o"" o o~~ |\n they don\'t _\\- /_ _\\- /_ |\n have / \\ / \\ |\n blasters. //| __ |\\\\ //| __ |\\\\ __ |\n \\\\|/ \\ // \\\\|/ \\|// |o=||\n #[][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]____________________/__][_]________|_________\n10\n ===- ==== |\n And hope o o"" ~~o o |\n they don\'t _\\- /_ _\\ -/_ |\n have / \\ / \\ |\n blasters. //| __ |\\\\ //| __ |\\\\ __ |\n \\\\|/ \\ // \\\\|/ \\|// |o=||\n #[][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]_____________________[_][_]________|_________\n5\n ===- ==== |\n o o"" ~~o o |\n _\\- /_ _\\ -/_ |\n / \\ / \\ |\n //| __ |\\\\ //| __ |\\\\ __ |\n \\\\|/ \\ // \\\\|/ \\|// |o=||\n #[][][]# #[][][]# |__||\n |\\ /| |\\ /| |\n |_||_| |_||_| |\n [ ][ ] [ ][ ] |\n | || | | || | |\n |_||_| |_||_| |\n_______________/__][_]_____________________[_][_]________|_________\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n /~\\\n ( oo|\n _\\=/_\n / \\ ___\n //|/.\\|\\\\ / ()\\\n || \\_/ || _|_____|_\n || |\\ /| || | | === | |\n # \\_ _/ # |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n15\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ ___\n //|/.\\|\\\\ / ()\\\n || \\_/ || _|_____|_\n || |\\ /| || | | === | |\n # \\_ _/ # |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n3\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ # ___\n //|/.\\|\\\\// / ()\\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n8\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ # ___\n //|/.\\|\\\\// /() \\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n11\n /~\\\n That isn\'t very ( oo|\n reassuring. _\\=/_\n / \\ # ___\n //|/.\\|\\\\// / ()\\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n7\n /~\\\n ( oo|\n _\\=/_\n / \\ # ___\n //|/.\\|\\\\// / ()\\\n || \\_/ \\/ _|_____|_\n || |\\ /| | | === | |\n # \\_ _/ |_| O |_|\n | | | || O ||\n | | | ||__*__||\n []|[] |~ \\___/ ~|\n | | | /=\\ /=\\ /=\\\n_________________________/_]_[_\\___[_]_[_]_[_]_____________________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | {"||"} \' | | || |\n |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]_______________[_][_]____________\n2\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | {"||"} \' | | || |\n) |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n- | || | {"||"} \' | | || |\n_) |_||_| {"||"} [_| |_||_|\nO________[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n-- | || | {"||"} \' | | || |\n__) |_||_| {"||"} [_| |_||_|\n_O_______[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n--- | || | {"||"} \' | | || |\n___) |_||_| {"||"} [_| |_||_|\n__O______[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n---- | || | {"||"} \' | | || |\n____) |_||_| {"||"} [_| |_||_|\nO__O_____[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n[____) |_||_| {"||"} [_| |_||_|\n_O__O____[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n [____) |_||_| {"||"} [_| |_||_|\n__O__O___[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n [____) |_||_| {"||"} [_| |_||_|\n___O__O__[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | || | {"||"} \' | | || |\n [____)|_||_| {"||"} [_| |_||_|\n____O__O_[_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----| || | {"||"} \' | | || |\n [____)_||_| {"||"} [_| |_||_|\n_____O__O__][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- || | {"||"} \' | | || |\n [____)||_| {"||"} [_| |_||_|\n______O__O_][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----|| | {"||"} \' | | || |\n [____)|_| {"||"} [_| |_||_|\n_______O__O][_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----| | {"||"} \' | | || |\n [____)_| {"||"} [_| |_||_|\n________O__O[_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- | {"||"} \' | | || |\n [____)| {"||"} [_| |_||_|\n_________O__O_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |----| {"||"} \' | | || |\n [____) {"||"} [_| |_||_|\n_________[O__O]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | ---- {"||"} \' | | || |\n |[____) {"||"} [_| |_||_|\n_________[_O__O_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | |---- {"||"} \' | | || |\n | [____) {"||"} [_| |_||_|\n_________[_]O__O____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | ||---- {"||"} \' | | || |\n | |[____) {"||"} [_| |_||_|\n_________[_]_O__O___________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || ---- {"||"} \' | | || |\n | ||[____) {"||"} [_| |_||_|\n_________[_][_O__O__________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || |---- {"||"} \' | | || |\n | || [____) {"||"} [_| |_||_|\n_________[_][_]O__O_________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || |[____) {"||"} [_| |_||_|\n_________[_][_]_O__O________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]__O__O_______[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]___O__O______[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n2\n /__\\ #### /__\\\n | <><| {O O"} . |><> |\n (__/\\) {= } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n14\n /__\\ #### /__\\\n | <><| Grrrrrr! {O O"} . |><> |\n (__/\\) {0 } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n4\n /__\\ #### /__\\\n | <><| Grrrrrr! {o o"} . |><> |\n (__/\\) {0 } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]____O__O_____[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]______O__O___[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | [____) {"||"} [_| |_||_|\n_________[_][_]_______O__O__[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | (____] {"||"} [_| |_||_|\n_________[_][_]_______O__O__[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | (____] {"||"} [_| |_||_|\n_________[_][_]_____O__O____[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) { -} | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || | (____] {"||"} [_| |_||_|\n_________[_][_]___O__O______[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) --{ -}-- | (/\\__)\n / \\ { // } I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || | ---- {"||"} \' | | || |\n | || |(____] {"||"} [_| |_||_|\n_________[_][_]_O__O________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) --{ -}-- | (/\\__)\n / \\ { // } I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | || ---- {"||"} \' | | || |\n | ||(____] {"||"} [_| |_||_|\n_________[_][_O__O__________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) --{ -}-- | (/\\__)\n / \\ { // } I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n | |---- {"||"} \' | | || |\n | (____] {"||"} [_| |_||_|\n_________[_]O__O____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n | <><| {"o o} . |><> |\n (__/\\) { -} | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |----| {"||"} \' | | || |\n (____] {"||"} [_| |_||_|\n_________[O__O]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----| | {"||"} \' | | || |\n (____]_| {"||"} [_| |_||_|\n________O__O[_]_____________[_][_]_______________[_][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ----_|| | {"||"} \' | | || |\n (____]||_| {"||"} [_| |_||_|\n______O__O_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- |_|| | {"||"} \' | | || |\n (____]|_||_| {"||"} [_| |_||_|\n____O__O_[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n |><> | {o o"} . |><> |\n (/\\__) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n ---- |_|| | {"||"} \' | | || |\n (____] |_||_| {"||"} [_| |_||_|\n__O__O___[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n---- |_|| | {"||"} \' | | || |\n____] |_||_| {"||"} [_| |_||_|\nO__O_____[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n-- |_|| | {"||"} \' | | || |\n__] |_||_| {"||"} [_| |_||_|\n_O_______[_][_]_____________[_][_]______________/__][_]____________\n1\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |_|| | {"||"} \' | | || |\n] |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]______________/__][_]____________\n4\n /__\\ #### /__\\\n | <><| {o o"} . |><> |\n (__/\\) {- } | (/\\__)\n / \\ {~~ //~} I / \\\n ||/(===o {}{ //}{} I || __ |\\\\\n | / \\ | {}{// {} (I// / \\| ||\n \\/][][\\/ {}/ {} ,]/ [][][] ||\n |\\ /| {}@@{} [] |\\ /| \'\n |_||_| H"||"} [] |_||_|\n [ ][ ] {"||"} /| [ ][ ]\n |_|| | {"||"} \' | | || |\n |_||_| {"||"} [_| |_||_|\n_________[_][_]_____________[_][_]______________/__][_]____________\n5\n\n\n\n\n\n\n\n\n\n\n\n\n\n9\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) {= } . (/\\__) |\n | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n11\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {o o"} |><> | |\n thing in this | (__/\\) {= } . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n6\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} |><> | |\n thing in this | (__/\\) { =} . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n3\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} | <><| |\n thing in this | (__/\\) { =} . (__/\\) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n14\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} | <><| |\n thing in this | (__/\\) { =} . (__/\\) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][__\\__|______________\n9\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} |><> | |\n thing in this | (__/\\) { =} . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|__[_][_]___|______________\n6\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {"o o} |><> | |\n thing in this | (__/\\) { =} . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]___|______________\n7\n | /__\\ #### /__\\ |\n I can\'t see a | | <><| {o o"} |><> | |\n thing in this | (__/\\) {= } . (/\\__) |\n helmet. | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]___|______________\n6\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) {= } . (/\\__) |\n | / \\ {~~ //~} | / \\ |\n | ||/(===o {}{ //}{} I || __ |\\\\ |\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \' |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ ] |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]___|______________\n1\n | /__\\ #### /__\\ ||\n | | <><| {o o"} |><> | ||\n | (__/\\) {= } . (/\\__) ||\n | / \\ {~~ //~} | / \\ ||\n | ||/(===o {}{ //}{} I || __ |\\\\||\n | | / \\ | {}{// {} I// / \\| |||\n | \\/][][\\/ {}/ {} (I/ [][][] |||\n | |\\ /| {}@@{} ,] |\\ /| \'||\n | |_||_| H"||"} [] |_||_| ||\n | [ ][ ] {"||"} [] [ ][ ] ||\n | | || | {"||"} /| | || | ||\n | |_||_| {"||"} \' | |_||_| ||\n________________|__[_][_]_____[_][_]__[_|_/__][_]__||______________\n1\n | /__\\ #### /__\\ | |\n | | <><| {o o"} |><> | | |\n | (__/\\) {= } . (/\\__) | |\n | / \\ {~~ //~} | / \\| |\n | ||/(===o {}{ //}{} I || __ |\\| |\n | | / \\ | {}{// {} I// / \\| | |\n | \\/][][\\/ {}/ {} (I/ [][][] | |\n | |\\ /| {}@@{} ,] |\\ /| | |\n | |_||_| H"||"} [] |_||_| | |\n | [ ][ ] {"||"} [] [ ][ ] | |\n | | || | {"||"} /| | || | | |\n | |_||_| {"||"} \' | |_||_| | |\n________________|__[_][_]_____[_][_]__[_|_/__][_]_|_|______________\n1\n | /__\\ #### /__\\ | |\n | | <><| {o o"} |><> || |\n | (__/\\) {= } . (/\\__)| |\n | / \\ {~~ //~} | / | |\n | ||/(===o {}{ //}{} I || __ || |\n | | / \\ | {}{// {} I// / \\|| |\n | \\/][][\\/ {}/ {} (I/ [][][]| |\n | |\\ /| {}@@{} ,] |\\ /|| |\n | |_||_| H"||"} [] |_||_|| |\n | [ ][ ] {"||"} [] [ ][ ]| |\n | | || | {"||"} /| | || || |\n | |_||_| {"||"} \' | |_||_|| |\n________________|__[_][_]_____[_][_]__[_|_/__][_]|__|______________\n1\n | /__\\ #### /__\\| |\n | | <><| {o o"} |><> | |\n | (__/\\) {= } . (/\\__| |\n | / \\ {~~ //~} | / | |\n | ||/(===o {}{ //}{} I || __ | |\n | | / \\ | {}{// {} I// / \\| |\n | \\/][][\\/ {}/ {} (I/ [][][| |\n | |\\ /| {}@@{} ,] |\\ /| |\n | |_||_| H"||"} [] |_||_| |\n | [ ][ ] {"||"} [] [ ][ | |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_||_| |\n________________|__[_][_]_____[_][_]__[_|_/__][_|___|______________\n1\n | /__\\ #### /__| |\n | | <><| {o o"} |><>| ||\n | (__/\\) {= } . (/\\_| ||\n | / \\ {~~ //~} | / | ||\n | ||/(===o {}{ //}{} I || __| ||\n | | / \\ | {}{// {} I// / | ||\n | \\/][][\\/ {}/ {} (I/ [][]| |\n | |\\ /| {}@@{} ,] |\\ | ||\n | |_||_| H"||"} [] |_||| ||\n | [ ][ ] {"||"} [] [ ][| ||\n | | || | {"||"} /| | ||| ||\n | |_||_| {"||"} \' | |_||| ||\n________________|__[_][_]_____[_][_]__[_|_/__][|____|______________\n1\n | /__\\ #### /_| _|\n | | <><| {o o"} |><| | |\n | (__/\\) {= } . (/\\| | |\n | / \\ {~~ //~} | / | | |\n | ||/(===o {}{ //}{} I || _| | |\n | | / \\ | {}{// {} I// / | |_|\n | \\/][][\\/ {}/ {} (I/ [][| _|\n | |\\ /| {}@@{} ,] |\\ | | |\n | |_||_| H"||"} [] |_|| | |\n | [ ][ ] {"||"} [] [ ]| | |\n | | || | {"||"} /| | || | |\n | |_||_| {"||"} \' | |_|| |_|\n________________|__[_][_]_____[_][_]__[_|_/__]|_____|______________\n1\n | /__\\ #### /| _ |\n | |><> | {o o"} |>| | ||\n | (/\\__) {= } . (/| | ||\n | / \\ {~~ //~} | / | | ||\n | ||/(===o {}{ //}{} I || | | ||\n | | / \\ | {}{// {} I// /| |_||\n | \\/][][\\/ {}/ {} (I/ []| _ |\n | |\\ /| {}@@{} ,] |\\| | ||\n | |_||_| H"||"} [] |_| | ||\n | [ ][ ] {"||"} [] [ | | ||\n | | || | {"||"} /| | | | ||\n | |_||_| {"||"} \' | |_| |_||\n________________|__[_][_]_____[_][_]__[_|_/__|______|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} || | | |\n | (/\\__) {= } . (| | | |\n | / \\ {~~ //~} | / | | | |\n | ||/(===o {}{ //}{} I ||| | | |\n | | / \\ | {}{// {} I// | |_| |\n | \\/][][\\/ {}/ {} (I/ [| _ |\n | |\\ /| {}@@{} ,] || | | |\n | |_||_| H"||"} [] || | | |\n | [ ][ ] {"||"} [] [| | | |\n | | || | {"||"} /| || | | |\n | |_||_| {"||"} \' | || |_| |\n________________|__[_][_]_____[_][_]__[_|_/_|_______|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } . | | | |\n | / \\ {~~ //~} | /| | | |\n | ||/(===o {}{ //}{} I || | | |\n | | / \\ | {}{// {} I//| |_| |\n | \\/][][\\/ {}/ {} (I/ | _ |\n | |\\ /| {}@@{} ,] | | | |\n | |_||_| H"||"} [] | | | |\n | [ ][ ] {"||"} [] | | | |\n | | || | {"||"} /| | | | |\n | |_||_| {"||"} \' | | |_| |\n________________|__[_][_]_____[_][_]__[_|_/|________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } . | | | |\n | / \\ {~~ //~} | | | | |\n | ||/(===o {}{ //}{} I | | | |\n | | / \\ | {}{// {} I/| |_| |\n | \\/][][\\/ {}/ {} (I/| _ |\n | |\\ /| {}@@{} ,] | | | |\n | |_||_| H"||"} [] | | | |\n | [ ][ ] {"||"} [] | | | |\n | | || | {"||"} /| | | | |\n | |_||_| {"||"} \' | | |_| |\n________________|__[_][_]_____[_][_]__[_|_|_________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } .| | | |\n | / \\ {~~ //~} || | | |\n | ||/(===o {}{ //}{} I| | | |\n | | / \\ | {}{// {} I| |_| |\n | \\/][][\\/ {}/ {} (I| _ |\n | |\\ /| {}@@{} ,]| | | |\n | |_||_| H"||"} []| | | |\n | [ ][ ] {"||"} []| | | |\n | | || | {"||"} /|| | | |\n | |_||_| {"||"} \' || |_| |\n________________|__[_][_]_____[_][_]__[_||__________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } | | | |\n | / \\ {~~ //~} | | | |\n | ||/(===o {}{ //}{} | | | |\n | | / \\ | {}{// {} | |_| |\n | \\/][][\\/ {}/ {} (| _ |\n | |\\ /| {}@@{} ,| | | |\n | |_||_| H"||"} [| | | |\n | [ ][ ] {"||"} [| | | |\n | | || | {"||"} /| | | |\n | |_||_| {"||"} \' | |_| |\n________________|__[_][_]_____[_][_]__[_|___________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } | | | |\n | / \\ {~~ //~} | | | |\n | ||/(===o {}{ //}{} | | | |\n | | / \\ | {}{// {} | |_| |\n | \\/][][\\/ {}/ {} | _ |\n | |\\ /| {}@@{} | | | |\n | |_||_| H"||"} | | | |\n | [ ][ ] {"||"} | | | |\n | | || | {"||"} | | | |\n | |_||_| {"||"} \'| |_| |\n________________|__[_][_]_____[_][_]__[|____________|______________\n1\n | /__\\ #### | _ |\n | |><> | {o o"} | | | |\n | (/\\__) {= } | | | |\n | / \\ {~~ //~}| | | |\n | ||/(===o {}{ //}{}| | | |\n | | / \\ | {}{// {}| |_| |\n | \\/][][\\/ {}/ {} | _ |\n | |\\ /| {}@@{} | | | |\n | |_||_| H"||"} | | | |\n | [ ][ ] {"||"} | | | |\n | | || | {"||"} | | | |\n | |_||_| {"||"} | |_| |\n________________|__[_][_]_____[_][_]__|_____________|______________\n1\n | /__\\ #### | _ |\n | |><> | {"o o} | | | |\n | (/\\__) { =} | | | |\n | / \\ {~~ //~| | | |\n | ||/(===o {}{ //}{| | | |\n | | / \\ | {}{// {| |_| |\n | \\/][][\\/ {}/ {}| _ |\n | |\\ /| {}@@{} | | | |\n | |_||_| H"||"} | | | |\n | [ ][ ] {"||"} | | | |\n | | || | {"||"} | | | |\n | |_||_| {"||"} | |_| |\n________________|__[_][_]_____[_][_]_|______________|______________\n1\n | /__\\ #### | _ |\n | |><> | {"o o}| | | |\n | (/\\__) { =} | | | |\n | / \\ {~~ //| | | |\n | ||/(===o {}{ //}| | | |\n | | / \\ | {}{// | |_| |\n | \\/][][\\/ {}/ {| _ |\n | |\\ /| {}@@{}| | | |\n | |_||_| H"||"}| | | |\n | [ ][ ] {"||"}| | | |\n | | || | {"||"}| | | |\n | |_||_| {"||"}| |_| |\n________________|__[_][_]_____[_][_]|_______________|______________\n1\n | /__\\ ####| _ |\n | |><> | {"o o| | | |\n | (/\\__) { =}| | | |\n | / \\ {~~ /| | | |\n | ||/(===o {}{ //| | | |\n | | / \\ | {}{// | |_| |\n | \\/][][\\/ {}/ | _ |\n | |\\ /| {}@@{| | | |\n | |_||_| H"||"| | | |\n | [ ][ ] {"||"| | | |\n | | || | {"||"| | | |\n | |_||_| {"||"| |_| |\n________________|__[_][_]_____[_][_|________________|______________\n1\n | /__\\ ###| _ |\n | |><> | {o o| | | |\n | (/\\__) {= | | | |\n | / \\ {~~ | | | |\n | ||/(===o {}{ /| | | |\n | | / \\ | {}{// | |_| |\n | \\/][][\\/ {}/ | _ |\n | |\\ /| {}@@| | | |\n | |_||_| H"||| | | |\n | [ ][ ] {"||| | | |\n | | || | {"||| | | |\n | |_||_| {"||| |_| |\n________________|__[_][_]_____[_][|_________________|______________\n1\n | /__\\ ##| _ |\n | |><> | {o | | | |\n | (/\\__) {=| | | |\n | / \\ {~~ | | | |\n | ||/(===o {}{ | | | |\n | | / \\ | {}{//| |_| |\n | \\/][][\\/ {}/ | _ |\n | |\\ /| {}@| | | |\n | |_||_| H"|| | | |\n | [ ][ ] {"|| | | |\n | | || | {"|| | | |\n | |_||_| {"|| |_| |\n________________|__[_][_]_____[_]|__________________|______________\n1\n | /__\\ #| _ |\n | |><> | {o| | | |\n | (/\\__) {| | | |\n | / \\ {~~ | | | |\n | ||/(===o {}{ | | | |\n | | / \\ | {}{/| |_| |\n | \\/][][\\/ {}/| _ |\n | |\\ /| {}| | | |\n | |_||_| H"| | | |\n | [ ][ ] {"| | | |\n | | || | {"| | | |\n | |_||_| {"| |_| |\n________________|__[_][_]_____[_|___________________|______________\n1\n | /__\\ | _ |\n | |><> | {| | | |\n | (/\\__) | | | |\n | / \\ {~~| | | |\n | ||/(===o {}{| | | |\n | | / \\ | {}{| |_| |\n | \\/][][\\/ {}| _ |\n | |\\ /| {| | | |\n | |_||_| H| | | |\n | [ ][ ] {| | | |\n | | || | {| | | |\n | |_||_| {| |_| |\n________________|__[_][_]_____[|____________________|______________\n1\n | /__\\ | _ |\n | |><> | | | | |\n | (/\\__) | | | |\n | / \\ {~| | | |\n | ||/(===o {}| | | |\n | | / \\ | {}| |_| |\n | \\/][][\\/ {| _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]_____|_____________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\ {| | | |\n | ||/(===o {| | | |\n | | / \\ | {| |_| |\n | \\/][][\\/ | _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]____|______________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\ | | | |\n | ||/(===o | | | |\n | | / \\ | | |_| |\n | \\/][][\\/ | _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]___|_______________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\ | | | |\n | ||/(===o | | | |\n | | / \\ | | |_| |\n | \\/][][\\/ | _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]__|________________________|______________\n1\n | /__\\ | _ |\n | | <><| | | | |\n | (__/\\) | | | |\n | / \\| | | |\n | ||/(===o| | | |\n | | / \\ || |_| |\n | \\/][][\\/| _ |\n | |\\ /| | | | |\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | |_||_| | |_| |\n________________|__[_][_]_|_________________________|______________\n1\n | /__\\ | _ |\n | | <><|| | | |\n | (__/\\)| | | |\n | / | | | |\n | ||/(===| | | |\n | | / \\ | |_| |\n | \\/][][\\| _ |\n | |\\ /|| | | |\n | |_||_|| | | |\n | [ ][ ]| | | |\n | | || || | | |\n | |_||_|| |_| |\n________________|__[_][_]|__________________________|______________\n1\n | /__\\| _ |\n | | <><| | | |\n | (__/\\| | | |\n | / | | | |\n | ||/(==| | | |\n | | / \\| |_| |\n | \\/][][| _ |\n | |\\ /| | | |\n | |_||_| | | |\n | [ ][ | | | |\n | | || | | | |\n | |_||_| |_| |\n________________|__[_][_|___________________________|______________\n1\n | /__| _ |\n | | <>| | | |\n | (__/| | | |\n | / | | | |\n | ||/(=| | | |\n | | / | |_| |\n | \\/][]| _ |\n | |\\ | | | |\n | |_||| | | |\n | [ ][| | | |\n | | ||| | | |\n | |_||| |_| |\n________________|__[_][|____________________________|______________\n1\n | /_| _ |\n | | <| | | |\n | (__| | | |\n | / | | | |\n | ||/(| | | |\n | | / | |_| |\n | \\/][| _ |\n | |\\ | | | |\n | |_|| | | |\n | [ ]| | | |\n | | || | | |\n | |_|| |_| |\n________________|__[_]|_____________________________|______________\n1\n | /| _ |\n | | | | | |\n | (_| | | |\n | / | | | |\n | ||/| | | |\n | | /| |_| |\n | \\/]| _ |\n | |\\| | | |\n | |_| | | |\n | [ | | | |\n | | | | | |\n | |_| |_| |\n________________|__[_|______________________________|______________\n1\n | | _ |\n | || | | |\n | (| | | |\n | / | | | |\n | ||| | | |\n | | | |_| |\n | \\/| _ |\n | || | | |\n | || | | |\n | [| | | |\n | || | | |\n | || |_| |\n________________|__[|_______________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | /| | | |\n | || | | |\n | || |_| |\n | \\| _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|__|________________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|_|_________________________________|______________\n1\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n________________||__________________________________|______________\n1\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n________________|___________________________________|______________\n2\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n________________|___________________________________|______________\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n | _ |\n | | | |\n | | | |\n | | | |\n | | | |\n | |_| |\n________________|___________________________________|______________\n1\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n || _ |\n || | | |\n || | | |\n || | | |\n || | | |\n || |_| |\n________________||__________________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n | | _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|_|_________________________________|______________\n1\n | | _ |\n | | | | |\n | | | | |\n | /| | | |\n | || | | |\n | || |_| |\n | \\| _ |\n | | | | |\n | | | | |\n | | | | |\n | | | | |\n | | |_| |\n________________|__|________________________________|______________\n1\n | | _ |\n | || | | |\n | (| | | |\n | / | | | |\n | ||| | | |\n | ||| |_| |\n | \\[| _ |\n | || | | |\n | || | | |\n | [| | | |\n | || | | |\n | || |_| |\n________________|__[|_______________________________|______________\n1\n | /| _ |\n | | | | | |\n | (_| | | |\n | / -| | | |\n | ||O| | | |\n | ||-| |_| |\n | \\[(| _ |\n | |\\| | | |\n | | | | | |\n | [ | | | |\n | | | | | |\n | | | |_| |\n________________|__[_|______________________________|______________\n1\n | /_| _ |\n | | | | | |\n | (__| | | |\n | / --| | | |\n | ||O!| | | |\n | ||--| |_| |\n | \\[(_| _ |\n | |\\ | | | |\n | | || | | |\n | [ ]| | | |\n | | || | | |\n | | || |_| |\n________________|__[_]|_____________________________|______________\n1\n | /__| _ |\n | | | | | |\n | (___| | | |\n | / ---| | | |\n | ||O!L| | | |\n | ||---| |_| |\n | \\[(_(| _ |\n | |\\ | | | |\n | | ||| | | |\n | [ ][| | | |\n | | ||| | | |\n | | ||| |_| |\n________________|__[_][|____________________________|______________\n1\n | /__\\| _ |\n | | | | | |\n | (____| | | |\n | / ----| | | |\n | ||O!L|| | | |\n | ||----| |_| |\n | \\[(_()| _ |\n | |\\ /| | | |\n | | || | | | |\n | [ ][ | | | |\n | | || | | | |\n | | || | |_| |\n________________|__[_][_|___________________________|______________\n1\n | /__\\ | _ |\n | | || | | |\n | (____)| | | |\n | / ---- | | | |\n | ||O!L||| | | |\n | ||----|| |_| |\n | \\[(_()]| _ |\n | |\\ /|| | | |\n | | || || | | |\n | [ ][ ]| | | |\n | | || || | | |\n | | || || |_| |\n________________|__[_][__|__________________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) | | | |\n | / ---- \\| | | |\n | ||O!L|||| | | |\n | ||----|\\| |_| |\n | \\[(_()] | _ |\n | |\\ /| | | | |\n | | || | | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | | || | | |_| |\n________________|__[_][__\\|_________________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) | | | |\n | / ---- \\ | | | |\n | ||O!L||| | | | |\n | ||----|\\\\| |_| |\n | \\[(_()] \\| _ |\n | |\\ /| | | | |\n | | || | | | | |\n | [ ][ ] | | | |\n | | || | | | | |\n | | || | | |_| |\n________________|__[_][__\\_|________________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) .| | | |\n | / ---- \\ || | | |\n | ||O!L||| I| | | |\n | ||----|\\\\I| |_| |\n | \\[(_()] \\I| _ |\n | |\\ /| [| | | |\n | | || | [| | | |\n | [ ][ ] [| | | |\n | | || | || | | |\n | | || | || |_| |\n________________|__[_][__\\_||_______________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | | | | |\n | ||O!L||| I | | | |\n | ||----|\\\\I | |_| |\n | \\[(_()] \\I)| _ |\n | |\\ /| [,| | | |\n | | || | []| | | |\n | [ ][ ] []| | | |\n | | || | |\\| | | |\n | | || | | | |_| |\n________________|__[_][__\\_|_|______________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | | | | |\n | ||O!L||| I | | | |\n | ||----|\\\\I | |_| |\n | \\[(_()] \\I) | _ |\n | |\\ /| [, | | | |\n | | || | [] | | | |\n | [ ][ ] [] | | | |\n | | || | |\\ | | | |\n | | || | | \'| |_| |\n________________|__[_][__\\_|_]|_____________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | {| | | |\n | ||O!L||| I {| | | |\n | ||----|\\\\I {| |_| |\n | \\[(_()] \\I) | _ |\n | |\\ /| [, | | | |\n | | || | [] | | | |\n | [ ][ ] [] | | | |\n | | || | |\\ | | | |\n | | || | | \' | |_| |\n________________|__[_][__\\_|_]_|____________________|______________\n1\n | /__\\ | _ |\n | | | | | | |\n | (____) . | | | |\n | / ---- \\ | {~| | | |\n | ||O!L||| I {}| | | |\n | ||----|\\\\I {}| |_| |\n | \\[(_()] \\I) {| _ |\n | |\\ /| [, | | | |\n | | || | [] | | | |\n | [ ][ ] [] | | | |\n | | || | |\\ | | | |\n | | || | | \' | |_| |\n________________|__[_][__\\_|_]__|___________________|______________\n1\n | /__\\ | _ |\n | | | {| | | |\n | (____) . | | | |\n | / ---- \\ | {~\\| | | |\n | ||O!L||| I {}{| | | |\n | ||----|\\\\I {}{| |_| |\n | \\[(_()] \\I) {}| _ |\n | |\\ /| [, {| | | |\n | | || | [] {| | | |\n | [ ][ ] [] {| | | |\n | | || | |\\ {| | | |\n | | || | | \' {| |_| |\n________________|__[_][__\\_|_]__[|__________________|______________\n1\n | /__\\ #| _ |\n | | | {"| | | |\n | (____) . {| | | |\n | / ---- \\ | {~\\\\| | | |\n | ||O!L||| I {}{\\| | | |\n | ||----|\\\\I {}{~| |_| |\n | \\[(_()] \\I) {}~| _ |\n | |\\ /| [, {~| | | |\n | | || | [] {"| | | |\n | [ ][ ] [] {"| | | |\n | | || | |\\ {"| | | |\n | | || | | \' {"| |_| |\n________________|__[_][__\\_|_]__[_|_________________|______________\n1\n | /__\\ ##| _ |\n | | | {""| | | |\n | (____) . {"| | | |\n | / ---- \\ | {~\\\\~| | | |\n | ||O!L||| I {}{\\\\| | | |\n | ||----|\\\\I {}{~\\| |_| |\n | \\[(_()] \\I) {}~~| _ |\n | |\\ /| [, {~~| | | |\n | | || | [] {"|| | | |\n | [ ][ ] [] {"|| | | |\n | | || | |\\ {"|| | | |\n | | || | | \' {"|| |_| |\n________________|__[_][__\\_|_]__[_]|________________|______________\n1\n | /__\\ ###| _ |\n | | | {"""| | | |\n | (____) . {""| | | |\n | / ---- \\ | {~\\\\~~| | | |\n | ||O!L||| I {}{\\\\~| | | |\n | ||----|\\\\I {}{~\\\\| |_| |\n | \\[(_()] \\I) {}~~\\| _ |\n | |\\ /| [, {~~~| | | |\n | | || | [] {"||| | | |\n | [ ][ ] [] {"||| | | |\n | | || | |\\ {"||| | | |\n | | || | | \' {"||| |_| |\n________________|__[_][__\\_|_]__[_][|_______________|______________\n1\n | /__\\ ####| _ |\n | | | {""""| | | |\n | (____) . {""}| | | |\n | / ---- \\ | {~\\\\~~~| | | |\n | ||O!L||| I {}{\\\\~~| | | |\n | ||----|\\\\I {}{~\\\\~| |_| |\n | \\[(_()] \\I) {}~~\\\\| _ |\n | |\\ /| [, {~~~\\| | | |\n | | || | [] {"||"| | | |\n | [ ][ ] [] {"||"| | | |\n | | || | |\\ {"||"| | | |\n | | || | | \' {"||"| |_| |\n________________|__[_][__\\_|_]__[_][_|______________|______________\n1\n | /__\\ #### | _ |\n | | | {""""}| | | |\n | (____) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~| | | |\n | ||O!L||| I {}{\\\\~~~| | | |\n | ||----|\\\\I {}{~\\\\~~| |_| |\n | \\[(_()] \\I) {}~~\\\\{| _ |\n | |\\ /| [, {~~~\\}| | | |\n | | || | [] {"||"}| | | |\n | [ ][ ] [] {"||"}| | | |\n | | || | |\\ {"||"}| | | |\n | | || | | \' {"||"}| |_| |\n________________|__[_][__\\_|_]__[_][_]|_____________|______________\n1\n | /__\\ #### | _ |\n | | | {""""} | | | |\n | (____) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~| | | |\n | ||O!L||| I {}{\\\\~~~{| | | |\n | ||----|\\\\I {}{~\\\\~~{| |_| |\n | \\[(_()] \\I) {}~~\\\\{}| _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]_|____________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~}| | | |\n | ||O!L||| I {}{\\\\~~~{}| | | |\n | ||----|\\\\I {}{~\\\\~~{}| |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]__|___________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} | | | |\n | ||O!L||| I {}{\\\\~~~{} | | | |\n | ||----|\\\\I {}{~\\\\~~{} | |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]___|__________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} | | | |\n | ||O!L||| I {}{\\\\~~~{} | | | |\n | ||----|\\\\I {}{~\\\\~~{} | |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]____|_________|______________\n1\n | /__\\ #### | _ |\n | | <| {""""} | | | |\n | (___/) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} | | | |\n | ||O!L||| I {}{\\\\~~~{} /| | | |\n | ||----|\\\\I {}{~\\\\~~{} \\| |_| |\n | \\[(_()] \\I) {}~~\\\\{} | _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]_____|________|______________\n1\n | /__\\ #### | _ |\n | | | {""""} | | | |\n | (____) . {""} | | | |\n | / ---- \\ | {~\\\\~~~~~} /| | | |\n | ||O!L||| I {}{\\\\~~~{} / | | | |\n | ||----|\\\\I {}{~\\\\~~{} \\\\| |_| |\n | \\[(_()] \\I) {}~~\\\\{} \\| _ |\n | |\\ /| [, {~~~\\} | | | |\n | | || | [] {"||"} | | | |\n | [ ][ ] [] {"||"} | | | |\n | | || | |\\ {"||"} | | | |\n | | || | | \' {"||"} | |_| |\n________________|__[_][__\\_|_]__[_][_]______|_______|______________\n1\n | /__\\ #### | _ |\n | | | {""""} || | | |\n | (____) . {""} (| | | |\n | / ---- \\ | {~\\\\~~~~~} / | | | |\n | ||O!L||| I {}{\\\\~~~{} / || | | |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|| |_| |\n | \\[(_()] \\I) {}~~\\\\{} \\[| _ |\n | |\\ /| [, {~~~\\} || | | |\n | | || | [] {"||"} || | | |\n | [ ][ ] [] {"||"} [| | | |\n | | || | |\\ {"||"} || | | |\n | | || | | \' {"||"} || |_| |\n________________|__[_][__\\_|_]__[_][_]______[|______|______________\n1\n | /__\\ #### /| _ |\n | | | {""""} | | | ||\n | (____) . {""} (_| | ||\n | / ---- \\ | {~\\\\~~~~~} / -| | ||\n | ||O!L||| I {}{\\\\~~~{} / |O| | ||\n | ||----|\\\\I {}{~\\\\~~{} \\\\|-| |_||\n | \\[(_()] \\I) {}~~\\\\{} \\[(| _ |\n | |\\ /| [, {~~~\\} |\\| | ||\n | | || | [] {"||"} | | | ||\n | [ ][ ] [] {"||"} [ | | ||\n | | || | |\\ {"||"} | | | ||\n | | || | | \' {"||"} | | |_||\n________________|__[_][__\\_|_]__[_][_]______[_|_____|______________\n1\n | /__\\ #### /_| _|\n | | | {""""} | | | |\n | (____) . {""} (__| | |\n | / ---- \\ | {~\\\\~~~~~} / --| | |\n | ||O!L||| I {}{\\\\~~~{} / |O!| | |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|--| |_|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_| _|\n | |\\ /| [, {~~~\\} |\\ | | |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ]| | |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || |_|\n________________|__[_][__\\_|_]__[_][_]______[_]|____|______________\n1\n | /__\\ #### /__| |\n | | | {""""} | | ||\n | (____) . {""} (___| ||\n | / ---- \\ | {~\\\\~~~~~} / ---| ||\n | ||O!L||| I {}{\\\\~~~{} / |O!L| ||\n | ||----|\\\\I {}{~\\\\~~{} \\\\|---| ||\n | \\[(_()] \\I) {}~~\\\\{} \\[(_(| |\n | |\\ /| [, {~~~\\} |\\ | ||\n | | || | [] {"||"} | ||| ||\n | [ ][ ] [] {"||"} [ ][| ||\n | | || | |\\ {"||"} | ||| ||\n | | || | | \' {"||"} | ||| ||\n________________|__[_][__\\_|_]__[_][_]______[_][|___|______________\n1\n | /__\\ #### /__\\| |\n | | | {""""} | | |\n | (____) . {""} (____| |\n | / ---- \\ | {~\\\\~~~~~} / ----| |\n | ||O!L||| I {}{\\\\~~~{} / |O!L|| |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----| |\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()| |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ | |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_|__|______________\n1\n | /__\\ #### /__\\ | |\n | | | {""""} | || |\n | (____) . {""} (____)| |\n | / ---- \\ | {~\\\\~~~~~} / ---- | |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||| |\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|| |\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]| |\n | |\\ /| [, {~~~\\} |\\ /|| |\n | | || | [] {"||"} | || || |\n | [ ][ ] [] {"||"} [ ][ ]| |\n | | || | |\\ {"||"} | || || |\n | | || | | \' {"||"} | || || |\n________________|__[_][__\\_|_]__[_][_]______[_][_]|_|______________\n1\n | /__\\ #### /__\\ ||\n | | | {""""} | | ||\n | (____) . {""} (____) ||\n | / ---- \\ | {~\\\\~~~~~} / ---- \\||\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\||\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|/||\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/||\n | |\\ /| [, {~~~\\} |\\ /| ||\n | | || | [] {"||"} | || | ||\n | [ ][ ] [] {"||"} [ ][ ] ||\n | | || | |\\ {"||"} | || | ||\n | | || | | \' {"||"} | || | ||\n________________|__[_][__\\_|_]__[_][_]______[_][_]_||______________\n1\n | /__\\ #### /__\\ |\n | | | {""""} | | |\n | (____) . {""} (____) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n2\n | /__\\ #### /__\\ |\n | | <><| {""""} | | |\n | (__/\\) . {""} (____) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n1\n | /__\\ #### /__\\ |\n | | <><| {o o"} | | |\n | (__/\\) . {= } (____) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n4\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) . {= } (/\\__) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} / |O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} \\\\|----|//|\n | \\[(_()] \\I) {}~~\\\\{} \\[(_()]/ |\n | |\\ /| [, {~~~\\} |\\ /| |\n | | || | [] {"||"} | || | |\n | [ ][ ] [] {"||"} [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n4\n | /__\\ #### /__\\ |\n | | <><| {o o"} |><> | |\n | (__/\\) . {= } (/\\__) |\n | / ---- \\ | {~\\\\~~~~~} / ---- \\ |\n | ||O!L||| I {}{\\\\~~~{} //|O!L||\\\\|\n | ||----|\\\\I {}{~\\\\~~{} || |----|//|\n | \\[(_()] \\I) {}~~\\\\{} # [(_()]/ |\n | |\\ /| [, {~~~\\} [ |\\ /| |\n | | || | [] {"||"} [ | || | |\n | [ ][ ] [] {"||"} \' [ ][ ] |\n | | || | |\\ {"||"} | || | |\n | | || | | \' {"||"} | || | |\n________________|__[_][__\\_|_]__[_][_]______[_][_]__|______________\n4\n\n\n\n\n\n\n\n\n\n\n\n\n\n11\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) @@@ [....] [|\n [)______________________[___|||__\\__/___[|\n6\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) @ @@ [....] [|\n [)______________________[__|_||__\\__/___[|\n7\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n | /__\\ #### /__\\ |\n | | <><| {"o o} | <><| |\n | . (__/\\) { =} (__/\\) |\n | | / \\ {~~ //~} / \\ |\n | I | __ | {}{ //}{} ||/(===o |\n | I// / \\ | {}{// {} | / \\|| |\n |(I/ /][][\\| {}/ {} \\[][][] |\n |,] |\\ /|# {}@@{} |\\ /| |\n |[] |_||_| H"||"} |_||_| |\n |[] [ ][ ] {"||"} [ ][ ] |\n |/| | || | {"||"} | || | |\n | | |_||_| {"||"} |_||_| |\n________________|_|__[_][_]_____[_][_]______[_][_]__|______________\n3\n | /__\\ #### /__\\ |\n | | <><| {o o"} | <><| |\n | . (__/\\) {= } (__/\\) |\n | | / \\ {~~ //~} / \\ |\n | I | __ | {}{ //}{} ||/(===o |\n | I// / \\ | {}{// {} | / \\|| |\n |(I/ /][][\\| {}/ {} \\[][][] |\n |,] |\\ /|# {}@@{} |\\ /| |\n |[] |_||_| H"||"} |_||_| |\n |[] [ ][ ] {"||"} [ ][ ] |\n |/| | || | {"||"} | || | |\n | | |_||_| {"||"} |_||_| |\n________________|_|__[_][_]_____[_][_]______[_][_]__|______________\n13\n | /__\\ #### /__\\ |\n | | <><| {"o o} | <><| |\n | . (__/\\) { =} (__/\\) |\n | | / \\ {~~ //~} / \\ |\n | I | __ | {}{ //}{} ||/(===o |\n | I// / \\ | {}{// {} | / \\|| |\n |(I/ /][][\\| {}/ {} \\[][][] |\n |,] |\\ /|# {}@@{} |\\ /| |\n |[] |_||_| H"||"} |_||_| |\n |[] [ ][ ] {"||"} [ ][ ] |\n |/| | || | {"||"} | || | |\n | | |_||_| {"||"} |_||_| |\n________________|_|__[_][_]_____[_][_]______[_][_]__|______________\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) @ @@ [....] [|\n [)______________________[__|_||__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)o @ @@ [....] [|\n [)|_____________________[__|_||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o @ @@ [....] [|\n [)_|____________________[__|_||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)# o @ @@ [....] [|\n [)|_|___________________[__|_||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o @ @@ [....] [|\n [)_|_|__________________[__|_||__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)o # o @ @@ [....] [|\n [)|_|_|_________________[__|_||__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)o # o @ @@ [....] [|\n [)|_|_|_________________[_|__||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)_|_|_|________________[_|__||__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)__|_|_|_______________[_|__||__\\__/___[|\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n30\n\n\n Where are you taking\n this... thing?\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n32\n\n\n Prisoner transfer from\n cell block 1138.\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n3\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n12\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @@ [....] [|\n [)___|_|_|______________[_|__||__\\__/___[|\n4\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|______________[_|_|_|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @@ @ [....] [|\n [)___|_|_|______________[_||__|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ [....] [|\n [)___|_|_|______________[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @@ @ [....] [|\n [)___|_|_|______________[||___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|______________[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|_____________|[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|____________|_[_|___|__\\__/___[|\n2\n\n\n I wasn\'t notified.\n\n I\'ll have to clear it.\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|___________|__[_|___|__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|__________|___[_|___|__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|_________|____[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|________|_____[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|________|_____[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ @ @ [....] [|\n [)___|_|_|_______|______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o #o @ @ @ [....] [|\n [)___|__||_______|______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o #o @ @ @ [....] [|\n [)___|__||______|_______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # @ @ @ [....] [|\n [)___|___|______|_______[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # @ @ @ [....] [|\n [)___|___|_____|________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o# @ @ @ [....] [|\n [)___|___||____|________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o# @ @ @ [....] [|\n [)___|___||___|_________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)___|___|_|__|_________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)___|___|_|_|__________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)____|__|_|_|__________[_|___|__\\__/___[|\n3\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o #@ @ @ [....] [|\n [)____|__|_||___________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o #@ @ @ [....] [|\n [)____|__|_|/___________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ @ [....] [|\n [)____|__|_|/___________[_|___|__\\__/___[|\n2\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ [....] [|\n [)____|__|_|/-@_________[_|___|__\\__/___[|\n5\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n Look out!\n\n He\'s loose!\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)____|__|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)_____|_|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o # - @ @ [....] [|\n [)_____|_|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) oo # - @ @ [....] [|\n [)______||_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) -oo # - @ @ [....] [|\n [)______||_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - o # - @ @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - o # - @ @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - oo# - @ @ [....] [|\n [)_______|||--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) - oo# -@ @ [....] [|\n [)_______|||--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [)- o # * @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [* o # * @ [....] [|\n [)_______|_|--@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [). / \\ [|\n [), o #o @ @ [....] [|\n [)_______|_||-@_________[_|___|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) . / \\ [|\n [) o #o @ @ [....] [|\n [)_,_____|_||-@_________[_/___|__\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ [....] [|\n [)_______|_|-|@_________[_/-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o-# o @ [....] [|\n [)_______|_|--|_________[_/-@|___\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ [....] [|\n [)_______|_|--|_________[_/-@|___\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o #- o @ [....] [|\n [)_______|_|--@|________[_/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # - o @ [....] [|\n [)_______|_|--@|________[_/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # - o @ [....] [|\n [)_______|_|--@_|_______[_/|@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # -o @ [....] [|\n [)_______|_|--@_|_______[_/|@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o- @ [....] [|\n [)_______|_|--@_|_______[_|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - @ [....] [|\n [)_______|_|--@_|_______[_|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - .@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - @ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - .@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o - @ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o -.@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o -@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o .* [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o * [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o .@ [....] [|\n [)_______|_|--@_|_______[|/-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o @ [....] [|\n [)_______|_|--@_|_______[//-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . @ [....] [|\n [)_______|_|--@_|_______[//-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)_______|_|--@_|_______[/@-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)_______|_|--@_|_______[/@-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)_______|_|--@_|_______[/@-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)_______|__|-@__|______[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)________|_|-@__|______[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)________|_-|@___|_____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)_________|-|@___|_____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)_________|--|____|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________|-|____|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)__________|-@|____|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________-|@|____|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)__________-|@_|____|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--|_|____|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o . [....] [|\n [)__________--|__|____|_[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@|_|____|_[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o. [....] [|\n [)__________--@|__|____|[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@_|_|____|[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@_|__|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@__|_|____[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # .o [....] [|\n [)__________--@__|__|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@___|_|___[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # . o [....] [|\n [)__________--@___|__|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # o [....] [|\n [)__________--@____|_|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # . o [....] [|\n [)__________--@____|_|__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o# o [....] [|\n [)__________--@_____||__[/@-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o# . o [....] [|\n [)__________--@_____||__[/@/@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o [....] [|\n [)__________--@______|__[/@/@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #o o [....] [|\n [)__________--@______||_[/|-@____\\__/___[|\n1\n\n\n We\'ve got to find out what cell\n this princess of yours is in!\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #o . o [....] [|\n [)__________--@______||_[/|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@______|_|[/|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o. o [....] [|\n [)__________--@______|_|[/|-@____\\__/___[|\n2\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # .oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # oo [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o o [....] [|\n [)__________--@______|__[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@_______|_[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # . o o [....] [|\n [)__________--@_______|_[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@________|[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #. o o [....] [|\n [)__________--@________|[/|-@_|__\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) # o o[....] [|\n [)__________--@_________[/|-@__|_\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) #o o[....] [|\n [)__________--@_________[/|-@__|_\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) .#o o....] [|\n [)__________--@_________[/|-@___|\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o o....] [|\n [)__________--@_________[/|-@___|\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o [o...] [|\n [)__________--@_________[/|-@____|__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o# [o...] [|\n [)__________--@_________[/|-@____|__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o# [.o..] [|\n [)__________--@_________[/|-@____\\|_/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [.o..] [|\n [)__________--@_________[/|-@____\\|_/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / o\\ [|\n [) . o # [..|.] [|\n [)__________--@_________[/|-@____\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / o\\ [|\n [) o # [..|.] [|\n [)__________--@_________[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@|___\\__/___[|\n1\n\n\n Here it is, twenty one eighty seven.\n You go get her.\n\n I\'ll hold them off here!\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n1\n\n\n\n\n\n\n\n ________________________________________\n | ^ ^ ^ ^ |\n | __ |\n [) / \\ [|\n [) . o # [....] [|\n [)__________--@_________[/|-@_|__\\__/___[|\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n ===- ####\n o o" {o o"}\n _\\- /_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n ===- Everything is under ####\n o o"" control. Situation {o o"}\n _\\- /_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {"o o}\n _\\ -/_ normal. { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Everything is under ####\n ""o o control. Situation {o o"}\n _\\ -/_ normal. {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n4\n ===- ####\n o o"" {o o"}\n _\\- /_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n ===- ####\n o o"" What\'s your operating {o o"}\n _\\- /_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n ===- Who is this? ####\n o o"" What\'s your operating {o o"}\n _\\- /_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {"o o}\n _\\ -/_ number? { =} .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== Who is this? ####\n ""o o What\'s your operating {o o"}\n _\\ -/_ number? {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ * / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ // | __ | \\\\ / | {} {// } {}I\n | \\ || [(_()] #) / | {} // } {}I\n \\ \\__#]_|\\__/|_____/ / {} H{{}}} ,I}\n | | [I | || | | | @ H"||"} []\n | | I [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ * / | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ \\\\| __ |-\\\\ * / | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ ______ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\- * / | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n _______//|O!L||\\\\ __*___ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ ***/ | {} {// } {}I\n | \\ [(_()] #) */ | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ * {~~ //~} |\n _______//|O!L||\\\\ _***__ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ **** | {} {// } {}I\n | \\ [(_()] #)*** | {} // } {}I\n \\ \\_____|\\__/|_____/ / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ , **" {~~ //~} |\n _______//|O!L||\\\\ _****_. {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ *****| {} {// } {}I\n | \\ [(_()] #)****.| {} // } {}I\n \\ \\_____|\\__/|_____*` / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ , " {= } .\n / __ \\ .***. {~~ //~} |\n _______//|O!L||\\\\ ****** {{~{ //}~~ I\n | \\ \\\\| __ | \\\\******| {} {// } {}I\n | \\ [(_()] #)*****| {} // } {}I\n \\ \\_____|\\__/|____*** /. {} H{{}}} ,I}\n | | | || | | |, @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ " {= } .\n / __ \\. * . {~~ //~} |\n _______//|O!L||\\\\__****_ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ **** | {} {// } {}I\n | \\ [(_()] #) ** | {} // } {}I\n \\ \\_____|\\__/|____ * / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | . {"||"} []\n | | | || | | |, {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/________________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ " {= } .\n / __ \\ . {~~ //~} |\n _______//|O!L||\\\\___**__ {{~{ //}~~ I\n | \\ \\\\| __ | \\\\ %**/ | {} {// } {}I\n | \\ [(_()] #) / | {} // } {}I\n \\ \\_____|\\__/|____ / / {} H{{}}} ,I}\n | | | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | . {"||"} | |\n_______\\_|____[_][__\\___|_/__,_____________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ " {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | . @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,_____._______________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | . @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | . {"||"} | |\n_______\\_|____[_][__\\___|_/__,_____________________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / " {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | . {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,________.____________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | " {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,_________.___________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | " {"||"} | |\n_______\\_|____[_][__\\___|_/__,__________.__________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,__________"._________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | " {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | " {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.________[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.__"_____[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.___,____[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________.____,___[_][_]_|_|______\n1\n -=== ####\n ""o o Bah! {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n3\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n19\n -=== ####\n ""o o Boring conversation {o o"}\n _\\ -/_ anyway! {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n8\n -=== ####\n ""o o Boring conversation {"o o}\n _\\ -/_ anyway! { =} .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n1\n -=== ####\n ""o o Boring conversation {o o"}\n _\\ -/_ anyway! {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n2\n -=== ####\n ""o o {o o"}\n _\\ -/_ {= } .\n / __ \\ {~~ //~} |\n ______ //|O!L||\\\\_______ {{~{ //}~~ I\n | \\ || | __ | \\\\ %$*/ | {} {// } {}I\n | \\ #] [(_()] #) / | {} // } {}I\n \\ \\__[I_|\\__/|____ / / {} H{{}}} ,I}\n | | I | || | | | @ H"||"} []\n | | [ ][ ] | | {"||"} []\n | | | || | | | {"||"} /|\n | | |_||_| | | {"||"} | |\n_______\\_|____[_][__\\___|_/__,____________._____,__[_][_]_|_|______\n1\n\n\n\n\n\n\n\n\n\n\n\n\n* *\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n5\n / /__\\ \\\n / | <><| \\\n / (__/\\) \\\n | / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n11\n / /__\\ \\\n / Luke! We\'re | <><| \\\n / going to have (__/\\) \\\n | company! / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n18\n / /__\\ \\\n / Luke! We\'re |><> | \\\n / going to have (/\\__) \\\n | company! / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n5\n / /__\\ \\\n / |><> | \\\n / (/\\__) \\\n | / \\ |\n | ||/(===o |\n | | / \\ | |\n | \\/][][\\/ |\n | |\\ /| |\n | |_||_| |\n | [ ][ ] |\n \\ | || | /\n \\ | || | /\n \\________________________[_][_]_______________________/\n2\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n / \\ ===,\n | | @- -@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n______|_____________|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @- -@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n | | ~~~~~~~\n______|\\___________/|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @- -@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n | | / | \\\n |\\___________/| ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n | | | | |\n |\\___________/| / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n | | | | |\n |\\___________/| | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n | | @ | | | @\n |\\___________/| | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n | | \\\\ \\ // ||\n |\\___________/| @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________(_)_(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n | | /_/\\ /\\_|\n |\\___________/| \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n | | / ( ) \\\n |\\___________/| /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n | | /~~ ~~\\\n |\\___________/| / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n | | \\- /\n |\\___________/| /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n | | @o o@)\n |\\___________/| \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / \\ ===,\n |\\___________/| @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n /___________\\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n7\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n11\n / / \\ \\ ===,\n | | <><| | Aren\'t you a little @o o@)\n | (__/\\) | short for a \\- /\n | / \\ | Stormtrooper? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n15\n / / \\ \\ ===,\n | | <><| | Aren\'t you a little @o o@)\n | (__/\\) | short for a \\- /\n | / \\ | Stormtrooper? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @| | |@\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | | <><| | Aren\'t you a little @o o@)\n | (__/\\) | short for a \\- /\n | / \\ | Stormtrooper? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n17\n / / \\ \\ ===,\n | | <><| | Oh, the uniform. @o o@)\n | (__/\\) | \\- /\n | / \\ | I\'m Luke Skywalker. /~~ ~~\\\n | ||/(===o | I\'m here to / ( ) \\\n | | / \\ | | rescue you! /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n15\n / / \\ \\ ===,\n | | <><| | Oh, the uniform. @o o@)\n | (__/\\) | \\- /\n | / \\ | I\'m Luke Skywalker. /~~ ~~\\\n | ||/(===o | I\'m here to / ( ) \\\n | | / \\ | | rescue you! /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n2\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n1\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n24\n / / \\ \\ ===,\n | | <><| | You\'re who? @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n2\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n16\n / / \\ \\ ===,\n | | <><| | I\'m with Ben Kenobi! @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n5\n / / \\ \\ ===,\n | |><> | | I\'m with Ben Kenobi! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | |><> | | I\'m with Ben Kenobi! @O O@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | |><> | | @O O@)\n | (/\\__) | \\O /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | |><> | | Ben Kenobi! @o o@)\n | (/\\__) | \\- /\n | / \\ | Where is he? /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | \\\\ \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n23\n / / \\ \\ ===,\n | | <><| | Ben Kenobi! @o o@)\n | (__/\\) | \\- /\n | / \\ | Where is he? /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n3\n / / \\ \\ ===,\n | | <><| | @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n9\n / / \\ \\ ===,\n | | <><| | Come on! @o o@)\n | (__/\\) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][__\\__|___________________________/__)(_)____________\n2\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | @\\ / ( ) \\\n | | / \\ | | \\\\_/\\ /\\_|\n | \\/][][\\/ | \\ // ||\n | |\\ /| | | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][_]___|___________________________/__)(_)____________\n4\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | || \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|____[_][_]___|___________________________/__)(_)____________\n8\n / / \\ \\ ===,\n | |><> | | Come on! @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | || \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|___/__][_]___|___________________________/__)(_)____________\n6\n / / \\ \\ ===,\n | |><> | | @o o@)\n | (/\\__) | \\- /\n | / \\ | /~~ ~~\\\n | ||/(===o | / ( ) \\\n | | / \\ | | /_/\\ /\\_|\n | \\/][][\\/ | || \\ // ||\n | |\\ /| | @ | | | @\n | |_||_| | | | |\n | [ ][ ] | | | |\n | | || | | / | \\\n | | || | | ~~~~~~~\n______|___/__][_]___|___________________________/__)(_)____________\n3\n\n\n\n\n\n\n\n\n\n\n\n\n\n4\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n4\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ 0/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\- /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n 0 0\')\n __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n3\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\o /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n5\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n6\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n _\\o /__ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n (\'0 0\n __\\ -/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n10\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n7\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n5\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n4\n """"\n Never gonna to 0 0\')\n make you cry... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n9\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n4\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n8\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n11\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__]_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n3\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ 0/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ o/_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ / give you up...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\- /_ give you up...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n 0 0\')\n __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n7\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n3\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\o /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n5\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n Never gonna to 0 0\')\n let you down... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n Never gonna to (\'0 0\n let you down... __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna to (\'0 0\n let you down... __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n6\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ \\ run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n4\n """"\n 0 0\') Never gonna to\n __\\o /_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n4\n """"\n 0 0\') Never gonna to\n _\\o /__ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n4\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n (\'0 0 Never gonna to\n __\\ -/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ run around and\n / \\ / \\ desert you!\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ o/_ ,| run around and\n / \\ / \\ // desert you!\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0\n __\\ o/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n (\'0 0\n __\\ -/_ ,|\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_ \\\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n10\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n7\n """"\n Never gonna to 0 0\')\n make you cry... __\\- /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... __\\o /_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n5\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | //\n /\' | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n_________________________/__]___[__]_______________________________\n4\n """"\n Never gonna to 0 0\')\n make you cry... \\ _\\- /__\n \\\\ / \\ / \\\n \\\\//| || |\\\\\n \\/ | || | \\\\\n | || | //\n | || |/\'\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n2\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\o /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n________________________/__]____[_]________________________________\n1\n """"\n Never gonna to 0 0\')\n make you cry... _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n /_/ |_|\n_________________________/__]____[_]_______________________________\n1\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n8\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ -/_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n9\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n (\'0 0 Never gonna to\n __\\ o/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n3\n """"\n (\'0 0 Never gonna to\n __\\ -/_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n 0 0\') Never gonna to\n __\\o /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\- /_ / say goodbye...\n / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n 0 0\') Never gonna to\n __\\o /_ say goodbye...\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n2\n """"\n 0 0\')\n _\\- /__\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n4\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n2\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n5\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n8\n """"\n Never gonna tell (\'0 0\n a lie and __\\ -/_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n // | || |\n /\' | || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ ,|\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n2\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n8\n """"\n Never gonna tell 0 0\')\n a lie and __\\- /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n11\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_ \\\n hurt you! / \\ / \\ //\n //| || |\\\\//\n // | || | \\/\n \\\\ | || |\n \'\\| || |\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]____[__\\____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__\\_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and __\\o /_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]___[__]_____________________________\n1\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n3\n """"\n Never gonna tell 0 0\')\n a lie and _\\o /__\n hurt you! / \\ / \\\n //| | | |\\\\\n // | | | | \\\\\n // | | | | \\\\\n /\' | | | | \'\\\n / | | \\\n / | \\ \\\n /___/---\\__\\\n |_| \\_\\\n__________________________/__]___[__]______________________________\n1\n """"\n Never gonna tell (\'0 0\n a lie and __\\ o/_\n hurt you! / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n3\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n // | || | \\\\\n /\' | || | \'\\\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n___________________________/__]__[__]______________________________\n1\n """"\n (\'0 0\n __\\ -/_\n / \\ / \\\n //| || |\\\\\n // | || | \\\\\n \\\\ | || | \\\\\n \'\\| || | \'|\n / || \\\n / | \\ \\\n /___ /-- \\__\\\n |_| \\_\\\n____________________________[_]__[__\\______________________________\n48\n\n\n\n\n To be continued.\n\n Simon Jansen (C) 1997 - 2008\n\n www.asciimation.co.nz\n\n\n\n\n1\n\n\n\n\n\n\n\n\n\n\n\n\n\n˙\n' local function iterator() diff --git a/src/test/resources/test-rom/spec/programs/type_spec.lua b/src/test/resources/test-rom/spec/programs/type_spec.lua index 78009c746..09d59ee4a 100644 --- a/src/test/resources/test-rom/spec/programs/type_spec.lua +++ b/src/test/resources/test-rom/spec/programs/type_spec.lua @@ -23,4 +23,3 @@ describe("The type program", function() end) end) - diff --git a/tools/check-lines.py b/tools/check-lines.py index d50d4610d..5fb6e9b91 100644 --- a/tools/check-lines.py +++ b/tools/check-lines.py @@ -10,8 +10,13 @@ for path in pathlib.Path("src").glob("**/*"): continue with path.open(encoding="utf-8") as file: - has_dos, has_trailing, needs_final = False, False, False + has_dos, has_trailing, first, count = False, False, 0, True for i, line in enumerate(file): + if first: + first = False + if line.strip() == "": + print("%s has empty first line" % path) + if len(line) >= 2 and line[-2] == "\r" and line[-1] == "\n" and not has_line: print("%s has contains '\\r\\n' on line %d" % (path, i + 1)) problems = has_dos = True @@ -20,8 +25,15 @@ for path in pathlib.Path("src").glob("**/*"): print("%s has trailing whitespace on line %d" % (path, i + 1)) problems = has_trailing = True - if line is not None and len(line) >= 1 and line[-1] != "\n": - print("%s should end with '\\n'" % path) + if len(line) == 0 or line[-1] != "\n": + count = 0 + elif line.strip() == "": + count += 1 + else: + count = 1 + + if count != 1: + print("%s should have 1 trailing lines, but has %d" % (path, count)) problems = True if problems: From 9a71dc1a264fbf369e3ba61668d76e70d389ae3e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 11 May 2020 18:05:23 +0100 Subject: [PATCH 220/711] Copy across a bunch of 5.1/5.3 io tests I've been meaning to do this for ages. Woops. --- .../assets/computercraft/lua/rom/apis/io.lua | 14 +- .../resources/test-rom/spec/apis/io_spec.lua | 284 +++++++++++++++++- 2 files changed, 277 insertions(+), 21 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua index 8079e022f..917faef7f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/io.lua @@ -75,7 +75,10 @@ handleMetatable = { if not handle.read then return nil, "file is not readable" end local args = table.pack(...) - return function() return checkResult(self, self:read(table.unpack(args, 1, args.n))) end + return function() + if self._closed then error("file is already closed", 2) end + return checkResult(self, self:read(table.unpack(args, 1, args.n))) + end end, read = function(self, ...) @@ -259,12 +262,13 @@ end -- instead. In this case, the handle is not used. -- -- @tparam[opt] string filename The name of the file to extract lines from +-- @param ... The argument to pass to @{Handle:read} for each line. -- @treturn function():string|nil The line iterator. -- @throws If the file cannot be opened for reading -- -- @see Handle:lines -- @see io.input -function lines(filename) +function lines(filename, ...) expect(1, filename, "string", "nil") if filename then local ok, err = open(filename, "rb") @@ -273,9 +277,9 @@ function lines(filename) -- We set this magic flag to mark this file as being opened by io.lines and so should be -- closed automatically ok._autoclose = true - return ok:lines() + return ok:lines(...) else - return currentInput:lines() + return currentInput:lines(...) end end @@ -313,7 +317,7 @@ end -- @throws If the provided filename cannot be opened for writing. function output(file) if type_of(file) == "string" then - local res, err = open(file, "w") + local res, err = open(file, "wb") if not res then error(err, 2) end currentOutput = res elseif type_of(file) == "table" and getmetatable(file) == handleMetatable then diff --git a/src/test/resources/test-rom/spec/apis/io_spec.lua b/src/test/resources/test-rom/spec/apis/io_spec.lua index 484588014..b1746093f 100644 --- a/src/test/resources/test-rom/spec/apis/io_spec.lua +++ b/src/test/resources/test-rom/spec/apis/io_spec.lua @@ -1,8 +1,44 @@ --- Tests the io library is (mostly) consistent with PUC Lua. -- --- These tests are based on the tests for Lua 5.1 +-- These tests are based on the tests for Lua 5.1 and 5.3 describe("The io library", function() + local file = "/test-files/tmp.txt" + local otherfile = "/test-files/tmp2.txt" + + local t = '0123456789' + for _ = 1, 12 do t = t .. t end + assert(#t == 10 * 2 ^ 12) + + local function read_all(f) + local h = fs.open(f, "rb") + local contents = h.readAll() + h.close() + return contents + end + + local function write_file(f, contents) + local h = fs.open(f, "wb") + h.write(contents) + h.close() + end + + local function setup() + write_file(file, "\"�lo\"{a}\nsecond line\nthird line \n�fourth_line\n\n\9\9 3450\n") + end + + describe("io.close", function() + it("cannot close stdin", function() + expect{ io.stdin:close() }:same { nil, "attempt to close standard stream" } + end) + it("cannot close stdout", function() + expect{ io.stdout:close() }:same { nil, "attempt to close standard stream" } + end) + it("cannot close stdout", function() + expect{ io.stdout:close() }:same { nil, "attempt to close standard stream" } + end) + end) + it("io.input on a handle returns that handle", function() expect(io.input(io.stdin)):equals(io.stdin) end) @@ -11,11 +47,16 @@ describe("The io library", function() expect(io.output(io.stdout)):equals(io.stdout) end) + it("defines a __name field", function() + expect(getmetatable(io.input()).__name):eq("FILE*") + end) + describe("io.type", function() it("returns file on handles", function() local handle = io.input() expect(handle):type("table") expect(io.type(handle)):equals("file") + expect(io.type(io.stdin)):equals("file") end) it("returns nil on values", function() @@ -33,6 +74,88 @@ describe("The io library", function() expect.error(io.lines, ""):eq("/: No such file") expect.error(io.lines, false):eq("bad argument #1 (expected string, got boolean)") end) + + it("closes the file", function() + setup() + + local n = 0 + local f = io.lines(file) + while f() do n = n + 1 end + expect(n):eq(6) + + expect.error(f):eq("file is already closed") + expect.error(f):eq("file is already closed") + end) + + it("can copy a file", function() + setup() + + local n = 0 + io.output(otherfile) + for l in io.lines(file) do + io.write(l, "\n") + n = n + 1 + end + io.close() + expect(n):eq(6) + + io.input(file) + local f = io.open(otherfile):lines() + local n = 0 + for l in io.lines() do + expect(l):eq(f()) + n = n + 1 + end + expect(n):eq(6) + end) + + it("does not close on a normal file handle", function() + setup() + + local f = assert(io.open(file)) + local n = 0 + for _ in f:lines() do n = n + 1 end + expect(n):eq(6) + + expect(tostring(f):sub(1, 5)):eq("file ") + assert(f:close()) + + expect(tostring(f)):eq("file (closed)") + expect(io.type(f)):eq("closed file") + end) + + it("accepts multiple arguments", function() + write_file(file, "0123456789\n") + for a, b in io.lines(file, 1, 1) do + if a == "\n" then + expect(b):eq(nil) + else + expect(tonumber(a)):eq(tonumber(b) - 1) + end + end + + for a, b, c in io.lines(file, 1, 2, "a") do + expect(a):eq("0") + expect(b):eq("12") + expect(c):eq("3456789\n") + end + + for a, b, c in io.lines(file, "a", 0, 1) do + if a == "" then break end + expect(a):eq("0123456789\n") + expect(b):eq(nil) + expect(c):eq(nil) + end + + write_file(file, "00\n10\n20\n30\n40\n") + for a, b in io.lines(file, "n", "n") do + if a == 40 then + expect(b):eq(nil) + else + expect(a):eq(b - 10) + end + end + end) end) describe("io.open", function() @@ -44,6 +167,22 @@ describe("The io library", function() expect.error(io.open, "", false):eq("bad argument #2 (expected string, got boolean)") end) + it("checks the mode", function() + io.open(file, "w"):close() + + -- This really should be invalid mode, but I'll live. + expect.error(io.open, file, "rw"):str_match("Unsupported mode") + -- TODO: expect.error(io.open, file, "rb+"):str_match("Unsupported mode") + expect.error(io.open, file, "r+bk"):str_match("Unsupported mode") + expect.error(io.open, file, ""):str_match("Unsupported mode") + expect.error(io.open, file, "+"):str_match("Unsupported mode") + expect.error(io.open, file, "b"):str_match("Unsupported mode") + + assert(io.open(file, "r+b")):close() + assert(io.open(file, "r+")):close() + assert(io.open(file, "rb")):close() + end) + it("returns an error message on non-existent files", function() local a, b = io.open('xuxu_nao_existe') expect(a):equals(nil) @@ -51,26 +190,139 @@ describe("The io library", function() end) end) - pending("io.output allows redirecting and seeking", function() - fs.delete("/tmp/io_spec.txt") + describe("a readable handle", function() + it("cannot be written to", function() + write_file(file, "") + io.input(file) + expect { io.input():write("xuxu") }:same { nil, "file is not writable" } + io.input(io.stdin) + end) - io.output("/tmp/io_spec.txt") + it("supports various modes", function() + write_file(file, "alo\n " .. t .. " ;end of file\n") - expect(io.output()):not_equals(io.stdout) + io.input(file) + expect(io.read()):eq("alo") + expect(io.read(1)):eq(' ') + expect(io.read(#t)):eq(t) + expect(io.read(1)):eq(' ') + expect(io.read(0)) + expect(io.read('*a')):eq(';end of file\n') + expect(io.read(0)):eq(nil) + expect(io.close(io.input())):eq(true) - expect(io.output():seek()):equal(0) - assert(io.write("alo alo")) - expect(io.output():seek()):equal(#"alo alo") - expect(io.output():seek("cur", -3)):equal(#"alo alo" - 3) - assert(io.write("joao")) - expect(io.output():seek("end"):equal(#"alo joao")) + fs.delete(file) + end) - expect(io.output():seek("set")):equal(0) + it("support seeking", function() + setup() + io.input(file) - assert(io.write('"�lo"', "{a}\n", "second line\n", "third line \n")) - assert(io.write('�fourth_line')) + expect(io.read(0)):eq("") -- not eof + expect(io.read(5, '*l')):eq('"�lo"') + expect(io.read(0)):eq("") + expect(io.read()):eq("second line") + local x = io.input():seek() + expect(io.read()):eq("third line ") + assert(io.input():seek("set", x)) + expect(io.read('*l')):eq("third line ") + expect(io.read(1)):eq("�") + expect(io.read(#"fourth_line")):eq("fourth_line") + assert(io.input():seek("cur", -#"fourth_line")) + expect(io.read()):eq("fourth_line") + expect(io.read()):eq("") -- empty line + expect(io.read(8)):eq('\9\9 3450') -- FIXME: Not actually supported + expect(io.read(1)):eq('\n') + expect(io.read(0)):eq(nil) -- end of file + expect(io.read(1)):eq(nil) -- end of file + expect(({ io.read(1) })[2]):eq(nil) + expect(io.read()):eq(nil) -- end of file + expect(({ io.read() })[2]):eq(nil) + expect(io.read('*n')):eq(nil) -- end of file + expect(({ io.read('*n') })[2]):eq(nil) + expect(io.read('*a')):eq('') -- end of file (OK for `*a') + expect(io.read('*a')):eq('') -- end of file (OK for `*a') - io.output(io.stdout) - expect(io.output()):equals(io.stdout) + io.close(io.input()) + end) + + it("supports the 'L' mode", function() + write_file(file, "\n\nline\nother") + + io.input(file) + expect(io.read"L"):eq("\n") + expect(io.read"L"):eq("\n") + expect(io.read"L"):eq("line\n") + expect(io.read"L"):eq("other") + expect(io.read"L"):eq(nil) + io.input():close() + + local f = assert(io.open(file)) + local s = "" + for l in f:lines("L") do s = s .. l end + expect(s):eq("\n\nline\nother") + f:close() + + io.input(file) + s = "" + for l in io.lines(nil, "L") do s = s .. l end + expect(s):eq("\n\nline\nother") + io.input():close() + + s = "" + for l in io.lines(file, "L") do s = s .. l end + expect(s):eq("\n\nline\nother") + + s = "" + for l in io.lines(file, "l") do s = s .. l end + expect(s):eq("lineother") + + write_file(file, "a = 10 + 34\na = 2*a\na = -a\n") + local t = {} + load(io.lines(file, "L"), nil, nil, t)() + expect(t.a):eq(-((10 + 34) * 2)) + end) + end) + + describe("a writable handle", function() + it("supports seeking", function() + fs.delete(file) + io.output(file) + + expect(io.output()):not_equals(io.stdout) + + expect(io.output():seek()):equal(0) + assert(io.write("alo alo")) + expect(io.output():seek()):equal(#"alo alo") + expect(io.output():seek("cur", -3)):equal(#"alo alo" - 3) + assert(io.write("joao")) + expect(io.output():seek("end")):equal(#"alo joao") + + expect(io.output():seek("set")):equal(0) + + assert(io.write('"�lo"', "{a}\n", "second line\n", "third line \n")) + assert(io.write('�fourth_line')) + + io.output(io.stdout) + expect(io.output()):equals(io.stdout) + end) + + it("supports appending", function() + io.output(file) + io.write("alo\n") + io.close() + expect.error(io.write) + + local f = io.open(file, "a") + io.output(f) + + assert(io.write(' ' .. t .. ' ')) + assert(io.write(';', 'end of file\n')) + f:flush() + io.flush() + f:close() + + expect(read_all(file)):eq("alo\n " .. t .. " ;end of file\n") + end) end) end) From 05d7be0362360d8818f18449fe4736a6bb61c26e Mon Sep 17 00:00:00 2001 From: Lupus590 Date: Tue, 12 May 2020 11:32:48 +0100 Subject: [PATCH 221/711] Improvements to the various file system programs (rm, mv, rename) (#440) This enforces several sanity checks before actually attempting the move, allowing us to produce friendlier error messages. --- doc/stub/fs.lua | 12 +++++ .../assets/computercraft/lua/bios.lua | 6 +++ .../computercraft/lua/rom/programs/delete.lua | 15 ++++-- .../computercraft/lua/rom/programs/move.lua | 27 +++++++++- .../computercraft/lua/rom/programs/rename.lua | 6 +++ .../resources/test-rom/spec/apis/fs_spec.lua | 15 ++++++ .../test-rom/spec/programs/delete_spec.lua | 10 +++- .../test-rom/spec/programs/move_spec.lua | 50 ++++++++++++++++++- .../test-rom/spec/programs/rename_spec.lua | 12 ++++- 9 files changed, 145 insertions(+), 8 deletions(-) diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua index a9e76a352..41e1db8e1 100644 --- a/doc/stub/fs.lua +++ b/doc/stub/fs.lua @@ -19,6 +19,18 @@ function getFreeSpace(path) end function find(pattern) end function getDir(path) end +--- Returns true if a path is mounted to the parent filesystem. +-- +-- The root filesystem "/" is considered a mount, along with disk folders and +-- the rom folder. Other programs (such as network shares) can exstend this to +-- make other mount types by correctly assigning their return value for getDrive. +-- +-- @tparam string path The path to check. +-- @treturn boolean If the path is mounted, rather than a normal file/folder. +-- @throws If the path does not exist. +-- @see getDrive +function isDriveRoot(path) end + --- Get the capacity of the drive at the given path. -- -- This may be used in conjunction with @{getFreeSpace} to determine what diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index cef90b633..55688a4f2 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -797,6 +797,12 @@ function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) return tEmpty end +function fs.isDriveRoot(sPath) + expect(1, sPath, "string") + -- Force the root directory to be a mount. + return fs.getDir(sPath) == ".." or fs.getDrive(sPath) ~= fs.getDrive(fs.getDir(sPath)) +end + -- Load APIs local bAPIError = false local tApis = fs.list("rom/apis") diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua b/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua index 91f2e0c23..620cdd629 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/delete.lua @@ -9,9 +9,18 @@ for i = 1, args.n do local files = fs.find(shell.resolve(args[i])) if #files > 0 then for _, file in ipairs(files) do - local ok, err = pcall(fs.delete, file) - if not ok then - printError((err:gsub("^pcall: ", ""))) + if fs.isReadOnly(file) then + printError("Cannot delete read-only file /" .. file) + elseif fs.isDriveRoot(file) then + printError("Cannot delete mount /" .. file) + if fs.isDir(file) then + print("To delete its contents run rm /" .. fs.combine(file, "*")) + end + else + local ok, err = pcall(fs.delete, file) + if not ok then + printError((err:gsub("^pcall: ", ""))) + end end end else diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua index 3273b1ba9..254592200 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/move.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/move.lua @@ -7,12 +7,35 @@ end local sSource = shell.resolve(tArgs[1]) local sDest = shell.resolve(tArgs[2]) local tFiles = fs.find(sSource) + +local function sanity_checks(source, dest) + if fs.exists(dest) then + printError("Destination exists") + return false + elseif fs.isReadOnly(dest) then + printError("Destination is read-only") + return false + elseif fs.isDriveRoot(source) then + printError("Cannot move mount /" .. source) + return false + elseif fs.isReadOnly(source) then + printError("Cannot move read-only file /" .. source) + return false + end + return true +end + if #tFiles > 0 then for _, sFile in ipairs(tFiles) do if fs.isDir(sDest) then - fs.move(sFile, fs.combine(sDest, fs.getName(sFile))) + local dest = fs.combine(sDest, fs.getName(sFile)) + if sanity_checks(sFile, dest) then + fs.move(sFile, dest) + end elseif #tFiles == 1 then - fs.move(sFile, sDest) + if sanity_checks(sFile, sDest) then + fs.move(sFile, sDest) + end else printError("Cannot overwrite file multiple times") return diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua b/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua index a90c1f8ad..8b491abcd 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/rename.lua @@ -10,6 +10,12 @@ local sDest = shell.resolve(tArgs[2]) if not fs.exists(sSource) then printError("No matching files") return +elseif fs.isDriveRoot(sSource) then + printError("Can't rename mounts") + return +elseif fs.isReadOnly(sSource) then + printError("Source is read-only") + return elseif fs.exists(sDest) then printError("Destination exists") return diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index 5288aa9c8..fd16599de 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -12,6 +12,21 @@ describe("The fs library", function() end) end) + describe("fs.isDriveRoot", function() + it("validates arguments", function() + fs.isDriveRoot("") + + expect.error(fs.isDriveRoot, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("correctly identifies drive roots", function() + expect(fs.isDriveRoot("/rom")):eq(true) + expect(fs.isDriveRoot("/")):eq(true) + expect(fs.isDriveRoot("/rom/startup.lua")):eq(false) + expect(fs.isDriveRoot("/rom/programs/delete.lua")):eq(false) + end) + end) + describe("fs.list", function() it("fails on files", function() expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory") diff --git a/src/test/resources/test-rom/spec/programs/delete_spec.lua b/src/test/resources/test-rom/spec/programs/delete_spec.lua index 1eec95cc4..18a01c5c0 100644 --- a/src/test/resources/test-rom/spec/programs/delete_spec.lua +++ b/src/test/resources/test-rom/spec/programs/delete_spec.lua @@ -42,7 +42,15 @@ describe("The rm program", function() it("errors when trying to delete a read-only file", function() expect(capture(stub, "rm /rom/startup.lua")) - :matches { ok = true, output = "", error = "/rom/startup.lua: Access denied\n" } + :matches { ok = true, output = "", error = "Cannot delete read-only file /rom/startup.lua\n" } + end) + + it("errors when trying to delete the root mount", function() + expect(capture(stub, "rm /")):matches { + ok = true, + output = "To delete its contents run rm /*\n", + error = "Cannot delete mount /\n", + } end) it("errors when a glob fails to match", function() diff --git a/src/test/resources/test-rom/spec/programs/move_spec.lua b/src/test/resources/test-rom/spec/programs/move_spec.lua index de1a36569..664010118 100644 --- a/src/test/resources/test-rom/spec/programs/move_spec.lua +++ b/src/test/resources/test-rom/spec/programs/move_spec.lua @@ -1,11 +1,13 @@ local capture = require "test_helpers".capture_program describe("The move program", function() + local function cleanup() fs.delete("/test-files/move") end local function touch(file) io.open(file, "w"):close() end it("move a file", function() + cleanup() touch("/test-files/move/a.txt") shell.run("move /test-files/move/a.txt /test-files/move/b.txt") @@ -14,11 +16,57 @@ describe("The move program", function() expect(fs.exists("/test-files/move/b.txt")):eq(true) end) - it("try to move a not existing file", function() + it("moves a file to a directory", function() + cleanup() + touch("/test-files/move/a.txt") + fs.makeDir("/test-files/move/a") + + expect(capture(stub, "move /test-files/move/a.txt /test-files/move/a")) + :matches { ok = true } + + expect(fs.exists("/test-files/move/a.txt")):eq(false) + expect(fs.exists("/test-files/move/a/a.txt")):eq(true) + end) + + it("fails when moving a file which doesn't exist", function() expect(capture(stub, "move nothing destination")) :matches { ok = true, output = "", error = "No matching files\n" } end) + it("fails when overwriting an existing file", function() + cleanup() + touch("/test-files/move/a.txt") + + expect(capture(stub, "move /test-files/move/a.txt /test-files/move/a.txt")) + :matches { ok = true, output = "", error = "Destination exists\n" } + end) + + it("fails when moving to read-only locations", function() + cleanup() + touch("/test-files/move/a.txt") + + expect(capture(stub, "move /test-files/move/a.txt /rom/test.txt")) + :matches { ok = true, output = "", error = "Destination is read-only\n" } + end) + + it("fails when moving from read-only locations", function() + expect(capture(stub, "move /rom/startup.lua /test-files/move/not-exist.txt")) + :matches { ok = true, output = "", error = "Cannot move read-only file /rom/startup.lua\n" } + end) + + it("fails when moving mounts", function() + expect(capture(stub, "move /rom /test-files/move/rom")) + :matches { ok = true, output = "", error = "Cannot move mount /rom\n" } + end) + + it("fails when moving a file multiple times", function() + cleanup() + touch("/test-files/move/a.txt") + touch("/test-files/move/b.txt") + expect(capture(stub, "move /test-files/move/*.txt /test-files/move/c.txt")) + :matches { ok = true, output = "", error = "Cannot overwrite file multiple times\n" } + end) + it("displays the usage with no arguments", function() expect(capture(stub, "move")) :matches { ok = true, output = "Usage: mv \n", error = "" } diff --git a/src/test/resources/test-rom/spec/programs/rename_spec.lua b/src/test/resources/test-rom/spec/programs/rename_spec.lua index 2ab955dab..437e940d3 100644 --- a/src/test/resources/test-rom/spec/programs/rename_spec.lua +++ b/src/test/resources/test-rom/spec/programs/rename_spec.lua @@ -26,13 +26,23 @@ describe("The rename program", function() :matches { ok = true, output = "", error = "Destination exists\n" } end) - it("fails when copying to read-only locations", function() + it("fails when renaming to read-only locations", function() touch("/test-files/rename/d.txt") expect(capture(stub, "rename /test-files/rename/d.txt /rom/test.txt")) :matches { ok = true, output = "", error = "Destination is read-only\n" } end) + it("fails when renaming from read-only locations", function() + expect(capture(stub, "rename /rom/startup.lua /test-files/rename/d.txt")) + :matches { ok = true, output = "", error = "Source is read-only\n" } + end) + + it("fails when renaming mounts", function() + expect(capture(stub, "rename /rom /test-files/rename/rom")) + :matches { ok = true, output = "", error = "Can't rename mounts\n" } + end) + it("displays the usage when given no arguments", function() expect(capture(stub, "rename")) :matches { ok = true, output = "Usage: rename \n", error = "" } From ac075d9f533b4b7c63998137bbf1d8b96ba68f89 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 13 May 2020 10:26:59 +0100 Subject: [PATCH 222/711] Allow using command computers in survival mode I'm really not a fan of this change, but it's gated behind a config option and there's apparently sufficient demand that it's worthwhile. Closes #442. --- .../dan200/computercraft/ComputerCraft.java | 3 ++- .../dan200/computercraft/shared/Config.java | 8 +++++++- .../computer/blocks/TileCommandComputer.java | 14 +++++++++----- .../inventory/ContainerViewComputer.java | 17 +++-------------- .../assets/computercraft/lang/en_us.lang | 1 + 5 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 2f3e85b66..f2ae2b16e 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -112,7 +112,8 @@ public class ComputerCraft public static boolean disable_lua51_features = false; public static String default_computer_settings = ""; public static boolean debug_enable = true; - public static boolean logPeripheralErrors = false; + public static boolean logPeripheralErrors = true; + public static boolean commandRequireCreative = true; public static int computer_threads = 1; public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( 10 ); diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 92f2b75c3..ceb42e27b 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -47,6 +47,7 @@ public final class Config private static Property defaultComputerSettings; private static Property debugEnabled; private static Property logComputerErrors; + private static Property commandRequireCreative; private static Property computerThreads; private static Property maxMainGlobalTime; @@ -119,10 +120,14 @@ public final class Config logComputerErrors.setComment( "Log exceptions thrown by peripherals and other Lua objects.\n" + "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ); + commandRequireCreative = config.get( CATEGORY_GENERAL, "command_require_creative", ComputerCraft.commandRequireCreative ); + commandRequireCreative.setComment( "Require players to be in creative mode and be opped in order to interact with command computers." + + "This is the default behaviour for vanilla's Command blocks." ); + setOrder( CATEGORY_GENERAL, computerSpaceLimit, floppySpaceLimit, maximumFilesOpen, - disableLua51Features, defaultComputerSettings, debugEnabled, logComputerErrors + disableLua51Features, defaultComputerSettings, debugEnabled, logComputerErrors, commandRequireCreative ); } @@ -441,6 +446,7 @@ public final class Config ComputerCraft.default_computer_settings = defaultComputerSettings.getString(); ComputerCraft.debug_enable = debugEnabled.getBoolean(); ComputerCraft.logPeripheralErrors = logComputerErrors.getBoolean(); + ComputerCraft.commandRequireCreative = commandRequireCreative.getBoolean(); // Execution ComputerCraft.computer_threads = computerThreads.getInt(); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index a822dad84..d173d493f 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.computer.blocks; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.apis.CommandAPI; import dan200.computercraft.shared.computer.core.ServerComputer; import io.netty.buffer.ByteBuf; @@ -167,6 +168,11 @@ public class TileCommandComputer extends TileComputer @Override public boolean isUsable( EntityPlayer player, boolean ignoreRange ) + { + return isUsable( player ) && super.isUsable( player, ignoreRange ); + } + + public static boolean isUsable( EntityPlayer player ) { MinecraftServer server = player.getServer(); if( server == null || !server.isCommandBlockEnabled() ) @@ -174,14 +180,12 @@ public class TileCommandComputer extends TileComputer player.sendMessage( new TextComponentTranslation( "advMode.notEnabled" ) ); return false; } - else if( !player.canUseCommandBlock() ) + else if( ComputerCraft.commandRequireCreative ? !player.canUseCommandBlock() : !server.getPlayerList().canSendCommands( player.getGameProfile() ) ) { player.sendMessage( new TextComponentTranslation( "advMode.notAllowed" ) ); return false; } - else - { - return super.isUsable( player, ignoreRange ); - } + + return true; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 18f5d37bb..860722517 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -6,11 +6,10 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.core.*; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; -import net.minecraft.server.MinecraftServer; -import net.minecraft.util.text.TextComponentTranslation; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -46,19 +45,9 @@ public class ContainerViewComputer extends Container implements IContainerComput } // If we're a command computer then ensure we're in creative - if( serverComputer.getFamily() == ComputerFamily.Command ) + if( serverComputer.getFamily() == ComputerFamily.Command && !TileCommandComputer.isUsable( player ) ) { - MinecraftServer server = player.getServer(); - if( server == null || !server.isCommandBlockEnabled() ) - { - player.sendMessage( new TextComponentTranslation( "advMode.notEnabled" ) ); - return false; - } - else if( !player.canUseCommandBlock() ) - { - player.sendMessage( new TextComponentTranslation( "advMode.notAllowed" ) ); - return false; - } + return false; } } diff --git a/src/main/resources/assets/computercraft/lang/en_us.lang b/src/main/resources/assets/computercraft/lang/en_us.lang index 53182df9b..503e4aaef 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.lang +++ b/src/main/resources/assets/computercraft/lang/en_us.lang @@ -159,6 +159,7 @@ gui.computercraft:config.disable_lua51_features=Disable Lua 5.1 features gui.computercraft:config.default_computer_settings=Default Computer settings gui.computercraft:config.debug_enabled=Enable debug library gui.computercraft:config.log_computer_errors=Log computer errors +gui.computercraft:config.command_require_creative=Command computers require creative gui.computercraft:config.execution=Execution gui.computercraft:config.execution.computer_threads=Computer threads From a4ae36b6b37281c3afa041ed7a38936e00e714af Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 13 May 2020 13:43:40 +0100 Subject: [PATCH 223/711] Bump version to 1.88.0 There's probably some other stuff I'll get in before release, but let's do this just in case. --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 14 ++++++++ .../computercraft/lua/rom/help/whatsnew.txt | 36 ++++++------------- 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/gradle.properties b/gradle.properties index d61ef4e0f..6a0e98d27 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.87.0 +mod_version=1.88.0 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 36a482fb4..3d9f00769 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,17 @@ +# New features in CC: Tweaked 1.88.0 + +* Computers and turtles now preserve their ID when broken. +* Add `peripheral.getName` - returns the name of a wrapped peripheral. +* Reduce network overhead of monitors and terminals. +* Add a TBO backend for monitors, with a significant performance boost. +* The Lua REPL warns when declaring locals (lupus590, exerro) +* Add config to allow using command computers in survival. +* Add fs.isDriveRoot - checks if a path is the root of a drive. + +And several bug fixes: +* Fix io.lines not accepting arguments. +* Fix settings.load using an unknown global (MCJack123). + # New features in CC: Tweaked 1.87.0 * Add documentation to many Lua functions. This is published online at https://tweaked.cc/. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 29e395d9f..a3cb561de 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,31 +1,15 @@ -New features in CC: Tweaked 1.87.0 +New features in CC: Tweaked 1.88.0 -* Add documentation to many Lua functions. This is published online at https://tweaked.cc/. -* Replace to pretty-printer in the Lua REPL. It now supports displaying functions and recursive tables. This printer is may be used within your own code through the `cc.pretty` module. -* Add `fs.getCapacity`. A complement to `fs.getFreeSpace`, this returns the capacity of the supplied drive. -* Add `fs.getAttributes`. This provides file size and type, as well as creation and modification time. -* Update Cobalt version. This backports several features from Lua 5.2 and 5.3: - - The `__len` metamethod may now be used by tables. - - Add `\z`, hexadecimal (`\x00`) and unicode (`\u0000`) string escape codes. - - Add `utf8` lib. - - Mirror Lua's behaviour of tail calls more closely. Native functions are no longer tail called, and tail calls are displayed in the stack trace. - - `table.unpack` now uses `__len` and `__index` metamethods. - - Parser errors now include the token where the error occured. -* Add `textutils.unserializeJSON`. This can be used to decode standard JSON and stringified-NBT. -* Switch the monitor renderer to use VBOs, providing a _significant_ performance boost in some cases. You can switch back to the display list renderer via the config. -* The `settings` API now allows "defining" settings. This allows settings to specify a default value and description. -* Enable the motd on non-pocket computers. -* Allow using the menu with the mouse in edit and paint (JakobDev). -* Add Danish and Korean translations (ChristianLW, mindy15963) -* Fire `mouse_up` events in the monitor program. -* Allow specifying a timeout to `websocket.receive`. -* Increase the maximimum limit for websocket messages. -* Optimise capacity checking of computer/disk folders. +* Computers and turtles now preserve their ID when broken. +* Add `peripheral.getName` - returns the name of a wrapped peripheral. +* Reduce network overhead of monitors and terminals. +* Add a TBO backend for monitors, with a significant performance boost. +* The Lua REPL warns when declaring locals (lupus590, exerro) +* Add config to allow using command computers in survival. +* Add fs.isDriveRoot - checks if a path is the root of a drive. And several bug fixes: -* Fix turtle texture being incorrectly oriented (magiczocker10). -* Prevent copying folders into themselves. -* Fix race condition within ID assignment. -* Normalise file paths within shell.setDir (JakobDev) +* Fix io.lines not accepting arguments. +* Fix settings.load using an unknown global (MCJack123). Type "help changelog" to see the full version history. From c60dcb4f5a4faa4abb53764c103c59c8ba0c7ce8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 13 May 2020 14:04:32 +0100 Subject: [PATCH 224/711] Fix deprecated usage --- src/main/java/dan200/computercraft/core/apis/OSAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 6ccd51730..825ad05fa 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -103,7 +103,7 @@ public class OSAPI implements ILuaAPI double t = alarm.m_day * 24.0 + alarm.m_time; if( now >= t ) { - queueLuaEvent( "alarm", new Object[] { entry.getKey() } ); + queueLuaEvent( "alarm", new Object[] { entry.getIntKey() } ); it.remove(); } } From 9abcfe56ea91014b0f1bb3636819c0d3e329080a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 13 May 2020 14:41:50 +0100 Subject: [PATCH 225/711] Create the coverage directory before writing Odd that this failed - we should make the directory within the test suite - but let's see if this helps. --- .../java/dan200/computercraft/core/ComputerTestDelegate.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 301b1c9a8..f2d2453a7 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -333,6 +333,7 @@ public class ComputerTestDelegate if( finishedWith != null ) { + REPORT_PATH.getParentFile().mkdirs(); try( BufferedWriter writer = Files.newBufferedWriter( REPORT_PATH.toPath() ) ) { new LuaCoverage( finishedWith ).write( writer ); From e251dd066c612bb2bd44c06250e4efb34bbb1484 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 13 May 2020 15:27:50 +0100 Subject: [PATCH 226/711] Fix test failures --- src/test/java/dan200/computercraft/core/LuaCoverage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/dan200/computercraft/core/LuaCoverage.java b/src/test/java/dan200/computercraft/core/LuaCoverage.java index e6e61e8f2..92998d629 100644 --- a/src/test/java/dan200/computercraft/core/LuaCoverage.java +++ b/src/test/java/dan200/computercraft/core/LuaCoverage.java @@ -23,7 +23,7 @@ import java.util.stream.Stream; class LuaCoverage { - private static final Path ROOT = new File( "src/main/resources/assets/computercraft/lua" ).toPath(); + private static final Path ROOT = new File( "src/main/resources/data/computercraft/lua" ).toPath(); private static final Path BIOS = ROOT.resolve( "bios.lua" ); private static final Path APIS = ROOT.resolve( "rom/apis" ); private static final Path SHELL = ROOT.resolve( "rom/programs/shell.lua" ); From 086fccd997a7339187b0ed17ac0727e5f2d92321 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 14 May 2020 17:27:50 +0100 Subject: [PATCH 227/711] Move the package library into a separate module Hopefully this makes it a little easier for people to use in custom shells (and anything else where it might be useful). --- .../lua/rom/modules/main/cc/require.lua | 121 ++++++++++++++++++ .../computercraft/lua/rom/programs/shell.lua | 93 +------------- .../spec/modules/cc/shell/require_spec.lua | 79 ++++++++++++ 3 files changed, 205 insertions(+), 88 deletions(-) create mode 100644 src/main/resources/assets/computercraft/lua/rom/modules/main/cc/require.lua create mode 100644 src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/require.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/require.lua new file mode 100644 index 000000000..a90e189b8 --- /dev/null +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/require.lua @@ -0,0 +1,121 @@ +--- This provides a pure Lua implementation of the builtin @{require} function +-- and @{package} library. +-- +-- Generally you do not need to use this module - it is injected into the +-- every program's environment. However, it may be useful when building a +-- custom shell or when running programs yourself. +-- +-- @module cc.require +-- @usage Construct the package and require function, and insert them into a +-- custom environment. +-- +-- local env = setmetatable({}, { __index = _ENV }) +-- local r = require "cc.require" +-- env.require, env.package = r.make(env, "/") + +local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua") +local expect = expect.expect + +local function preload(package) + return function(name) + if package.preload[name] then + return package.preload[name] + else + return nil, "no field package.preload['" .. name .. "']" + end + end +end + +local function from_file(package, env, dir) + return function(name) + local fname = string.gsub(name, "%.", "/") + local sError = "" + for pattern in string.gmatch(package.path, "[^;]+") do + local sPath = string.gsub(pattern, "%?", fname) + if sPath:sub(1, 1) ~= "/" then + sPath = fs.combine(dir, sPath) + end + if fs.exists(sPath) and not fs.isDir(sPath) then + local fnFile, sError = loadfile(sPath, nil, env) + if fnFile then + return fnFile, sPath + else + return nil, sError + end + else + if #sError > 0 then + sError = sError .. "\n " + end + sError = sError .. "no file '" .. sPath .. "'" + end + end + return nil, sError + end +end + +local function make_require(package) + local sentinel = {} + return function(name) + expect(1, name, "string") + + if package.loaded[name] == sentinel then + error("loop or previous error loading module '" .. name .. "'", 0) + end + + if package.loaded[name] then + return package.loaded[name] + end + + local sError = "module '" .. name .. "' not found:" + for _, searcher in ipairs(package.loaders) do + local loader = table.pack(searcher(name)) + if loader[1] then + package.loaded[name] = sentinel + local result = loader[1](name, table.unpack(loader, 2, loader.n)) + if result == nil then result = true end + + package.loaded[name] = result + return result + else + sError = sError .. "\n " .. loader[2] + end + end + error(sError, 2) + end +end + +--- Build an implementation of Lua's @{package} library, and a @{require} +-- function to load modules within it. +-- +-- @tparam table env The environment to load packages into. +-- @tparam string dir The directory that relative packages are loaded from. +-- @treturn function The new @{require} function. +-- @treturn table The new @{package} library. +local function make_package(env, dir) + expect(1, env, "table") + expect(2, dir, "string") + + local package = {} + package.loaded = { + _G = _G, + bit32 = bit32, + coroutine = coroutine, + math = math, + package = package, + string = string, + table = table, + } + package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" + if turtle then + package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" + elseif commands then + package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" + end + package.config = "/\n;\n?\n!\n-" + package.preload = {} + package.loaders = { preload(package), from_file(package, env, dir) } + + return make_require(package), package +end + +return { make = make_package } diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua index 843e28e71..0c6b5868b 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/shell.lua @@ -11,6 +11,7 @@ -- @module[module] shell local expect = dofile("rom/modules/main/cc/expect.lua").expect +local make_package = dofile("rom/modules/main/cc/require.lua").make local multishell = multishell local parentShell = shell @@ -28,94 +29,10 @@ local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {} local tProgramStack = {} local shell = {} --- @export -local function createShellEnv(sDir) - local tEnv = {} - tEnv.shell = shell - tEnv.multishell = multishell - - local package = {} - package.loaded = { - _G = _G, - bit32 = bit32, - coroutine = coroutine, - math = math, - package = package, - string = string, - table = table, - } - package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua" - if turtle then - package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua" - elseif commands then - package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua" - end - package.config = "/\n;\n?\n!\n-" - package.preload = {} - package.loaders = { - function(name) - if package.preload[name] then - return package.preload[name] - else - return nil, "no field package.preload['" .. name .. "']" - end - end, - function(name) - local fname = string.gsub(name, "%.", "/") - local sError = "" - for pattern in string.gmatch(package.path, "[^;]+") do - local sPath = string.gsub(pattern, "%?", fname) - if sPath:sub(1, 1) ~= "/" then - sPath = fs.combine(sDir, sPath) - end - if fs.exists(sPath) and not fs.isDir(sPath) then - local fnFile, sError = loadfile(sPath, nil, tEnv) - if fnFile then - return fnFile, sPath - else - return nil, sError - end - else - if #sError > 0 then - sError = sError .. "\n " - end - sError = sError .. "no file '" .. sPath .. "'" - end - end - return nil, sError - end, - } - - local sentinel = {} - local function require(name) - expect(1, name, "string") - if package.loaded[name] == sentinel then - error("loop or previous error loading module '" .. name .. "'", 0) - end - if package.loaded[name] then - return package.loaded[name] - end - - local sError = "module '" .. name .. "' not found:" - for _, searcher in ipairs(package.loaders) do - local loader = table.pack(searcher(name)) - if loader[1] then - package.loaded[name] = sentinel - local result = loader[1](name, table.unpack(loader, 2, loader.n)) - if result == nil then result = true end - - package.loaded[name] = result - return result - else - sError = sError .. "\n " .. loader[2] - end - end - error(sError, 2) - end - - tEnv.package = package - tEnv.require = require - - return tEnv +local function createShellEnv(dir) + local env = { shell = shell, multishell = multishell } + env.require, env.package = make_package(env, dir) + return env end -- Colours diff --git a/src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua b/src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua new file mode 100644 index 000000000..721476f9d --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/shell/require_spec.lua @@ -0,0 +1,79 @@ +describe("cc.require", function() + local r = require "cc.require" + local function mk() + local env = setmetatable({}, { __index = _ENV }) + env.require, env.package = r.make({}, "/test-files/modules") + return env.require, env.package + end + + local function setup(path, contents) + fs.delete("/test-files/modules") + io.open(path, "w"):write(contents):close() + end + + describe("require", function() + it("errors on recursive modules", function() + local require, package = mk() + package.preload.pkg = function() require "pkg" end + expect.error(require, "pkg"):eq("loop or previous error loading module 'pkg'") + end) + + it("supplies the current module name", function() + local require, package = mk() + package.preload.pkg = table.pack + expect(require("pkg")):same { n = 1, "pkg" } + end) + + it("returns true instead of nil", function() + local require, package = mk() + package.preload.pkg = function() return nil end + expect(require("pkg")):eq(true) + end) + + it("returns a constant value", function() + local require, package = mk() + package.preload.pkg = function() return {} end + expect(require("pkg")):eq(require("pkg")) + end) + + it("returns an error on not-found modules", function() + local require, package = mk() + package.path = "/?;/?.lua" + expect.error(require, "pkg"):eq( + "module 'pkg' not found:\n" .. + " no field package.preload['pkg']\n" .. + " no file '/pkg'\n" .. + " no file '/pkg.lua'") + end) + end) + + describe("the file loader", function() + local function get(path) + local require, package = mk() + if path then package.path = path end + return require + end + + it("works on absolute paths", function() + local require = get("/test-files/?.lua") + setup("test-files/some_module.lua", "return 123") + expect(require("some_module")):eq(123) + end) + + it("works on relative paths", function() + local require = get("?.lua") + setup("test-files/modules/some_module.lua", "return 123") + expect(require("some_module")):eq(123) + end) + + it("fails on syntax errors", function() + local require = get("?.lua") + setup("test-files/modules/some_module.lua", "1") + expect.error(require, "some_module"):str_match( + "^module 'some_module' not found:\n" .. + " no field package.preload%['some_module'%]\n" .. + " [^:]*some_module.lua:1: unexpected symbol near '1'$" + ) + end) + end) +end) From 96e7b60285a771ddaeecd20985cdb88904ebadb8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 14 May 2020 19:11:57 +0100 Subject: [PATCH 228/711] Display function arguments and positions in the REPL - cc.pretty.pretty now accepts two additional options: - function_args: Show function arguments - function_source: Show where functions are defined. - Expose the two options as lua.* settings (defaulting function_args to true, and function_source to false). These are then used in the Lua REPL. Closes #361 --- .../assets/computercraft/lua/bios.lua | 12 ++++ .../lua/rom/modules/main/cc/pretty.lua | 59 ++++++++++++++++--- .../computercraft/lua/rom/programs/lua.lua | 5 +- .../test-rom/spec/modules/cc/pretty_spec.lua | 19 +++++- 4 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/main/resources/assets/computercraft/lua/bios.lua b/src/main/resources/assets/computercraft/lua/bios.lua index 55688a4f2..4573f9826 100644 --- a/src/main/resources/assets/computercraft/lua/bios.lua +++ b/src/main/resources/assets/computercraft/lua/bios.lua @@ -938,11 +938,23 @@ settings.define("motd.path", { description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]], type = "string", }) + settings.define("lua.warn_against_use_of_local", { default = true, description = [[Print a message when input in the Lua REPL starts with the word 'local'. Local variables defined in the Lua REPL are be inaccessable on the next input.]], type = "boolean", }) +settings.define("lua.function_args", { + default = true, + description = "Show function arguments when printing functions.", + type = "boolean", +}) +settings.define("lua.function_source", { + default = false, + description = "Show where a function was defined when printing functions.", + type = "boolean", +}) + if term.isColour() then settings.define("bios.use_multishell", { default = true, diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua index 65718f949..33fce2c7a 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -19,8 +19,12 @@ -- local pretty = require "cc.pretty" -- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world"))) -local expect = require "cc.expect".expect -local type, getmetatable, setmetatable, colours, str_write = type, getmetatable, setmetatable, colours, write +local expect = require "cc.expect" +local expect, field = expect.expect, expect.field + +local type, getmetatable, setmetatable, colours, str_write, tostring = type, getmetatable, setmetatable, colours, write, tostring +local debug_info = type(debug) == "table" and type(debug.getinfo) == "function" and debug.getinfo +local debug_local = type(debug) == "table" and type(debug.getlocal) == "function" and debug.getlocal --- @{table.insert} alternative, but with the length stored inline. local function append(out, value) @@ -343,13 +347,38 @@ local function key_compare(a, b) return false end -local function pretty_impl(obj, tracking) +local function show_function(fn, options) + local info = debug_info and debug_info(fn, "Su") + + -- Include function source position if available + local name + if options.function_source and info and info.short_src and info.linedefined and info.linedefined >= 1 then + name = "function<" .. info.short_src .. ":" .. info.linedefined .. ">" + else + name = tostring(fn) + end + + -- Include arguments if a Lua function and if available. Lua will report "C" + -- functions as variadic. + if options.function_args and info and info.what == "Lua" and info.nparams and debug_local then + local args = {} + for i = 1, info.nparams do args[i] = debug_local(fn, i) or "?" end + if info.isvararg then args[#args + 1] = "..." end + name = name .. "(" .. table.concat(args, ", ") .. ")" + end + + return name +end + +local function pretty_impl(obj, options, tracking) local obj_type = type(obj) if obj_type == "string" then local formatted = ("%q"):format(obj):gsub("\\\n", "\\n") return text(formatted, colours.red) elseif obj_type == "number" then return text(tostring(obj), colours.magenta) + elseif obj_type == "function" then + return text(show_function(obj, options), colours.lightGrey) elseif obj_type ~= "table" or tracking[obj] then return text(tostring(obj), colours.lightGrey) elseif getmetatable(obj) ~= nil and getmetatable(obj).__tostring then @@ -371,15 +400,15 @@ local function pretty_impl(obj, tracking) local v = obj[k] local ty = type(k) if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then - append(doc, pretty_impl(v, tracking)) + append(doc, pretty_impl(v, options, tracking)) elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then append(doc, text(k .. " = ")) - append(doc, pretty_impl(v, tracking)) + append(doc, pretty_impl(v, options, tracking)) else append(doc, obracket) - append(doc, pretty_impl(k, tracking)) + append(doc, pretty_impl(k, options, tracking)) append(doc, cbracket) - append(doc, pretty_impl(v, tracking)) + append(doc, pretty_impl(v, options, tracking)) end end @@ -393,12 +422,24 @@ end -- This can then be rendered with @{write} or @{print}. -- -- @param obj The object to pretty-print. +-- @tparam[opt] { function_args = boolean, function_source = boolean } options +-- Controls how various properties are displayed. +-- - `function_args`: Show the arguments to a function if known (`false` by default). +-- - `function_source: Show where the function was defined, instead of +-- `function: xxxxxxxx` (`false` by default). -- @treturn Doc The object formatted as a document. -- @usage Display a table on the screen -- local pretty = require "cc.pretty" -- pretty.print(pretty.pretty({ 1, 2, 3 })) -local function pretty(obj) - return pretty_impl(obj, {}) +local function pretty(obj, options) + expect(2, options, "table", "nil") + options = options or {} + + local actual_options = { + function_source = field(options, "function_source", "boolean", "nil") or false, + function_args = field(options, "function_args", "boolean", "nil") or false, + } + return pretty_impl(obj, actual_options, {}) end return { diff --git a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua index 7ab9bda42..7418a017f 100644 --- a/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua +++ b/src/main/resources/assets/computercraft/lua/rom/programs/lua.lua @@ -95,7 +95,10 @@ while bRunning do local n = 1 while n < tResults.n or n <= nForcePrint do local value = tResults[n + 1] - local ok, serialised = pcall(pretty.pretty, value) + local ok, serialised = pcall(pretty.pretty, value, { + function_args = settings.get("lua.function_args"), + function_source = settings.get("lua.function_source"), + }) if ok then pretty.print(serialised) else diff --git a/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua index 2949c1a75..174751606 100644 --- a/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua +++ b/src/test/resources/test-rom/spec/modules/cc/pretty_spec.lua @@ -165,7 +165,7 @@ describe("cc.pretty", function() describe("pretty", function() -- We make use of "render" here, as it's considerably easier than checking against the actual structure. -- However, it does also mean our tests are less unit-like. - local function pretty(x, width) return pp.render(pp.pretty(x), width) end + local function pretty(x, width, options) return pp.render(pp.pretty(x, options), width) end describe("tables", function() it("displays empty tables", function() @@ -201,8 +201,21 @@ describe("cc.pretty", function() expect(pretty("hello\nworld")):eq('"hello\\nworld"') end) - it("shows functions", function() - expect(pretty(pretty)):eq(tostring(pretty)) + describe("functions", function() + it("shows functions", function() + expect(pretty(pretty)):eq(tostring(pretty)) + end) + + it("shows function arguments", function() + local f = function(a, ...) end + expect(pretty(f, nil, { function_args = true })):eq(tostring(f) .. "(a, ...)") + end) + + it("shows the function source", function() + local f = function(a, ...) end + expect(pretty(f, nil, { function_source = true })) + :str_match("^function<.*pretty_spec%.lua:%d+>$") + end) end) end) end) From c6b6b4479cbfc00173ac3701bfb99bda60faf5b9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 14 May 2020 19:23:47 +0100 Subject: [PATCH 229/711] Update changelog and fix doc typo --- .../resources/assets/computercraft/lua/rom/help/changelog.txt | 2 ++ .../resources/assets/computercraft/lua/rom/help/whatsnew.txt | 2 ++ .../assets/computercraft/lua/rom/modules/main/cc/pretty.lua | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 3d9f00769..6e6804037 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -7,6 +7,8 @@ * The Lua REPL warns when declaring locals (lupus590, exerro) * Add config to allow using command computers in survival. * Add fs.isDriveRoot - checks if a path is the root of a drive. +* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default. +* Move the shell's `require`/`package` implementation to a separate `cc.require` module. And several bug fixes: * Fix io.lines not accepting arguments. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index a3cb561de..772f17738 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -7,6 +7,8 @@ New features in CC: Tweaked 1.88.0 * The Lua REPL warns when declaring locals (lupus590, exerro) * Add config to allow using command computers in survival. * Add fs.isDriveRoot - checks if a path is the root of a drive. +* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default. +* Move the shell's `require`/`package` implementation to a separate `cc.require` module. And several bug fixes: * Fix io.lines not accepting arguments. diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua index 33fce2c7a..b934aa995 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -425,7 +425,7 @@ end -- @tparam[opt] { function_args = boolean, function_source = boolean } options -- Controls how various properties are displayed. -- - `function_args`: Show the arguments to a function if known (`false` by default). --- - `function_source: Show where the function was defined, instead of +-- - `function_source`: Show where the function was defined, instead of -- `function: xxxxxxxx` (`false` by default). -- @treturn Doc The object formatted as a document. -- @usage Display a table on the screen From 161a5b47077b3e3dfb9652cca55c5431a127735c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 10:03:47 +0100 Subject: [PATCH 230/711] Document and test the redstone library The tests may be a little agressive, but I wanted some sanity checks for the 1.15 API rewrite. --- doc/stub/redstone.lua | 114 +++++++++++++++++- illuaminate.sexp | 5 +- .../computercraft/core/apis/RedstoneAPI.java | 24 ++-- .../rom/modules/main/cc/shell/completion.lua | 12 +- .../test-rom/spec/apis/redstone_spec.lua | 92 ++++++++++++++ 5 files changed, 221 insertions(+), 26 deletions(-) create mode 100644 src/test/resources/test-rom/spec/apis/redstone_spec.lua diff --git a/doc/stub/redstone.lua b/doc/stub/redstone.lua index 217d41766..d19a80487 100644 --- a/doc/stub/redstone.lua +++ b/doc/stub/redstone.lua @@ -1,14 +1,120 @@ +--[[- Interact with redstone attached to this computer. + +The @{redstone} library exposes three "types" of redstone control: + - Binary input/output (@{setOutput}/@{getInput}): These simply check if a + redstone wire has any input or output. A signal strength of 1 and 15 are + treated the same. + - Analogue input/output (@{setAnalogueOutput}/@{getAnalogueInput}): These + work with the actual signal strength of the redstone wired, from 0 to 15. + - Bundled cables (@{setBundledOutput}/@{getBundledInput}): These interact with + "bundled" cables, such as those from Project:Red. These allow you to send + 16 separate on/off signals. Each channel corresponds to a colour, with the + first being @{colors.white} and the last @{colors.black}. + +Whenever a redstone input changes, a `redstone` event will be fired. This may +be used in or + +This module may also be referred to as `rs`. For example, one may call +`rs.getSides()` instead of @{redstone.getSides}. + +@module redstone +@usage Toggle the redstone signal above the computer every 0.5 seconds. + + while true do + redstone.setOutput("top", not redstone.getOutput("top")) + sleep(0.5) + end +@usage Mimic a redstone comparator in [subtraction mode][comparator]. + + while true do + local rear = rs.getAnalogueInput("back") + local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right")) + rs.setAnalogueOutput("front", math.max(rear - sides, 0)) + + os.pullEvent("redstone") -- Wait for a change to inputs. + end + +[comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on the Minecraft wiki." +]] + +--- Returns a table containing the six sides of the computer. Namely, "top", +-- "bottom", "left", "right", "front" and "back". +-- +-- @treturn { string... } A table of valid sides. function getSides() end + +--- Turn the redstone signal of a specific side on or off. +-- +-- @tparam string side The side to set. +-- @tparam boolean on Whether the redstone signal should be on or off. When on, +-- a signal strength of 15 is emitted. function setOutput(side, on) end + +--- Get the current redstone output of a specific side. +-- +-- @tparam string side The side to get. +-- @treturn boolean Whether the redstone output is on or off. +-- @see setOutput function getOutput(side) end + +--- Get the current redstone input of a specific side. +-- +-- @tparam string side The side to get. +-- @treturn boolean Whether the redstone input is on or off. function getInput(side) end -function setBundledOutput(side, output) end -function getBundledOutput(side) end -function getBundledInput(side) end -function testBundledInput(side, mask) end + +--- Set the redstone signal strength for a specific side. +-- +-- @tparam string side The side to set. +-- @tparam number value The signal strength, between 0 and 15. +-- @throws If `value` is not between 0 and 15. function setAnalogOutput(side, value) end setAnalogueOutput = setAnalogOutput + +--- Get the redstone output signal strength for a specific side. +-- +-- @tparam string side The side to get. +-- @treturn number The output signal strength, between 0 and 15. +-- @see setAnalogueOutput function getAnalogOutput(sid) end getAnalogueOutput = getAnalogOutput + +--- Get the redstone input signal strength for a specific side. +-- +-- @tparam string side The side to get. +-- @treturn number The input signal strength, between 0 and 15. function getAnalogInput(side) end getAnalogueInput = getAnalogInput + +--- Set the bundled cable output for a specific side. +-- +-- @tparam string side The side to set. +-- @tparam number The colour bitmask to set. +-- @see colors.subtract For removing a colour from the bitmask. +-- @see colors.combine For adding a colour to the bitmask. +function setBundledOutput(side, output) end + +--- Get the bundled cable output for a specific side. +-- +-- @tparam string side The side to get. +-- @treturn number The bundled cable's output. +function getBundledOutput(side) end + +--- Get the bundled cable input for a specific side. +-- +-- @tparam string side The side to get. +-- @treturn number The bundled cable's input. +-- @see testBundledInput To determine if a specific colour is set. +function getBundledInput(side) end + +--- Determine if a specific combination of colours are on for the given side. +-- +-- @tparam string side The side to test. +-- @tparam number mask The mask to test. +-- @see getBundledInput +-- @see colors.combine For adding a colour to the bitmask. +-- @usage Check if @{colors.white} and @{colors.black} are on for above the +-- computer. +-- +-- print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black))) +function testBundledInput(side, mask) end diff --git a/illuaminate.sexp b/illuaminate.sexp index 631a9eb58..769eba175 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -73,12 +73,10 @@ (/doc/stub/fs.lua /doc/stub/http.lua /doc/stub/os.lua - /doc/stub/redstone.lua /doc/stub/term.lua /doc/stub/turtle.lua /src/main/resources/*/computercraft/lua/rom/apis/io.lua - /src/main/resources/*/computercraft/lua/rom/apis/window.lua - /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua) + /src/main/resources/*/computercraft/lua/rom/apis/window.lua) (linters -doc:undocumented -doc:undocumented-arg)) @@ -87,7 +85,6 @@ (/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua /src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua - /src/main/resources/*/computercraft/lua/rom/programs/advanced/multishell.lua /src/main/resources/*/computercraft/lua/rom/programs/shell.lua) (linters -doc:unresolved-reference)) diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 1a987d519..fbb8feffa 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -16,11 +16,11 @@ import static dan200.computercraft.api.lua.ArgumentHelper.*; public class RedstoneAPI implements ILuaAPI { - private IAPIEnvironment m_environment; + private final IAPIEnvironment environment; public RedstoneAPI( IAPIEnvironment environment ) { - m_environment = environment; + this.environment = environment; } @Override @@ -63,31 +63,31 @@ public class RedstoneAPI implements ILuaAPI // setOutput ComputerSide side = parseSide( args ); boolean output = getBoolean( args, 1 ); - m_environment.setOutput( side, output ? 15 : 0 ); + environment.setOutput( side, output ? 15 : 0 ); return null; } case 2: // getOutput - return new Object[] { m_environment.getOutput( parseSide( args ) ) > 0 }; + return new Object[] { environment.getOutput( parseSide( args ) ) > 0 }; case 3: // getInput - return new Object[] { m_environment.getInput( parseSide( args ) ) > 0 }; + return new Object[] { environment.getInput( parseSide( args ) ) > 0 }; case 4: { // setBundledOutput ComputerSide side = parseSide( args ); int output = getInt( args, 1 ); - m_environment.setBundledOutput( side, output ); + environment.setBundledOutput( side, output ); return null; } case 5: // getBundledOutput - return new Object[] { m_environment.getBundledOutput( parseSide( args ) ) }; + return new Object[] { environment.getBundledOutput( parseSide( args ) ) }; case 6: // getBundledInput - return new Object[] { m_environment.getBundledInput( parseSide( args ) ) }; + return new Object[] { environment.getBundledInput( parseSide( args ) ) }; case 7: { // testBundledInput ComputerSide side = parseSide( args ); int mask = getInt( args, 1 ); - int input = m_environment.getBundledInput( side ); + int input = environment.getBundledInput( side ); return new Object[] { (input & mask) == mask }; } case 8: @@ -100,15 +100,15 @@ public class RedstoneAPI implements ILuaAPI { throw new LuaException( "Expected number in range 0-15" ); } - m_environment.setOutput( side, output ); + environment.setOutput( side, output ); return null; } case 10: case 11: // getAnalogOutput/getAnalogueOutput - return new Object[] { m_environment.getOutput( parseSide( args ) ) }; + return new Object[] { environment.getOutput( parseSide( args ) ) }; case 12: case 13: // getAnalogInput/getAnalogueInput - return new Object[] { m_environment.getInput( parseSide( args ) ) }; + return new Object[] { environment.getInput( parseSide( args ) ) }; default: return null; } diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua index 6be54fe2f..91d9ea7a4 100644 --- a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -141,12 +141,12 @@ return { program = program, -- Re-export various other functions - help = wrap(help.completeTopic), - choice = wrap(completion.choice), - peripheral = wrap(completion.peripheral), - side = wrap(completion.side), - setting = wrap(completion.setting), - command = wrap(completion.command), + help = wrap(help.completeTopic), --- Wraps @{help.completeTopic} as a @{build} compatible function. + choice = wrap(completion.choice), --- Wraps @{cc.completion.choice} as a @{build} compatible function. + peripheral = wrap(completion.peripheral), --- Wraps @{cc.completion.peripheral} as a @{build} compatible function. + side = wrap(completion.side), --- Wraps @{cc.completion.side} as a @{build} compatible function. + setting = wrap(completion.setting), --- Wraps @{cc.completion.setting} as a @{build} compatible function. + command = wrap(completion.command), --- Wraps @{cc.completion.command} as a @{build} compatible function. build = build, } diff --git a/src/test/resources/test-rom/spec/apis/redstone_spec.lua b/src/test/resources/test-rom/spec/apis/redstone_spec.lua new file mode 100644 index 000000000..17d8acab0 --- /dev/null +++ b/src/test/resources/test-rom/spec/apis/redstone_spec.lua @@ -0,0 +1,92 @@ +local function it_side(func, ...) + local arg = table.pack(...) + it("requires a specific side", function() + expect.error(func, 0):eq("bad argument #1 (string expected, got number)") + expect.error(func, "blah", table.unpack(arg)):eq("Invalid side.") + + func("top", table.unpack(arg)) + func("Top", table.unpack(arg)) + func("toP", table.unpack(arg)) + end) +end + +describe("The redstone library", function() + describe("redstone.setOutput", function() + it_side(redstone.setOutput, false) + + it("sets the output strength correctly", function() + redstone.setOutput("top", false) + expect(redstone.getAnalogueOutput("top")):eq(0) + + redstone.setOutput("top", true) + expect(redstone.getAnalogueOutput("top")):eq(15) + end) + end) + + describe("redstone.getOutput", function() + it_side(redstone.getOutput) + + it("gets the output strength correctly", function() + redstone.setAnalogueOutput("top", 0) + expect(redstone.getOutput("top")):eq(false) + + redstone.setAnalogueOutput("top", 1) + expect(redstone.getOutput("top")):eq(true) + + redstone.setAnalogueOutput("top", 15) + expect(redstone.getOutput("top")):eq(true) + end) + end) + + describe("redstone.getInput", function() + it_side(redstone.getInput) + end) + + describe("redstone.setAnalogueOutput", function() + it_side(redstone.setAnalogueOutput, 0) + + it("checks the strength parameter", function() + expect.error(redstone.setAnalogueOutput, "top", true):eq("bad argument #2 (number expected, got boolean)") + expect.error(redstone.setAnalogueOutput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)") + expect.error(redstone.setAnalogueOutput, "top", math.huge):eq("bad argument #2 (number expected, got inf)") + expect.error(redstone.setAnalogueOutput, "top", -1):eq("Expected number in range 0-15") + expect.error(redstone.setAnalogueOutput, "top", 16):eq("Expected number in range 0-15") + end) + end) + + describe("redstone.getAnalogueOutput", function() + it_side(redstone.getAnalogueOutput) + end) + + describe("redstone.getAnalogueInput", function() + it_side(redstone.getAnalogueInput) + end) + + describe("redstone.setBundledOutput", function() + it_side(redstone.setBundledOutput, 0) + + it("checks the mask parameter", function() + expect.error(redstone.setBundledOutput, "top", true):eq("bad argument #2 (number expected, got boolean)") + expect.error(redstone.setBundledOutput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)") + expect.error(redstone.setBundledOutput, "top", math.huge):eq("bad argument #2 (number expected, got inf)") + end) + end) + + describe("redstone.getBundledOutput", function() + it_side(redstone.getBundledOutput) + end) + + describe("redstone.getBundledInput", function() + it_side(redstone.getBundledInput) + end) + + describe("redstone.testBundledInput", function() + it_side(redstone.testBundledInput, 0) + + it("checks the mask parameter", function() + expect.error(redstone.testBundledInput, "top", true):eq("bad argument #2 (number expected, got boolean)") + expect.error(redstone.testBundledInput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)") + expect.error(redstone.testBundledInput, "top", math.huge):eq("bad argument #2 (number expected, got inf)") + end) + end) +end) From 13de2c4dd0143da86cf58c3ec7b3d99612b039ff Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 10:28:35 +0100 Subject: [PATCH 231/711] Fix location of cc.require Yay for 1.12->1.13 changes! --- src/main/resources/data/computercraft/lua/rom/help/changelog.txt | 1 + src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt | 1 + .../computercraft/lua/rom/modules/main/cc/require.lua | 0 3 files changed, 2 insertions(+) rename src/main/resources/{assets => data}/computercraft/lua/rom/modules/main/cc/require.lua (100%) diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 4cf0ce6b0..5616c8bc0 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -13,6 +13,7 @@ And several bug fixes: * Fix io.lines not accepting arguments. * Fix settings.load using an unknown global (MCJack123). +* Prevent computers scanning peripherals twice. # New features in CC: Tweaked 1.87.1 diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 772f17738..d99423023 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -13,5 +13,6 @@ New features in CC: Tweaked 1.88.0 And several bug fixes: * Fix io.lines not accepting arguments. * Fix settings.load using an unknown global (MCJack123). +* Prevent computers scanning peripherals twice. Type "help changelog" to see the full version history. diff --git a/src/main/resources/assets/computercraft/lua/rom/modules/main/cc/require.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/require.lua similarity index 100% rename from src/main/resources/assets/computercraft/lua/rom/modules/main/cc/require.lua rename to src/main/resources/data/computercraft/lua/rom/modules/main/cc/require.lua From d0deab3519215a647a767ffd0c4147983546c8f5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 10:48:31 +0100 Subject: [PATCH 232/711] Update changelog to include some missing things --- src/main/resources/data/computercraft/lua/rom/help/changelog.txt | 1 + src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 75f4de19a..1ce64df8a 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -9,6 +9,7 @@ * Add fs.isDriveRoot - checks if a path is the root of a drive. * `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default. * Move the shell's `require`/`package` implementation to a separate `cc.require` module. +* Move treasure programs into a separate external data pack. And several bug fixes: * Fix io.lines not accepting arguments. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index d99423023..eb087af78 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -9,6 +9,7 @@ New features in CC: Tweaked 1.88.0 * Add fs.isDriveRoot - checks if a path is the root of a drive. * `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default. * Move the shell's `require`/`package` implementation to a separate `cc.require` module. +* Move treasure programs into a separate external data pack. And several bug fixes: * Fix io.lines not accepting arguments. From d5f82fa458fd5ed50292629e554f38650df1d588 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 May 2020 13:21:16 +0100 Subject: [PATCH 233/711] Replace getMethodNames/callMethod with annotations (#447) When creating a peripheral or custom Lua object, one must implement two methods: - getMethodNames(): String[] - Returns the name of the methods - callMethod(int, ...): Object[] - Invokes the method using an index in the above array. This has a couple of problems: - It's somewhat unwieldy to use - you need to keep track of array indices, which leads to ugly code. - Functions which yield (for instance, those which run on the main thread) are blocking. This means we need to spawn new threads for each CC-side yield. We replace this system with a few changes: - @LuaFunction annotation: One may annotate a public instance method with this annotation. This then exposes a peripheral/lua object method. Furthermore, this method can accept and return a variety of types, which often makes functions cleaner (e.g. can return an int rather than an Object[], and specify and int argument rather than Object[]). - MethodResult: Instead of returning an Object[] and having blocking yields, functions return a MethodResult. This either contains an immediate return, or an instruction to yield with some continuation to resume with. MethodResult is then interpreted by the Lua runtime (i.e. Cobalt), rather than our weird bodgey hacks before. This means we no longer spawn new threads when yielding within CC. - Methods accept IArguments instead of a raw Object array. This has a few benefits: - Consistent argument handling - people no longer need to use ArgumentHelper (as it doesn't exist!), or even be aware of its existence - you're rather forced into using it. - More efficient code in some cases. We provide a Cobalt-specific implementation of IArguments, which avoids the boxing/unboxing when handling numbers and binary strings. --- build.gradle | 1 + .../computercraft/api/lua/ArgumentHelper.java | 334 ---------- .../computercraft/api/lua/IArguments.java | 407 ++++++++++++ .../api/lua/IDynamicLuaObject.java | 45 ++ .../dan200/computercraft/api/lua/ILuaAPI.java | 5 +- .../computercraft/api/lua/ILuaCallback.java | 27 + .../computercraft/api/lua/ILuaContext.java | 82 +-- .../computercraft/api/lua/ILuaObject.java | 55 -- .../computercraft/api/lua/ILuaTask.java | 8 +- .../computercraft/api/lua/LuaException.java | 21 +- .../computercraft/api/lua/LuaFunction.java | 58 ++ .../computercraft/api/lua/LuaValues.java | 152 +++++ .../computercraft/api/lua/MethodResult.java | 170 +++++ .../api/lua/ObjectArguments.java | 66 ++ .../api/peripheral/IComputerAccess.java | 6 +- .../api/peripheral/IDynamicPeripheral.java | 53 ++ .../api/peripheral/IPeripheral.java | 61 +- .../api/peripheral/NotAttachedException.java | 2 +- .../api/turtle/ITurtleAccess.java | 14 +- .../api/turtle/ITurtleCommand.java | 8 +- .../api/turtle/event/TurtleBlockEvent.java | 5 +- .../turtle/event/TurtleInspectItemEvent.java | 5 +- .../core/apis/ComputerAccess.java | 2 +- .../dan200/computercraft/core/apis/FSAPI.java | 579 ++++++++--------- .../computercraft/core/apis/HTTPAPI.java | 224 +++---- .../core/apis/IAPIEnvironment.java | 2 +- .../dan200/computercraft/core/apis/OSAPI.java | 400 +++++------- .../core/apis/PeripheralAPI.java | 327 +++++----- .../computercraft/core/apis/RedstoneAPI.java | 148 ++--- .../computercraft/core/apis/TableHelper.java | 6 +- .../computercraft/core/apis/TermAPI.java | 283 +------- .../computercraft/core/apis/TermMethods.java | 222 +++++++ .../apis/handles/BinaryReadableHandle.java | 354 +++++----- .../apis/handles/BinaryWritableHandle.java | 136 ++-- .../apis/handles/EncodedReadableHandle.java | 204 +++--- .../apis/handles/EncodedWritableHandle.java | 112 ++-- .../core/apis/handles/HandleGeneric.java | 36 +- .../core/apis/http/CheckUrl.java | 4 +- .../core/apis/http/request/HttpRequest.java | 11 +- .../apis/http/request/HttpRequestHandler.java | 8 +- .../apis/http/request/HttpResponseHandle.java | 50 +- .../core/apis/http/websocket/Websocket.java | 10 +- .../apis/http/websocket/WebsocketHandle.java | 153 ++--- .../apis/http/websocket/WebsocketHandler.java | 4 +- .../core/asm/DeclaringClassLoader.java | 24 + .../computercraft/core/asm/Generator.java | 320 ++++++++++ .../computercraft/core/asm/IntCache.java | 41 ++ .../computercraft/core/asm/LuaMethod.java | 30 + .../computercraft/core/asm/NamedMethod.java | 40 ++ .../computercraft/core/asm/ObjectSource.java | 33 + .../core/asm/PeripheralMethod.java | 33 + .../computercraft/core/asm/Reflect.java | 95 +++ .../computercraft/core/asm/TaskCallback.java | 58 ++ .../core/computer/ApiWrapper.java | 18 +- .../computercraft/core/computer/Computer.java | 2 +- .../core/computer/ComputerExecutor.java | 4 +- .../core/computer/Environment.java | 6 +- .../computercraft/core/lua/BasicFunction.java | 75 +++ .../core/lua/CobaltLuaMachine.java | 186 ++---- .../computercraft/core/lua/ILuaMachine.java | 6 +- .../core/lua/ResultInterpreterFunction.java | 121 ++++ .../core/lua/VarargArguments.java | 102 +++ .../shared/computer/apis/CommandAPI.java | 231 +++---- .../computer/blocks/ComputerPeripheral.java | 80 ++- .../commandblock/CommandBlockPeripheral.java | 71 +- .../diskdrive/DiskDrivePeripheral.java | 171 +++-- .../peripheral/diskdrive/TileDiskDrive.java | 4 +- .../peripheral/modem/ModemPeripheral.java | 149 ++--- .../modem/wired/WiredModemPeripheral.java | 218 +++---- .../wireless/WirelessModemPeripheral.java | 2 +- .../peripheral/monitor/MonitorPeripheral.java | 226 ++----- .../peripheral/monitor/TileMonitor.java | 8 +- .../peripheral/printer/PrinterPeripheral.java | 159 ++--- .../peripheral/speaker/SpeakerPeripheral.java | 72 +-- .../shared/pocket/apis/PocketAPI.java | 142 ++-- .../shared/turtle/apis/TurtleAPI.java | 604 +++++++++--------- .../shared/turtle/core/TurtleBrain.java | 47 +- .../upgrades/CraftingTablePeripheral.java | 43 +- .../computercraft/shared/util/StringUtil.java | 14 +- .../computercraft/ContramapMatcher.java | 54 ++ .../core/ComputerTestDelegate.java | 383 +++++------ .../core/apis/ObjectWrapper.java | 83 +-- .../handles/BinaryReadableHandleTest.java | 14 +- .../computercraft/core/asm/GeneratorTest.java | 253 ++++++++ .../computercraft/core/asm/MethodTest.java | 208 ++++++ .../core/computer/ComputerBootstrap.java | 66 +- .../core/computer/ComputerTest.java | 18 +- .../core/filesystem/FileSystemTest.java | 4 +- .../shared/wired/NetworkTest.java | 17 - src/test/resources/benchmark.lua | 24 + .../test-rom/spec/apis/redstone_spec.lua | 2 +- 91 files changed, 5288 insertions(+), 4133 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java create mode 100644 src/main/java/dan200/computercraft/api/lua/IArguments.java create mode 100644 src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java create mode 100644 src/main/java/dan200/computercraft/api/lua/ILuaCallback.java delete mode 100644 src/main/java/dan200/computercraft/api/lua/ILuaObject.java create mode 100644 src/main/java/dan200/computercraft/api/lua/LuaFunction.java create mode 100644 src/main/java/dan200/computercraft/api/lua/LuaValues.java create mode 100644 src/main/java/dan200/computercraft/api/lua/MethodResult.java create mode 100644 src/main/java/dan200/computercraft/api/lua/ObjectArguments.java create mode 100644 src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java create mode 100644 src/main/java/dan200/computercraft/core/apis/TermMethods.java create mode 100644 src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java create mode 100644 src/main/java/dan200/computercraft/core/asm/Generator.java create mode 100644 src/main/java/dan200/computercraft/core/asm/IntCache.java create mode 100644 src/main/java/dan200/computercraft/core/asm/LuaMethod.java create mode 100644 src/main/java/dan200/computercraft/core/asm/NamedMethod.java create mode 100644 src/main/java/dan200/computercraft/core/asm/ObjectSource.java create mode 100644 src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java create mode 100644 src/main/java/dan200/computercraft/core/asm/Reflect.java create mode 100644 src/main/java/dan200/computercraft/core/asm/TaskCallback.java create mode 100644 src/main/java/dan200/computercraft/core/lua/BasicFunction.java create mode 100644 src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java create mode 100644 src/main/java/dan200/computercraft/core/lua/VarargArguments.java create mode 100644 src/test/java/dan200/computercraft/ContramapMatcher.java create mode 100644 src/test/java/dan200/computercraft/core/asm/GeneratorTest.java create mode 100644 src/test/java/dan200/computercraft/core/asm/MethodTest.java create mode 100644 src/test/resources/benchmark.lua diff --git a/build.gradle b/build.gradle index 73446fdd6..5e75050db 100644 --- a/build.gradle +++ b/build.gradle @@ -109,6 +109,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' + testImplementation 'org.hamcrest:hamcrest:2.2' deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" } diff --git a/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java b/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java deleted file mode 100644 index 97500fa97..000000000 --- a/src/main/java/dan200/computercraft/api/lua/ArgumentHelper.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ -package dan200.computercraft.api.lua; - -import dan200.computercraft.api.peripheral.IComputerAccess; -import dan200.computercraft.api.peripheral.IPeripheral; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Map; - -/** - * Provides methods for extracting values and validating Lua arguments, such as those provided to - * {@link ILuaObject#callMethod(ILuaContext, int, Object[])} or - * {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}. - * - * This provides two sets of functions: the {@code get*} methods, which require an argument to be valid, and - * {@code opt*}, which accept a default value and return that if the argument was not present or was {@code null}. - * If the argument is of the wrong type, a suitable error message will be thrown, with a similar format to Lua's own - * error messages. - * - *

Example usage:

- *
- * {@code
- * int slot = getInt( args, 0 );
- * int amount = optInt( args, 1, 64 );
- * }
- * 
- */ -public final class ArgumentHelper -{ - private ArgumentHelper() - { - } - - /** - * Get a string representation of the given value's type. - * - * @param value The value whose type we are trying to compute. - * @return A string representation of the given value's type, in a similar format to that provided by Lua's - * {@code type} function. - */ - @Nonnull - public static String getType( @Nullable Object value ) - { - if( value == null ) return "nil"; - if( value instanceof String ) return "string"; - if( value instanceof Boolean ) return "boolean"; - if( value instanceof Number ) return "number"; - if( value instanceof Map ) return "table"; - return "userdata"; - } - - /** - * Construct a "bad argument" exception, from an expected type and the actual value provided. - * - * @param index The argument number, starting from 0. - * @param expected The expected type for this argument. - * @param actual The actual value provided for this argument. - * @return The constructed exception, which should be thrown immediately. - */ - @Nonnull - public static LuaException badArgumentOf( int index, @Nonnull String expected, @Nullable Object actual ) - { - return badArgument( index, expected, getType( actual ) ); - } - - /** - * Construct a "bad argument" exception, from an expected and actual type. - * - * @param index The argument number, starting from 0. - * @param expected The expected type for this argument. - * @param actual The provided type for this argument. - * @return The constructed exception, which should be thrown immediately. - */ - @Nonnull - public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual ) - { - return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); - } - - /** - * Get an argument as a double. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not a number. - * @see #getFiniteDouble(Object[], int) if you require this to be finite (i.e. not infinite or NaN). - */ - public static double getDouble( @Nonnull Object[] args, int index ) throws LuaException - { - if( index >= args.length ) throw badArgument( index, "number", "nil" ); - Object value = args[index]; - if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); - return ((Number) value).doubleValue(); - } - - /** - * Get an argument as an integer. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not an integer. - */ - public static int getInt( @Nonnull Object[] args, int index ) throws LuaException - { - return (int) getLong( args, index ); - } - - /** - * Get an argument as a long. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not a long. - */ - public static long getLong( @Nonnull Object[] args, int index ) throws LuaException - { - if( index >= args.length ) throw badArgument( index, "number", "nil" ); - Object value = args[index]; - if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); - return checkFinite( index, (Number) value ).longValue(); - } - - /** - * Get an argument as a finite number (not infinite or NaN). - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not finite. - */ - public static double getFiniteDouble( @Nonnull Object[] args, int index ) throws LuaException - { - return checkFinite( index, getDouble( args, index ) ); - } - - /** - * Get an argument as a boolean. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not a boolean. - */ - public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException - { - if( index >= args.length ) throw badArgument( index, "boolean", "nil" ); - Object value = args[index]; - if( !(value instanceof Boolean) ) throw badArgumentOf( index, "boolean", value ); - return (Boolean) value; - } - - /** - * Get an argument as a string. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not a string. - */ - @Nonnull - public static String getString( @Nonnull Object[] args, int index ) throws LuaException - { - if( index >= args.length ) throw badArgument( index, "string", "nil" ); - Object value = args[index]; - if( !(value instanceof String) ) throw badArgumentOf( index, "string", value ); - return (String) value; - } - - /** - * Get an argument as a table. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @return The argument's value. - * @throws LuaException If the value is not a table. - */ - @Nonnull - public static Map getTable( @Nonnull Object[] args, int index ) throws LuaException - { - if( index >= args.length ) throw badArgument( index, "table", "nil" ); - Object value = args[index]; - if( !(value instanceof Map) ) throw badArgumentOf( index, "table", value ); - return (Map) value; - } - - /** - * Get an argument as a double. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a number. - */ - public static double optDouble( @Nonnull Object[] args, int index, double def ) throws LuaException - { - Object value = index < args.length ? args[index] : null; - if( value == null ) return def; - if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); - return ((Number) value).doubleValue(); - } - - /** - * Get an argument as an int. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a number. - */ - public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException - { - return (int) optLong( args, index, def ); - } - - /** - * Get an argument as a long. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a number. - */ - public static long optLong( @Nonnull Object[] args, int index, long def ) throws LuaException - { - Object value = index < args.length ? args[index] : null; - if( value == null ) return def; - if( !(value instanceof Number) ) throw badArgumentOf( index, "number", value ); - return checkFinite( index, (Number) value ).longValue(); - } - - /** - * Get an argument as a finite number (not infinite or NaN). - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not finite. - */ - public static double optFiniteDouble( @Nonnull Object[] args, int index, double def ) throws LuaException - { - return checkFinite( index, optDouble( args, index, def ) ); - } - - /** - * Get an argument as a boolean. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a boolean. - */ - public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException - { - Object value = index < args.length ? args[index] : null; - if( value == null ) return def; - if( !(value instanceof Boolean) ) throw badArgumentOf( index, "boolean", value ); - return (Boolean) value; - } - - /** - * Get an argument as a string. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a string. - */ - public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException - { - Object value = index < args.length ? args[index] : null; - if( value == null ) return def; - if( !(value instanceof String) ) throw badArgumentOf( index, "string", value ); - return (String) value; - } - - /** - * Get an argument as a table. - * - * @param args The arguments to extract from. - * @param index The index into the argument array to read from. - * @param def The default value, if this argument is not given. - * @return The argument's value, or {@code def} if none was provided. - * @throws LuaException If the value is not a table. - */ - public static Map optTable( @Nonnull Object[] args, int index, Map def ) throws LuaException - { - Object value = index < args.length ? args[index] : null; - if( value == null ) return def; - if( !(value instanceof Map) ) throw badArgumentOf( index, "table", value ); - return (Map) value; - } - - private static Number checkFinite( int index, Number value ) throws LuaException - { - checkFinite( index, value.doubleValue() ); - return value; - } - - private static double checkFinite( int index, double value ) throws LuaException - { - if( !Double.isFinite( value ) ) throw badArgument( index, "number", getNumericType( value ) ); - return value; - } - - /** - * Returns a more detailed representation of this number's type. If this is finite, it will just return "number", - * otherwise it returns whether it is infinite or NaN. - * - * @param value The value to extract the type for. - * @return This value's numeric type. - */ - @Nonnull - public static String getNumericType( double value ) - { - if( Double.isNaN( value ) ) return "nan"; - if( value == Double.POSITIVE_INFINITY ) return "inf"; - if( value == Double.NEGATIVE_INFINITY ) return "-inf"; - return "number"; - } -} diff --git a/src/main/java/dan200/computercraft/api/lua/IArguments.java b/src/main/java/dan200/computercraft/api/lua/IArguments.java new file mode 100644 index 000000000..c19ed4526 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/IArguments.java @@ -0,0 +1,407 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Optional; + +import static dan200.computercraft.api.lua.LuaValues.checkFinite; + +/** + * The arguments passed to a function. + */ +public interface IArguments +{ + /** + * Get the number of arguments passed to this function. + * + * @return The number of passed arguments. + */ + int count(); + + /** + * Get the argument at the specific index. The returned value must obey the following conversion rules: + * + *
    + *
  • Lua values of type "string" will be represented by a {@link String}.
  • + *
  • Lua values of type "number" will be represented by a {@link Number}.
  • + *
  • Lua values of type "boolean" will be represented by a {@link Boolean}.
  • + *
  • Lua values of type "table" will be represented by a {@link Map}.
  • + *
  • Lua values of any other type will be represented by a {@code null} value.
  • + *
+ * + * @param index The argument number. + * @return The argument's value, or {@code null} if not present. + */ + @Nullable + Object get( int index ); + + /** + * Drop a number of arguments. The returned arguments instance will access arguments at position {@code i + count}, + * rather than {@code i}. However, errors will still use the given argument index. + * + * @param count The number of arguments to drop. + * @return The new {@link IArguments} instance. + */ + IArguments drop( int count ); + + default Object[] getAll() + { + Object[] result = new Object[count()]; + for( int i = 0; i < result.length; i++ ) result[i] = get( i ); + return result; + } + + /** + * Get an argument as a double. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not a number. + * @see #getFiniteDouble(int) if you require this to be finite (i.e. not infinite or NaN). + */ + default double getDouble( int index ) throws LuaException + { + Object value = get( index ); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return ((Number) value).doubleValue(); + } + + /** + * Get an argument as an integer. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not an integer. + */ + default int getInt( int index ) throws LuaException + { + return (int) getLong( index ); + } + + /** + * Get an argument as a long. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not a long. + */ + default long getLong( int index ) throws LuaException + { + Object value = get( index ); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return LuaValues.checkFiniteNum( index, (Number) value ).longValue(); + } + + /** + * Get an argument as a finite number (not infinite or NaN). + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not finite. + */ + default double getFiniteDouble( int index ) throws LuaException + { + return checkFinite( index, getDouble( index ) ); + } + + /** + * Get an argument as a boolean. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not a boolean. + */ + default boolean getBoolean( int index ) throws LuaException + { + Object value = get( index ); + if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value ); + return (Boolean) value; + } + + /** + * Get an argument as a string. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not a string. + */ + @Nonnull + default String getString( int index ) throws LuaException + { + Object value = get( index ); + if( !(value instanceof String) ) throw LuaValues.badArgumentOf( index, "string", value ); + return (String) value; + } + + /** + * Get a string argument as a byte array. + * + * @param index The argument number. + * @return The argument's value. This is a read only buffer. + * @throws LuaException If the value is not a string. + */ + @Nonnull + default ByteBuffer getBytes( int index ) throws LuaException + { + return LuaValues.encode( getString( index ) ); + } + + /** + * Get a string argument as an enum value. + * + * @param index The argument number. + * @param klass The type of enum to parse. + * @param The type of enum to parse. + * @return The argument's value. + * @throws LuaException If the value is not a string or not a valid option for this enum. + */ + @Nonnull + default > T getEnum( int index, Class klass ) throws LuaException + { + return LuaValues.checkEnum( index, klass, getString( index ) ); + } + + /** + * Get an argument as a table. + * + * @param index The argument number. + * @return The argument's value. + * @throws LuaException If the value is not a table. + */ + @Nonnull + default Map getTable( int index ) throws LuaException + { + Object value = get( index ); + if( !(value instanceof Map) ) throw LuaValues.badArgumentOf( index, "table", value ); + return (Map) value; + } + + /** + * Get an argument as a double. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a number. + */ + @Nonnull + default Optional optDouble( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return Optional.of( ((Number) value).doubleValue() ); + } + + /** + * Get an argument as an int. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a number. + */ + @Nonnull + default Optional optInt( int index ) throws LuaException + { + return optLong( index ).map( Long::intValue ); + } + + /** + * Get an argument as a long. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a number. + */ + default Optional optLong( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return Optional.of( LuaValues.checkFiniteNum( index, (Number) value ).longValue() ); + } + + /** + * Get an argument as a finite number (not infinite or NaN). + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not finite. + */ + default Optional optFiniteDouble( int index ) throws LuaException + { + Optional value = optDouble( index ); + if( value.isPresent() ) LuaValues.checkFiniteNum( index, value.get() ); + return value; + } + + /** + * Get an argument as a boolean. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a boolean. + */ + default Optional optBoolean( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value ); + return Optional.of( (Boolean) value ); + } + + /** + * Get an argument as a string. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a string. + */ + default Optional optString( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof String) ) throw LuaValues.badArgumentOf( index, "string", value ); + return Optional.of( (String) value ); + } + + /** + * Get a string argument as a byte array. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. This is a read only buffer. + * @throws LuaException If the value is not a string. + */ + default Optional optBytes( int index ) throws LuaException + { + return optString( index ).map( LuaValues::encode ); + } + + /** + * Get a string argument as an enum value. + * + * @param index The argument number. + * @param klass The type of enum to parse. + * @param The type of enum to parse. + * @return The argument's value. + * @throws LuaException If the value is not a string or not a valid option for this enum. + */ + @Nonnull + default > Optional optEnum( int index, Class klass ) throws LuaException + { + Optional str = optString( index ); + return str.isPresent() ? Optional.of( LuaValues.checkEnum( index, klass, str.get() ) ) : Optional.empty(); + } + + /** + * Get an argument as a table. + * + * @param index The argument number. + * @return The argument's value, or {@link Optional#empty()} if not present. + * @throws LuaException If the value is not a table. + */ + default Optional> optTable( int index ) throws LuaException + { + Object value = get( index ); + if( value == null ) return Optional.empty(); + if( !(value instanceof Map) ) throw LuaValues.badArgumentOf( index, "map", value ); + return Optional.of( (Map) value ); + } + + /** + * Get an argument as a double. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + default double optDouble( int index, double def ) throws LuaException + { + return optDouble( index ).orElse( def ); + } + + /** + * Get an argument as an int. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + default int optInt( int index, int def ) throws LuaException + { + return optInt( index ).orElse( def ); + } + + /** + * Get an argument as a long. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a number. + */ + default long optLong( int index, long def ) throws LuaException + { + return optLong( index ).orElse( def ); + } + + /** + * Get an argument as a finite number (not infinite or NaN). + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not finite. + */ + default double optFiniteDouble( int index, double def ) throws LuaException + { + return optFiniteDouble( index ).orElse( def ); + } + + /** + * Get an argument as a boolean. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a boolean. + */ + default boolean optBoolean( int index, boolean def ) throws LuaException + { + return optBoolean( index ).orElse( def ); + } + + /** + * Get an argument as a string. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a string. + */ + default String optString( int index, String def ) throws LuaException + { + return optString( index ).orElse( def ); + } + + /** + * Get an argument as a table. + * + * @param index The argument number. + * @param def The default value, if this argument is not given. + * @return The argument's value, or {@code def} if none was provided. + * @throws LuaException If the value is not a table. + */ + default Map optTable( int index, Map def ) throws LuaException + { + return optTable( index ).orElse( def ); + } +} diff --git a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java new file mode 100644 index 000000000..13b2c7a8f --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java @@ -0,0 +1,45 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.peripheral.IDynamicPeripheral; + +import javax.annotation.Nonnull; + +/** + * An interface for representing custom objects returned by peripherals or other Lua objects. + * + * Generally, one does not need to implement this type - it is sufficient to return an object with some methods + * annotated with {@link LuaFunction}. {@link IDynamicLuaObject} is useful when you wish your available methods to + * change at runtime. + */ +public interface IDynamicLuaObject +{ + /** + * Get the names of the methods that this object implements. This should not change over the course of the object's + * lifetime. + * + * @return The method names this object provides. + * @see IDynamicPeripheral#getMethodNames() + */ + @Nonnull + String[] getMethodNames(); + + /** + * Called when a user calls one of the methods that this object implements. + * + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which method index from {@link #getMethodNames()} the computer wishes + * to call. + * @param arguments The arguments for this method. + * @return The result of this function. Either an immediate value ({@link MethodResult#of(Object...)} or an + * instruction to yield. + * @throws LuaException If the function threw an exception. + */ + @Nonnull + MethodResult callMethod( @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java index a37f0404a..ae405e3aa 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java @@ -8,7 +8,8 @@ package dan200.computercraft.api.lua; import dan200.computercraft.api.ComputerCraftAPI; /** - * Represents a {@link ILuaObject} which is stored as a global variable on computer startup. + * Represents a Lua object which is stored as a global variable on computer startup. This must either provide + * {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}. * * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred * to use peripherals to provide functionality to users. @@ -16,7 +17,7 @@ import dan200.computercraft.api.ComputerCraftAPI; * @see ILuaAPIFactory * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) */ -public interface ILuaAPI extends ILuaObject +public interface ILuaAPI { /** * Get the globals this API will be assigned to. This will override any other global, so you should diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java new file mode 100644 index 000000000..f05d82a73 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java @@ -0,0 +1,27 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import javax.annotation.Nonnull; + +/** + * A continuation which is called when this coroutine is resumed. + * + * @see MethodResult#yield(Object[], ILuaCallback) + */ +public interface ILuaCallback +{ + /** + * Resume this coroutine. + * + * @param args The result of resuming this coroutine. These will have the same form as described in + * {@link LuaFunction}. + * @return The result of this continuation. Either the result to return to the callee, or another yield. + * @throws LuaException On an error. + */ + @Nonnull + MethodResult resume( Object[] args ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java index 623f19a74..569b61e5b 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java @@ -6,99 +6,25 @@ package dan200.computercraft.api.lua; import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** - * An interface passed to peripherals and {@link ILuaObject}s by computers or turtles, providing methods - * that allow the peripheral call to wait for events before returning, just like in lua. This is very useful if you need - * to signal work to be performed on the main thread, and don't want to return until the work has been completed. + * An interface passed to peripherals and {@link IDynamicLuaObject}s by computers or turtles, providing methods + * that allow the peripheral call to interface with the computer. */ public interface ILuaContext { - /** - * Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly - * equivalent to {@code os.pullEvent()} in lua. - * - * @param filter A specific event to wait for, or null to wait for any event. - * @return An object array containing the name of the event that occurred, and any event parameters. - * @throws LuaException If the user presses CTRL+T to terminate the current program while pullEvent() is - * waiting for an event, a "Terminated" exception will be thrown here. - * - * Do not attempt to catch this exception. You should use {@link #pullEventRaw(String)} - * should you wish to disable termination. - * @throws InterruptedException If the user shuts down or reboots the computer while pullEvent() is waiting for an - * event, InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state. - */ - @Nonnull - default Object[] pullEvent( @Nullable String filter ) throws LuaException, InterruptedException - { - Object[] results = pullEventRaw( filter ); - if( results.length >= 1 && results[0].equals( "terminate" ) ) throw new LuaException( "Terminated", 0 ); - return results; - } - - /** - * The same as {@link #pullEvent(String)}, except "terminated" events are ignored. Only use this if you want to - * prevent program termination, which is not recommended. This method is exactly equivalent to - * {@code os.pullEventRaw()} in lua. - * - * @param filter A specific event to wait for, or null to wait for any event. - * @return An object array containing the name of the event that occurred, and any event parameters. - * @throws InterruptedException If the user shuts down or reboots the computer while pullEventRaw() is waiting for - * an event, InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state. - * @see #pullEvent(String) - */ - @Nonnull - default Object[] pullEventRaw( @Nullable String filter ) throws InterruptedException - { - return yield( new Object[] { filter } ); - } - - /** - * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to - * {@code coroutine.yield()} in lua. Use {@code pullEvent()} if you wish to wait for events. - * - * @param arguments An object array containing the arguments to pass to coroutine.yield() - * @return An object array containing the return values from coroutine.yield() - * @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended, - * InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state. - * @see #pullEvent(String) - */ - @Nonnull - Object[] yield( @Nullable Object[] arguments ) throws InterruptedException; - - /** - * Queue a task to be executed on the main server thread at the beginning of next tick, waiting for it to complete. - * This should be used when you need to interact with the world in a thread-safe manner. - * - * Note that the return values of your task are handled as events, meaning more complex objects such as maps or - * {@link ILuaObject} will not preserve their identities. - * - * @param task The task to execute on the main thread. - * @return The objects returned by {@code task}. - * @throws LuaException If the task could not be queued, or if the task threw an exception. - * @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended, - * InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state. - */ - @Nullable - Object[] executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException, InterruptedException; - /** * Queue a task to be executed on the main server thread at the beginning of next tick, but do not wait for it to * complete. This should be used when you need to interact with the world in a thread-safe manner but do not care * about the result or you wish to run asynchronously. * * When the task has finished, it will enqueue a {@code task_completed} event, which takes the task id, a success - * value and the return values, or an error message if it failed. If you need to wait on this event, it may be - * better to use {@link #executeMainThreadTask(ILuaTask)}. + * value and the return values, or an error message if it failed. * * @param task The task to execute on the main thread. * @return The "id" of the task. This will be the first argument to the {@code task_completed} event. * @throws LuaException If the task could not be queued. + * @see LuaFunction#mainThread() To run functions on the main thread and return their results synchronously. */ long issueMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; } diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaObject.java b/src/main/java/dan200/computercraft/api/lua/ILuaObject.java deleted file mode 100644 index 4d0f37f89..000000000 --- a/src/main/java/dan200/computercraft/api/lua/ILuaObject.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ -package dan200.computercraft.api.lua; - -import dan200.computercraft.api.peripheral.IComputerAccess; -import dan200.computercraft.api.peripheral.IPeripheral; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * An interface for representing custom objects returned by {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])} - * calls. - * - * Return objects implementing this interface to expose objects with methods to lua. - */ -public interface ILuaObject -{ - /** - * Get the names of the methods that this object implements. This works the same as {@link IPeripheral#getMethodNames()}. - * See that method for detailed documentation. - * - * @return The method names this object provides. - * @see IPeripheral#getMethodNames() - */ - @Nonnull - String[] getMethodNames(); - - /** - * Called when a user calls one of the methods that this object implements. This works the same as - * {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}}. See that method for detailed - * documentation. - * - * @param context The context of the currently running lua thread. This can be used to wait for events - * or otherwise yield. - * @param method An integer identifying which of the methods from getMethodNames() the computercraft - * wishes to call. The integer indicates the index into the getMethodNames() table - * that corresponds to the string passed into peripheral.call() - * @param arguments The arguments for this method. See {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])} - * the possible values and conversion rules. - * @return An array of objects, representing the values you wish to return to the Lua program. - * See {@link IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])} for the valid values and - * conversion rules. - * @throws LuaException If the task could not be queued, or if the task threw an exception. - * @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended, - * InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state.w - * @see IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[]) - */ - @Nullable - Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException; -} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java index f99ce283b..4ea060358 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java @@ -8,11 +8,10 @@ package dan200.computercraft.api.lua; import javax.annotation.Nullable; /** - * A task which can be executed via {@link ILuaContext#executeMainThreadTask(ILuaTask)} or - * {@link ILuaContext#issueMainThreadTask(ILuaTask)}. This will be run on the main thread, at the beginning of the + * A task which can be executed via {@link ILuaContext#issueMainThreadTask(ILuaTask)} This will be run on the main + * thread, at the beginning of the * next tick. * - * @see ILuaContext#executeMainThreadTask(ILuaTask) * @see ILuaContext#issueMainThreadTask(ILuaTask) */ @FunctionalInterface @@ -21,8 +20,7 @@ public interface ILuaTask /** * Execute this task. * - * @return The arguments to add to the {@code task_completed} event. These will be returned by - * {@link ILuaContext#executeMainThreadTask(ILuaTask)}. + * @return The arguments to add to the {@code task_completed} event. * @throws LuaException If you throw any exception from this function, a lua error will be raised with the * same message as your exception. Use this to throw appropriate errors if the wrong * arguments are supplied to your method. diff --git a/src/main/java/dan200/computercraft/api/lua/LuaException.java b/src/main/java/dan200/computercraft/api/lua/LuaException.java index 65d8d0284..949a8eeba 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaException.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaException.java @@ -13,24 +13,33 @@ import javax.annotation.Nullable; public class LuaException extends Exception { private static final long serialVersionUID = -6136063076818512651L; + private final boolean hasLevel; private final int level; - public LuaException() - { - this( "error", 1 ); - } - public LuaException( @Nullable String message ) { - this( message, 1 ); + super( message ); + this.hasLevel = false; + this.level = 1; } public LuaException( @Nullable String message, int level ) { super( message ); + this.hasLevel = true; this.level = level; } + /** + * Whether a level was explicitly specified when constructing. This is used to determine + * + * @return Whether this has an explicit level. + */ + public boolean hasLevel() + { + return hasLevel; + } + /** * The level this error is raised at. Level 1 is the function's caller, level 2 is that function's caller, and so * on. diff --git a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java new file mode 100644 index 000000000..e17e30ac4 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java @@ -0,0 +1,58 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; + +import java.lang.annotation.*; +import java.util.Map; +import java.util.Optional; + +/** + * Used to mark a Java function which is callable from Lua. + * + * Methods annotated with {@link LuaFunction} must be public final instance methods. They can have any number of + * parameters, but they must be of the following types: + * + *
    + *
  • {@link ILuaContext} (and {@link IComputerAccess} if on a {@link IPeripheral})
  • + *
  • {@link IArguments}: The arguments supplied to this function.
  • + *
  • + * Alternatively, one may specify the desired arguments as normal parameters and the argument parsing code will + * be generated automatically. + * + * Each parameter must be one of the given types supported by {@link IArguments} (for instance, {@link int} or + * {@link Map}). Optional values are supported by accepting a parameter of type {@link Optional}. + *
  • + *
+ * + * This function may return {@link MethodResult}. However, if you simply return a value (rather than having to yield), + * you may return {@code void}, a single value (either an object or a primitive like {@code int}) or array of objects. + * These will be treated the same as {@link MethodResult#of()}, {@link MethodResult#of(Object)} and + * {@link MethodResult#of(Object...)}. + */ +@Documented +@Retention( RetentionPolicy.RUNTIME ) +@Target( ElementType.METHOD ) +public @interface LuaFunction +{ + /** + * Explicitly specify the method names of this function. If not given, it uses the name of the annotated method. + * + * @return This function's name(s). + */ + String[] value() default {}; + + /** + * Run this function on the main server thread. This should be specified for any method which interacts with + * Minecraft in a thread-unsafe manner. + * + * @return Whether this functi + * @see ILuaContext#issueMainThreadTask(ILuaTask) + */ + boolean mainThread() default false; +} diff --git a/src/main/java/dan200/computercraft/api/lua/LuaValues.java b/src/main/java/dan200/computercraft/api/lua/LuaValues.java new file mode 100644 index 000000000..f89b24a17 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/LuaValues.java @@ -0,0 +1,152 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.util.Map; + +/** + * Various utility functions for operating with Lua values. + * + * @see IArguments + */ +public final class LuaValues +{ + private LuaValues() + { + } + + /** + * Encode a Lua string into a read-only {@link ByteBuffer}. + * + * @param string The string to encode. + * @return The encoded string. + */ + @Nonnull + public static ByteBuffer encode( @Nonnull String string ) + { + byte[] chars = new byte[string.length()]; + for( int i = 0; i < chars.length; i++ ) + { + char c = string.charAt( i ); + chars[i] = c < 256 ? (byte) c : 63; + } + + return ByteBuffer.wrap( chars ).asReadOnlyBuffer(); + } + + /** + * Returns a more detailed representation of this number's type. If this is finite, it will just return "number", + * otherwise it returns whether it is infinite or NaN. + * + * @param value The value to extract the type for. + * @return This value's numeric type. + */ + @Nonnull + public static String getNumericType( double value ) + { + if( Double.isNaN( value ) ) return "nan"; + if( value == Double.POSITIVE_INFINITY ) return "inf"; + if( value == Double.NEGATIVE_INFINITY ) return "-inf"; + return "number"; + } + + /** + * Get a string representation of the given value's type. + * + * @param value The value whose type we are trying to compute. + * @return A string representation of the given value's type, in a similar format to that provided by Lua's + * {@code type} function. + */ + @Nonnull + public static String getType( @Nullable Object value ) + { + if( value == null ) return "nil"; + if( value instanceof String ) return "string"; + if( value instanceof Boolean ) return "boolean"; + if( value instanceof Number ) return "number"; + if( value instanceof Map ) return "table"; + return "userdata"; + } + + /** + * Construct a "bad argument" exception, from an expected type and the actual value provided. + * + * @param index The argument number, starting from 0. + * @param expected The expected type for this argument. + * @param actual The actual value provided for this argument. + * @return The constructed exception, which should be thrown immediately. + */ + @Nonnull + public static LuaException badArgumentOf( int index, @Nonnull String expected, @Nullable Object actual ) + { + return badArgument( index, expected, getType( actual ) ); + } + + /** + * Construct a "bad argument" exception, from an expected and actual type. + * + * @param index The argument number, starting from 0. + * @param expected The expected type for this argument. + * @param actual The provided type for this argument. + * @return The constructed exception, which should be thrown immediately. + */ + @Nonnull + public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual ) + { + return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); + } + + /** + * Ensure a numeric argument is finite (i.e. not infinite or {@link Double#NaN}. + * + * @param index The argument index to check. + * @param value The value to check. + * @return The input {@code value}. + * @throws LuaException If this is not a finite number. + */ + public static Number checkFiniteNum( int index, Number value ) throws LuaException + { + checkFinite( index, value.doubleValue() ); + return value; + } + + /** + * Ensure a numeric argument is finite (i.e. not infinite or {@link Double#NaN}. + * + * @param index The argument index to check. + * @param value The value to check. + * @return The input {@code value}. + * @throws LuaException If this is not a finite number. + */ + public static double checkFinite( int index, double value ) throws LuaException + { + if( !Double.isFinite( value ) ) throw badArgument( index, "number", getNumericType( value ) ); + return value; + } + + /** + * Ensure a string is a valid enum value. + * + * @param index The argument index to check. + * @param klass The class of the enum instance. + * @param value The value to extract. + * @param The type of enum we are extracting. + * @return The parsed enum value. + * @throws LuaException If this is not a known enum value. + */ + public static > T checkEnum( int index, Class klass, String value ) throws LuaException + { + for( T possibility : klass.getEnumConstants() ) + { + if( possibility.name().equalsIgnoreCase( value ) ) return possibility; + } + + throw new LuaException( "bad argument #" + (index + 1) + " (unknown option " + value + ")" ); + } +} diff --git a/src/main/java/dan200/computercraft/api/lua/MethodResult.java b/src/main/java/dan200/computercraft/api/lua/MethodResult.java new file mode 100644 index 000000000..2a7f80155 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/MethodResult.java @@ -0,0 +1,170 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.peripheral.IComputerAccess; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; + +/** + * The result of invoking a Lua method. + * + * Method results either return a value immediately ({@link #of(Object...)} or yield control to the parent coroutine. + * When the current coroutine is resumed, we invoke the provided {@link ILuaCallback#resume(Object[])} callback. + */ +public final class MethodResult +{ + private static final MethodResult empty = new MethodResult( null, null ); + + private final Object[] result; + private final ILuaCallback callback; + private final int adjust; + + private MethodResult( Object[] arguments, ILuaCallback callback ) + { + this.result = arguments; + this.callback = callback; + this.adjust = 0; + } + + private MethodResult( Object[] arguments, ILuaCallback callback, int adjust ) + { + this.result = arguments; + this.callback = callback; + this.adjust = adjust; + } + + /** + * Return no values immediately. + * + * @return A method result which returns immediately with no values. + */ + @Nonnull + public static MethodResult of() + { + return empty; + } + + /** + * Return a single value immediately. + * + * Integers, doubles, floats, strings, booleans, {@link Map}, {@link Collection}s, arrays and {@code null} will be + * converted to their corresponding Lua type. {@code byte[]} and {@link ByteBuffer} will be treated as binary + * strings. + * + * In order to provide a custom object with methods, one may return a {@link IDynamicLuaObject}, or an arbitrary + * class with {@link LuaFunction} annotations. Anything else will be converted to {@code nil}. + * + * @param value The value to return to the calling Lua function. + * @return A method result which returns immediately with the given value. + */ + @Nonnull + public static MethodResult of( @Nullable Object value ) + { + return new MethodResult( new Object[] { value }, null ); + } + + /** + * Return any number of values immediately. + * + * @param values The values to return. See {@link #of(Object)} for acceptable values. + * @return A method result which returns immediately with the given values. + */ + @Nonnull + public static MethodResult of( @Nullable Object... values ) + { + return values == null || values.length == 0 ? empty : new MethodResult( values, null ); + } + + /** + * Wait for an event to occur on the computer, suspending the thread until it arises. This method is exactly + * equivalent to {@code os.pullEvent()} in lua. + * + * @param filter A specific event to wait for, or null to wait for any event. + * @param callback The callback to resume with the name of the event that occurred, and any event parameters. + * @return The method result which represents this yield. + * @see IComputerAccess#queueEvent(String, Object[]) + */ + @Nonnull + public static MethodResult pullEvent( @Nullable String filter, @Nonnull ILuaCallback callback ) + { + Objects.requireNonNull( callback, "callback cannot be null" ); + return new MethodResult( new Object[] { filter }, results -> { + if( results.length >= 1 && results[0].equals( "terminate" ) ) throw new LuaException( "Terminated", 0 ); + return callback.resume( results ); + } ); + } + + /** + * The same as {@link #pullEvent(String, ILuaCallback)}, except "terminated" events are ignored. Only use this if + * you want to prevent program termination, which is not recommended. This method is exactly equivalent to + * {@code os.pullEventRaw()} in Lua. + * + * @param filter A specific event to wait for, or null to wait for any event. + * @param callback The callback to resume with the name of the event that occurred, and any event parameters. + * @return The method result which represents this yield. + * @see #pullEvent(String, ILuaCallback) + */ + @Nonnull + public static MethodResult pullEventRaw( @Nullable String filter, @Nonnull ILuaCallback callback ) + { + Objects.requireNonNull( callback, "callback cannot be null" ); + return new MethodResult( new Object[] { filter }, callback ); + } + + /** + * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to + * {@code coroutine.yield()} in lua. Use {@code pullEvent()} if you wish to wait for events. + * + * @param arguments An object array containing the arguments to pass to coroutine.yield() + * @param callback The callback to resume with an array containing the return values from coroutine.yield() + * @return The method result which represents this yield. + * @see #pullEvent(String, ILuaCallback) + */ + @Nonnull + public static MethodResult yield( @Nullable Object[] arguments, @Nonnull ILuaCallback callback ) + { + Objects.requireNonNull( callback, "callback cannot be null" ); + return new MethodResult( arguments, callback ); + } + + @Nullable + public Object[] getResult() + { + return result; + } + + @Nullable + public ILuaCallback getCallback() + { + return callback; + } + + public int getErrorAdjust() + { + return adjust; + } + + /** + * Increase the Lua error by a specific amount. One should never need to use this function - it largely exists for + * some CC internal code. + * + * @param adjust The amount to increase the level by. + * @return The new {@link MethodResult} with an adjusted error. This has no effect on immediate results. + */ + @Nonnull + public MethodResult adjustError( int adjust ) + { + if( adjust < 0 ) throw new IllegalArgumentException( "cannot adjust by a negative amount" ); + if( adjust == 0 || callback == null ) return this; + return new MethodResult( result, callback, this.adjust + adjust ); + } +} diff --git a/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java new file mode 100644 index 000000000..4ccc50b89 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java @@ -0,0 +1,66 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +/** + * An implementation of {@link IArguments} which wraps an array of {@link Object}. + */ +public final class ObjectArguments implements IArguments +{ + private static final IArguments EMPTY = new ObjectArguments(); + private final List args; + + @Deprecated + @SuppressWarnings( "unused" ) + public ObjectArguments( IArguments arguments ) + { + throw new IllegalStateException(); + } + + public ObjectArguments( Object... args ) + { + this.args = Arrays.asList( args ); + } + + public ObjectArguments( List args ) + { + this.args = Objects.requireNonNull( args ); + } + + @Override + public int count() + { + return args.size(); + } + + @Override + public IArguments drop( int count ) + { + if( count < 0 ) throw new IllegalStateException( "count cannot be negative" ); + if( count == 0 ) return this; + if( count >= args.size() ) return EMPTY; + + return new ObjectArguments( args.subList( count, args.size() ) ); + } + + @Nullable + @Override + public Object get( int index ) + { + return index >= args.size() ? null : args.get( index ); + } + + @Override + public Object[] getAll() + { + return args.toArray(); + } +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 9a6f243e9..fd46dd056 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -8,8 +8,10 @@ package dan200.computercraft.api.peripheral; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaTask; +import dan200.computercraft.api.lua.MethodResult; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -146,9 +148,9 @@ public interface IComputerAccess * * You may supply {@code null} to indicate that no arguments are to be supplied. * @throws NotAttachedException If the peripheral has been detached. - * @see IPeripheral#callMethod + * @see MethodResult#pullEvent(String, ILuaCallback) */ - void queueEvent( @Nonnull String event, @Nullable Object[] arguments ); + void queueEvent( @Nonnull String event, @Nullable Object... arguments ); /** * Get a string, unique to the computer, by which the computer refers to this peripheral. diff --git a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java new file mode 100644 index 000000000..5e7e8bfcc --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java @@ -0,0 +1,53 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.peripheral; + +import dan200.computercraft.api.lua.*; + +import javax.annotation.Nonnull; + +/** + * A peripheral whose methods are not known at runtime. + * + * This behaves similarly to {@link IDynamicLuaObject}, though also accepting the current {@link IComputerAccess}. + * Generally one may use {@link LuaFunction} instead of implementing this interface. + */ +public interface IDynamicPeripheral extends IPeripheral +{ + /** + * Should return an array of strings that identify the methods that this peripheral exposes to Lua. This will be + * called once before each attachment, and should not change when called multiple times. + * + * @return An array of strings representing method names. + * @see #callMethod + */ + @Nonnull + String[] getMethodNames(); + + /** + * This is called when a lua program on an attached computer calls {@code peripheral.call()} with + * one of the methods exposed by {@link #getMethodNames()}. + * + * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe when interacting + * with Minecraft objects. + * + * @param computer The interface to the computer that is making the call. Remember that multiple + * computers can be attached to a peripheral at once. + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which of the methods from getMethodNames() the computercraft + * wishes to call. The integer indicates the index into the getMethodNames() table + * that corresponds to the string passed into peripheral.call() + * @param arguments The arguments for this method. + * @return A {@link MethodResult} containing the values to return or the action to perform. + * @throws LuaException If you throw any exception from this function, a lua error will be raised with the + * same message as your exception. Use this to throw appropriate errors if the wrong + * arguments are supplied to your method. + * @see #getMethodNames() + */ + @Nonnull + MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 310ff24c5..a361848c3 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -5,15 +5,17 @@ */ package dan200.computercraft.api.peripheral; -import dan200.computercraft.api.lua.ArgumentHelper; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * The interface that defines a peripheral. See {@link IPeripheralProvider} for how to associate blocks with peripherals. + * The interface that defines a peripheral. See {@link IPeripheralProvider} for how to associate blocks with + * peripherals. + * + * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing + * {@link IDynamicPeripheral}. */ public interface IPeripheral { @@ -26,57 +28,6 @@ public interface IPeripheral @Nonnull String getType(); - /** - * Should return an array of strings that identify the methods that this - * peripheral exposes to Lua. This will be called once before each attachment, - * and should not change when called multiple times. - * - * @return An array of strings representing method names. - * @see #callMethod - */ - @Nonnull - String[] getMethodNames(); - - /** - * This is called when a lua program on an attached computer calls {@code peripheral.call()} with - * one of the methods exposed by {@link #getMethodNames()}. - * - * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe when interacting - * with Minecraft objects. - * - * @param computer The interface to the computer that is making the call. Remember that multiple - * computers can be attached to a peripheral at once. - * @param context The context of the currently running lua thread. This can be used to wait for events - * or otherwise yield. - * @param method An integer identifying which of the methods from getMethodNames() the computercraft - * wishes to call. The integer indicates the index into the getMethodNames() table - * that corresponds to the string passed into peripheral.call() - * @param arguments An array of objects, representing the arguments passed into {@code peripheral.call()}.
- * Lua values of type "string" will be represented by Object type String.
- * Lua values of type "number" will be represented by Object type Double.
- * Lua values of type "boolean" will be represented by Object type Boolean.
- * Lua values of type "table" will be represented by Object type Map.
- * Lua values of any other type will be represented by a null object.
- * This array will be empty if no arguments are passed. - * - * It is recommended you use {@link ArgumentHelper} in order to validate and process arguments. - * @return An array of objects, representing values you wish to return to the lua program. Integers, Doubles, Floats, - * Strings, Booleans, Maps, ILuaObject and null be converted to their corresponding lua type. All other types will - * be converted to nil. - * - * You may return null to indicate no values should be returned. - * @throws LuaException If you throw any exception from this function, a lua error will be raised with the - * same message as your exception. Use this to throw appropriate errors if the wrong - * arguments are supplied to your method. - * @throws InterruptedException If the user shuts down or reboots the computer the coroutine is suspended, - * InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state. - * @see #getMethodNames - * @see ArgumentHelper - */ - @Nullable - Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException; - /** * Is called when when a computer is attaching to the peripheral. * diff --git a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java index 08c343303..a01efa5a6 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java +++ b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java @@ -15,7 +15,7 @@ public class NotAttachedException extends IllegalStateException public NotAttachedException() { - super( "You are not attached to this Computer" ); + super( "You are not attached to this computer" ); } public NotAttachedException( String s ) diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 6e33e2871..53b176dbf 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -6,8 +6,8 @@ package dan200.computercraft.api.turtle; import com.mojang.authlib.GameProfile; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.ILuaCallback; +import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.inventory.IInventory; import net.minecraft.nbt.CompoundNBT; @@ -228,21 +228,15 @@ public interface ITurtleAccess * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. * - * @param context The Lua context to pull events from. * @param command An object which will execute the custom command when its point in the queue is reached * @return The objects the command returned when executed. you should probably return these to the player * unchanged if called from a peripheral method. * @throws UnsupportedOperationException When attempting to execute a command on the client side. - * @throws LuaException If the user presses CTRL+T to terminate the current program while {@code executeCommand()} is - * waiting for an event, a "Terminated" exception will be thrown here. - * @throws InterruptedException If the user shuts down or reboots the computer while pullEvent() is waiting for an - * event, InterruptedException will be thrown. This exception must not be caught or - * intercepted, or the computer will leak memory and end up in a broken state. * @see ITurtleCommand - * @see ILuaContext#pullEvent(String) + * @see MethodResult#pullEvent(String, ILuaCallback) */ @Nonnull - Object[] executeCommand( @Nonnull ILuaContext context, @Nonnull ITurtleCommand command ) throws LuaException, InterruptedException; + MethodResult executeCommand( @Nonnull ITurtleCommand command ); /** * Start playing a specific animation. This will prevent other turtle commands from executing until diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java index 88b4b7ab5..00c17ab54 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -5,14 +5,12 @@ */ package dan200.computercraft.api.turtle; -import dan200.computercraft.api.lua.ILuaContext; - import javax.annotation.Nonnull; /** - * An interface for objects executing custom turtle commands, used with {@link ITurtleAccess#executeCommand(ILuaContext, ITurtleCommand)}. + * An interface for objects executing custom turtle commands, used with {@link ITurtleAccess#executeCommand(ITurtleCommand)}. * - * @see ITurtleAccess#executeCommand(ILuaContext, ITurtleCommand) + * @see ITurtleAccess#executeCommand(ITurtleCommand) */ @FunctionalInterface public interface ITurtleCommand @@ -25,7 +23,7 @@ public interface ITurtleCommand * * @param turtle Access to the turtle for whom the command was issued. * @return A result, indicating whether this action succeeded or not. - * @see ITurtleAccess#executeCommand(ILuaContext, ITurtleCommand) + * @see ITurtleAccess#executeCommand(ITurtleCommand) * @see TurtleCommandResult#success() * @see TurtleCommandResult#failure(String) * @see TurtleCommandResult diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index e20ab37b1..efd20fd36 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -5,8 +5,7 @@ */ package dan200.computercraft.api.turtle.event; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; @@ -223,7 +222,7 @@ public abstract class TurtleBlockEvent extends TurtlePlayerEvent * Add new information to the inspection result. Note this will override fields with the same name. * * @param newData The data to add. Note all values should be convertible to Lua (see - * {@link dan200.computercraft.api.peripheral.IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}). + * {@link MethodResult#of(Object)}). */ public void addData( @Nonnull Map newData ) { diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index 12a1b751b..f21756a1a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -5,8 +5,7 @@ */ package dan200.computercraft.api.turtle.event; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.turtle.ITurtleAccess; import net.minecraft.item.ItemStack; @@ -63,7 +62,7 @@ public class TurtleInspectItemEvent extends TurtleActionEvent * Add new information to the inspection result. Note this will override fields with the same name. * * @param newData The data to add. Note all values should be convertible to Lua (see - * {@link dan200.computercraft.api.peripheral.IPeripheral#callMethod(IComputerAccess, ILuaContext, int, Object[])}). + * {@link MethodResult#of(Object)}). */ public void addData( @Nonnull Map newData ) { diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index 019333500..1eebc5e01 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -116,7 +116,7 @@ public abstract class ComputerAccess implements IComputerAccess } @Override - public void queueEvent( @Nonnull final String event, final Object[] arguments ) + public void queueEvent( @Nonnull String event, Object... arguments ) { Objects.requireNonNull( event, "event cannot be null" ); m_environment.queueEvent( event, arguments ); diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 90a866a53..f9f45a243 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -6,8 +6,8 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.core.apis.handles.BinaryReadableHandle; import dan200.computercraft.core.apis.handles.BinaryWritableHandle; import dan200.computercraft.core.apis.handles.EncodedReadableHandle; @@ -17,7 +17,6 @@ import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.filesystem.FileSystemWrapper; import dan200.computercraft.core.tracking.TrackingField; -import javax.annotation.Nonnull; import java.io.BufferedReader; import java.io.BufferedWriter; import java.nio.channels.ReadableByteChannel; @@ -29,17 +28,14 @@ import java.util.Map; import java.util.OptionalLong; import java.util.function.Function; -import static dan200.computercraft.api.lua.ArgumentHelper.getString; - public class FSAPI implements ILuaAPI { - private IAPIEnvironment m_env; - private FileSystem m_fileSystem; + private final IAPIEnvironment environment; + private FileSystem fileSystem = null; public FSAPI( IAPIEnvironment env ) { - m_env = env; - m_fileSystem = null; + environment = env; } @Override @@ -51,329 +47,280 @@ public class FSAPI implements ILuaAPI @Override public void startup() { - m_fileSystem = m_env.getFileSystem(); + fileSystem = environment.getFileSystem(); } @Override public void shutdown() { - m_fileSystem = null; + fileSystem = null; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final String[] list( String path ) throws LuaException { - return new String[] { - "list", - "combine", - "getName", - "getSize", - "exists", - "isDir", - "isReadOnly", - "makeDir", - "move", - "copy", - "delete", - "open", - "getDrive", - "getFreeSpace", - "find", - "getDir", - "getCapacity", - "attributes", - }; - } - - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException - { - switch( method ) + environment.addTrackingChange( TrackingField.FS_OPS ); + try { - case 0: + return fileSystem.list( path ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final String combine( String pathA, String pathB ) + { + return fileSystem.combine( pathA, pathB ); + } + + @LuaFunction + public final String getName( String path ) + { + return FileSystem.getName( path ); + } + + @LuaFunction + public final String getDir( String path ) + { + return FileSystem.getDirectory( path ); + } + + @LuaFunction + public final long getSize( String path ) throws LuaException + { + try + { + return fileSystem.getSize( path ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final boolean exists( String path ) + { + try + { + return fileSystem.exists( path ); + } + catch( FileSystemException e ) + { + return false; + } + } + + @LuaFunction + public final boolean isDir( String path ) + { + try + { + return fileSystem.isDir( path ); + } + catch( FileSystemException e ) + { + return false; + } + } + + @LuaFunction + public final boolean isReadOnly( String path ) + { + try + { + return fileSystem.isReadOnly( path ); + } + catch( FileSystemException e ) + { + return false; + } + } + + @LuaFunction + public final void makeDir( String path ) throws LuaException + { + try + { + environment.addTrackingChange( TrackingField.FS_OPS ); + fileSystem.makeDir( path ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final void move( String path, String dest ) throws LuaException + { + try + { + environment.addTrackingChange( TrackingField.FS_OPS ); + fileSystem.move( path, dest ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final void copy( String path, String dest ) throws LuaException + { + try + { + environment.addTrackingChange( TrackingField.FS_OPS ); + fileSystem.copy( path, dest ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final void delete( String path ) throws LuaException + { + try + { + environment.addTrackingChange( TrackingField.FS_OPS ); + fileSystem.delete( path ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final Object[] open( String path, String mode ) throws LuaException + { + environment.addTrackingChange( TrackingField.FS_OPS ); + try + { + switch( mode ) { - // list - String path = getString( args, 0 ); - m_env.addTrackingChange( TrackingField.FS_OPS ); - try + case "r": { - return new Object[] { m_fileSystem.list( path ) }; + // Open the file for reading, then create a wrapper around the reader + FileSystemWrapper reader = fileSystem.openForRead( path, EncodedReadableHandle::openUtf8 ); + return new Object[] { new EncodedReadableHandle( reader.get(), reader ) }; } - catch( FileSystemException e ) + case "w": { - throw new LuaException( e.getMessage() ); + // Open the file for writing, then create a wrapper around the writer + FileSystemWrapper writer = fileSystem.openForWrite( path, false, EncodedWritableHandle::openUtf8 ); + return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; } + case "a": + { + // Open the file for appending, then create a wrapper around the writer + FileSystemWrapper writer = fileSystem.openForWrite( path, true, EncodedWritableHandle::openUtf8 ); + return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; + } + case "rb": + { + // Open the file for binary reading, then create a wrapper around the reader + FileSystemWrapper reader = fileSystem.openForRead( path, Function.identity() ); + return new Object[] { BinaryReadableHandle.of( reader.get(), reader ) }; + } + case "wb": + { + // Open the file for binary writing, then create a wrapper around the writer + FileSystemWrapper writer = fileSystem.openForWrite( path, false, Function.identity() ); + return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; + } + case "ab": + { + // Open the file for binary appending, then create a wrapper around the reader + FileSystemWrapper writer = fileSystem.openForWrite( path, true, Function.identity() ); + return new Object[] { BinaryWritableHandle.of( writer.get(), writer ) }; + } + default: + throw new LuaException( "Unsupported mode" ); } - case 1: - { - // combine - String pathA = getString( args, 0 ); - String pathB = getString( args, 1 ); - return new Object[] { m_fileSystem.combine( pathA, pathB ) }; - } - case 2: - { - // getName - String path = getString( args, 0 ); - return new Object[] { FileSystem.getName( path ) }; - } - case 3: - { - // getSize - String path = getString( args, 0 ); - try - { - return new Object[] { m_fileSystem.getSize( path ) }; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 4: - { - // exists - String path = getString( args, 0 ); - try - { - return new Object[] { m_fileSystem.exists( path ) }; - } - catch( FileSystemException e ) - { - return new Object[] { false }; - } - } - case 5: - { - // isDir - String path = getString( args, 0 ); - try - { - return new Object[] { m_fileSystem.isDir( path ) }; - } - catch( FileSystemException e ) - { - return new Object[] { false }; - } - } - case 6: - { - // isReadOnly - String path = getString( args, 0 ); - try - { - return new Object[] { m_fileSystem.isReadOnly( path ) }; - } - catch( FileSystemException e ) - { - return new Object[] { false }; - } - } - case 7: - { - // makeDir - String path = getString( args, 0 ); - try - { - m_env.addTrackingChange( TrackingField.FS_OPS ); - m_fileSystem.makeDir( path ); - return null; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 8: - { - // move - String path = getString( args, 0 ); - String dest = getString( args, 1 ); - try - { - m_env.addTrackingChange( TrackingField.FS_OPS ); - m_fileSystem.move( path, dest ); - return null; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 9: - { - // copy - String path = getString( args, 0 ); - String dest = getString( args, 1 ); - try - { - m_env.addTrackingChange( TrackingField.FS_OPS ); - m_fileSystem.copy( path, dest ); - return null; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 10: - { - // delete - String path = getString( args, 0 ); - try - { - m_env.addTrackingChange( TrackingField.FS_OPS ); - m_fileSystem.delete( path ); - return null; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 11: - { - // open - String path = getString( args, 0 ); - String mode = getString( args, 1 ); - m_env.addTrackingChange( TrackingField.FS_OPS ); - try - { - switch( mode ) - { - case "r": - { - // Open the file for reading, then create a wrapper around the reader - FileSystemWrapper reader = m_fileSystem.openForRead( path, EncodedReadableHandle::openUtf8 ); - return new Object[] { new EncodedReadableHandle( reader.get(), reader ) }; - } - case "w": - { - // Open the file for writing, then create a wrapper around the writer - FileSystemWrapper writer = m_fileSystem.openForWrite( path, false, EncodedWritableHandle::openUtf8 ); - return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; - } - case "a": - { - // Open the file for appending, then create a wrapper around the writer - FileSystemWrapper writer = m_fileSystem.openForWrite( path, true, EncodedWritableHandle::openUtf8 ); - return new Object[] { new EncodedWritableHandle( writer.get(), writer ) }; - } - case "rb": - { - // Open the file for binary reading, then create a wrapper around the reader - FileSystemWrapper reader = m_fileSystem.openForRead( path, Function.identity() ); - return new Object[] { new BinaryReadableHandle( reader.get(), reader ) }; - } - case "wb": - { - // Open the file for binary writing, then create a wrapper around the writer - FileSystemWrapper writer = m_fileSystem.openForWrite( path, false, Function.identity() ); - return new Object[] { new BinaryWritableHandle( writer.get(), writer ) }; - } - case "ab": - { - // Open the file for binary appending, then create a wrapper around the reader - FileSystemWrapper writer = m_fileSystem.openForWrite( path, true, Function.identity() ); - return new Object[] { new BinaryWritableHandle( writer.get(), writer ) }; - } - default: - throw new LuaException( "Unsupported mode" ); - } - } - catch( FileSystemException e ) - { - return new Object[] { null, e.getMessage() }; - } - } - case 12: - { - // getDrive - String path = getString( args, 0 ); - try - { - if( !m_fileSystem.exists( path ) ) - { - return null; - } - return new Object[] { m_fileSystem.getMountLabel( path ) }; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 13: - { - // getFreeSpace - String path = getString( args, 0 ); - try - { - long freeSpace = m_fileSystem.getFreeSpace( path ); - if( freeSpace >= 0 ) - { - return new Object[] { freeSpace }; - } - return new Object[] { "unlimited" }; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 14: // find - { - String path = getString( args, 0 ); - try - { - m_env.addTrackingChange( TrackingField.FS_OPS ); - return new Object[] { m_fileSystem.find( path ) }; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 15: // getDir - { - String path = getString( args, 0 ); - return new Object[] { FileSystem.getDirectory( path ) }; - } - case 16: // getCapacity - { - String path = getString( args, 0 ); - try - { - OptionalLong capacity = m_fileSystem.getCapacity( path ); - return new Object[] { capacity.isPresent() ? capacity.getAsLong() : null }; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 17: // attributes - { - String path = getString( args, 0 ); - try - { - BasicFileAttributes attributes = m_fileSystem.getAttributes( path ); - Map result = new HashMap<>(); - result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); - result.put( "created", getFileTime( attributes.creationTime() ) ); - result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); - result.put( "isDir", attributes.isDirectory() ); - return new Object[] { result }; - } - catch( FileSystemException e ) - { - throw new LuaException( e.getMessage() ); - } - } - default: - assert false; - return null; + } + catch( FileSystemException e ) + { + return new Object[] { null, e.getMessage() }; + } + } + + @LuaFunction + public final Object[] getDrive( String path ) throws LuaException + { + try + { + return fileSystem.exists( path ) ? new Object[] { fileSystem.getMountLabel( path ) } : null; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final Object getFreeSpace( String path ) throws LuaException + { + try + { + long freeSpace = fileSystem.getFreeSpace( path ); + return freeSpace >= 0 ? freeSpace : "unlimited"; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final String[] find( String path ) throws LuaException + { + try + { + environment.addTrackingChange( TrackingField.FS_OPS ); + return fileSystem.find( path ); + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final Object getCapacity( String path ) throws LuaException + { + try + { + OptionalLong capacity = fileSystem.getCapacity( path ); + return capacity.isPresent() ? capacity.getAsLong() : null; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final Map attributes( String path ) throws LuaException + { + try + { + BasicFileAttributes attributes = fileSystem.getAttributes( path ); + Map result = new HashMap<>(); + result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); + result.put( "created", getFileTime( attributes.creationTime() ) ); + result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); + result.put( "isDir", attributes.isDirectory() ); + return result; + } + catch( FileSystemException e ) + { + throw new LuaException( e.getMessage() ); } } diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 375135ffd..eac31b9f8 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -6,9 +6,10 @@ package dan200.computercraft.core.apis; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.core.apis.http.*; import dan200.computercraft.core.apis.http.request.HttpRequest; import dan200.computercraft.core.apis.http.websocket.Websocket; @@ -21,8 +22,8 @@ import java.net.URI; import java.util.Collections; import java.util.Locale; import java.util.Map; +import java.util.Optional; -import static dan200.computercraft.api.lua.ArgumentHelper.*; import static dan200.computercraft.core.apis.TableHelper.*; public class HTTPAPI implements ILuaAPI @@ -68,135 +69,112 @@ public class HTTPAPI implements ILuaAPI Resource.cleanup(); } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final Object[] request( IArguments args ) throws LuaException { - return new String[] { - "request", - "checkURL", - "websocket", - }; + String address, postString, requestMethod; + Map headerTable; + boolean binary, redirect; + + if( args.get( 0 ) instanceof Map ) + { + Map options = args.getTable( 0 ); + address = getStringField( options, "url" ); + postString = optStringField( options, "body", null ); + headerTable = optTableField( options, "headers", Collections.emptyMap() ); + binary = optBooleanField( options, "binary", false ); + requestMethod = optStringField( options, "method", null ); + redirect = optBooleanField( options, "redirect", true ); + + } + else + { + // Get URL and post information + address = args.getString( 0 ); + postString = args.optString( 1, null ); + headerTable = args.optTable( 2, Collections.emptyMap() ); + binary = args.optBoolean( 3, false ); + requestMethod = null; + redirect = true; + } + + HttpHeaders headers = getHeaders( headerTable ); + + HttpMethod httpMethod; + if( requestMethod == null ) + { + httpMethod = postString == null ? HttpMethod.GET : HttpMethod.POST; + } + else + { + httpMethod = HttpMethod.valueOf( requestMethod.toUpperCase( Locale.ROOT ) ); + if( httpMethod == null || requestMethod.equalsIgnoreCase( "CONNECT" ) ) + { + throw new LuaException( "Unsupported HTTP method" ); + } + } + + try + { + URI uri = HttpRequest.checkUri( address ); + HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect ); + + long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers ); + if( ComputerCraft.httpMaxUpload != 0 && requestBody > ComputerCraft.httpMaxUpload ) + { + throw new HTTPRequestException( "Request body is too large" ); + } + + // Make the request + request.queue( r -> r.request( uri, httpMethod ) ); + + return new Object[] { true }; + } + catch( HTTPRequestException e ) + { + return new Object[] { false, e.getMessage() }; + } } - @Override - @SuppressWarnings( "resource" ) - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final Object[] checkURL( String address ) { - switch( method ) + try { - case 0: // request + URI uri = HttpRequest.checkUri( address ); + new CheckUrl( checkUrls, m_apiEnvironment, address, uri ).queue( CheckUrl::run ); + + return new Object[] { true }; + } + catch( HTTPRequestException e ) + { + return new Object[] { false, e.getMessage() }; + } + } + + @LuaFunction + public final Object[] websocket( String address, Optional> headerTbl ) throws LuaException + { + if( !ComputerCraft.httpWebsocketEnabled ) + { + throw new LuaException( "Websocket connections are disabled" ); + } + + HttpHeaders headers = getHeaders( headerTbl.orElse( Collections.emptyMap() ) ); + + try + { + URI uri = Websocket.checkUri( address ); + if( !new Websocket( websockets, m_apiEnvironment, uri, address, headers ).queue( Websocket::connect ) ) { - String address, postString, requestMethod; - Map headerTable; - boolean binary, redirect; - - if( args.length >= 1 && args[0] instanceof Map ) - { - Map options = (Map) args[0]; - address = getStringField( options, "url" ); - postString = optStringField( options, "body", null ); - headerTable = optTableField( options, "headers", Collections.emptyMap() ); - binary = optBooleanField( options, "binary", false ); - requestMethod = optStringField( options, "method", null ); - redirect = optBooleanField( options, "redirect", true ); - - } - else - { - // Get URL and post information - address = getString( args, 0 ); - postString = optString( args, 1, null ); - headerTable = optTable( args, 2, Collections.emptyMap() ); - binary = optBoolean( args, 3, false ); - requestMethod = null; - redirect = true; - } - - HttpHeaders headers = getHeaders( headerTable ); - - - HttpMethod httpMethod; - if( requestMethod == null ) - { - httpMethod = postString == null ? HttpMethod.GET : HttpMethod.POST; - } - else - { - httpMethod = HttpMethod.valueOf( requestMethod.toUpperCase( Locale.ROOT ) ); - if( httpMethod == null || requestMethod.equalsIgnoreCase( "CONNECT" ) ) - { - throw new LuaException( "Unsupported HTTP method" ); - } - } - - try - { - URI uri = HttpRequest.checkUri( address ); - HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect ); - - long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers ); - if( ComputerCraft.httpMaxUpload != 0 && requestBody > ComputerCraft.httpMaxUpload ) - { - throw new HTTPRequestException( "Request body is too large" ); - } - - // Make the request - request.queue( r -> r.request( uri, httpMethod ) ); - - return new Object[] { true }; - } - catch( HTTPRequestException e ) - { - return new Object[] { false, e.getMessage() }; - } + throw new LuaException( "Too many websockets already open" ); } - case 1: // checkURL - { - String address = getString( args, 0 ); - // Check URL - try - { - URI uri = HttpRequest.checkUri( address ); - new CheckUrl( checkUrls, m_apiEnvironment, address, uri ).queue( CheckUrl::run ); - - return new Object[] { true }; - } - catch( HTTPRequestException e ) - { - return new Object[] { false, e.getMessage() }; - } - } - case 2: // websocket - { - String address = getString( args, 0 ); - Map headerTbl = optTable( args, 1, Collections.emptyMap() ); - - if( !ComputerCraft.httpWebsocketEnabled ) - { - throw new LuaException( "Websocket connections are disabled" ); - } - - HttpHeaders headers = getHeaders( headerTbl ); - - try - { - URI uri = Websocket.checkUri( address ); - if( !new Websocket( websockets, m_apiEnvironment, uri, address, headers ).queue( Websocket::connect ) ) - { - throw new LuaException( "Too many websockets already open" ); - } - - return new Object[] { true }; - } - catch( HTTPRequestException e ) - { - return new Object[] { false, e.getMessage() }; - } - } - default: - return null; + return new Object[] { true }; + } + catch( HTTPRequestException e ) + { + return new Object[] { false, e.getMessage() }; } } diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 0a4315960..19e2d2f14 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -43,7 +43,7 @@ public interface IAPIEnvironment void reboot(); - void queueEvent( String event, Object[] args ); + void queueEvent( String event, Object... args ); void setOutput( ComputerSide side, int output ); diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 825ad05fa..1b63323ea 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -5,9 +5,10 @@ */ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.shared.util.StringUtil; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -20,11 +21,11 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatterBuilder; import java.util.*; -import static dan200.computercraft.api.lua.ArgumentHelper.*; +import static dan200.computercraft.api.lua.LuaValues.checkFinite; public class OSAPI implements ILuaAPI { - private IAPIEnvironment m_apiEnvironment; + private final IAPIEnvironment apiEnvironment; private final Int2ObjectMap m_alarms = new Int2ObjectOpenHashMap<>(); private int m_clock; @@ -55,11 +56,9 @@ public class OSAPI implements ILuaAPI public OSAPI( IAPIEnvironment environment ) { - m_apiEnvironment = environment; + apiEnvironment = environment; } - // ILuaAPI implementation - @Override public String[] getNames() { @@ -69,8 +68,8 @@ public class OSAPI implements ILuaAPI @Override public void startup() { - m_time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay(); - m_day = m_apiEnvironment.getComputerEnvironment().getDay(); + m_time = apiEnvironment.getComputerEnvironment().getTimeOfDay(); + m_day = apiEnvironment.getComputerEnvironment().getDay(); m_clock = 0; synchronized( m_alarms ) @@ -89,8 +88,8 @@ public class OSAPI implements ILuaAPI { double previousTime = m_time; int previousDay = m_day; - double time = m_apiEnvironment.getComputerEnvironment().getTimeOfDay(); - int day = m_apiEnvironment.getComputerEnvironment().getDay(); + double time = apiEnvironment.getComputerEnvironment().getTimeOfDay(); + int day = apiEnvironment.getComputerEnvironment().getDay(); if( time > previousTime || day > previousDay ) { @@ -103,7 +102,7 @@ public class OSAPI implements ILuaAPI double t = alarm.m_day * 24.0 + alarm.m_time; if( now >= t ) { - queueLuaEvent( "alarm", new Object[] { entry.getIntKey() } ); + apiEnvironment.queueEvent( "alarm", entry.getIntKey() ); it.remove(); } } @@ -123,31 +122,6 @@ public class OSAPI implements ILuaAPI } } - @Nonnull - @Override - public String[] getMethodNames() - { - return new String[] { - "queueEvent", - "startTimer", - "setAlarm", - "shutdown", - "reboot", - "computerID", - "getComputerID", - "setComputerLabel", - "computerLabel", - "getComputerLabel", - "clock", - "time", - "day", - "cancelTimer", - "cancelAlarm", - "epoch", - "date", - }; - } - private static float getTimeForCalendar( Calendar c ) { float time = c.get( Calendar.HOUR_OF_DAY ); @@ -174,214 +148,174 @@ public class OSAPI implements ILuaAPI return c.getTime().getTime(); } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final void queueEvent( String name, IArguments args ) { - switch( method ) + apiEnvironment.queueEvent( name, args.drop( 1 ).getAll() ); + } + + @LuaFunction + public final int startTimer( double timer ) throws LuaException + { + return apiEnvironment.startTimer( Math.round( checkFinite( 0, timer ) / 0.05 ) ); + } + + @LuaFunction + public final void cancelTimer( int token ) + { + apiEnvironment.cancelTimer( token ); + } + + @LuaFunction + public final int setAlarm( double time ) throws LuaException + { + checkFinite( 0, time ); + if( time < 0.0 || time >= 24.0 ) throw new LuaException( "Number out of range" ); + synchronized( m_alarms ) { - case 0: // queueEvent - queueLuaEvent( getString( args, 0 ), trimArray( args, 1 ) ); - return null; - case 1: - { - // startTimer - double timer = getFiniteDouble( args, 0 ); - int id = m_apiEnvironment.startTimer( Math.round( timer / 0.05 ) ); - return new Object[] { id }; - } - case 2: - { - // setAlarm - double time = getFiniteDouble( args, 0 ); - if( time < 0.0 || time >= 24.0 ) - { - throw new LuaException( "Number out of range" ); - } - synchronized( m_alarms ) - { - int day = time > m_time ? m_day : m_day + 1; - m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) ); - return new Object[] { m_nextAlarmToken++ }; - } - } - case 3: // shutdown - m_apiEnvironment.shutdown(); - return null; - case 4: // reboot - m_apiEnvironment.reboot(); - return null; - case 5: - case 6: // computerID/getComputerID - return new Object[] { getComputerID() }; - case 7: - { - // setComputerLabel - String label = optString( args, 0, null ); - m_apiEnvironment.setLabel( StringUtil.normaliseLabel( label ) ); - return null; - } - case 8: - case 9: - { - // computerLabel/getComputerLabel - String label = m_apiEnvironment.getLabel(); - if( label != null ) - { - return new Object[] { label }; - } - return null; - } - case 10: // clock - return new Object[] { m_clock * 0.05 }; - case 11: - { - // time - Object value = args.length > 0 ? args[0] : null; - if( value instanceof Map ) return new Object[] { LuaDateTime.fromTable( (Map) value ) }; - - String param = optString( args, 0, "ingame" ); - switch( param.toLowerCase( Locale.ROOT ) ) - { - case "utc": - { - // Get Hour of day (UTC) - Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); - return new Object[] { getTimeForCalendar( c ) }; - } - case "local": - { - // Get Hour of day (local time) - Calendar c = Calendar.getInstance(); - return new Object[] { getTimeForCalendar( c ) }; - } - case "ingame": - // Get ingame hour - synchronized( m_alarms ) - { - return new Object[] { m_time }; - } - default: - throw new LuaException( "Unsupported operation" ); - } - } - case 12: - { - // day - String param = optString( args, 0, "ingame" ); - switch( param.toLowerCase( Locale.ROOT ) ) - { - case "utc": - { - // Get numbers of days since 1970-01-01 (utc) - Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); - return new Object[] { getDayForCalendar( c ) }; - } - case "local": - { - // Get numbers of days since 1970-01-01 (local time) - Calendar c = Calendar.getInstance(); - return new Object[] { getDayForCalendar( c ) }; - } - case "ingame": - // Get game day - synchronized( m_alarms ) - { - return new Object[] { m_day }; - } - default: - throw new LuaException( "Unsupported operation" ); - } - } - case 13: - { - // cancelTimer - int token = getInt( args, 0 ); - m_apiEnvironment.cancelTimer( token ); - return null; - } - case 14: - { - // cancelAlarm - int token = getInt( args, 0 ); - synchronized( m_alarms ) - { - m_alarms.remove( token ); - } - return null; - } - case 15: // epoch - { - String param = optString( args, 0, "ingame" ); - switch( param.toLowerCase( Locale.ROOT ) ) - { - case "utc": - { - // Get utc epoch - Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); - return new Object[] { getEpochForCalendar( c ) }; - } - case "local": - { - // Get local epoch - Calendar c = Calendar.getInstance(); - return new Object[] { getEpochForCalendar( c ) }; - } - case "ingame": - // Get in-game epoch - synchronized( m_alarms ) - { - return new Object[] { m_day * 86400000 + (int) (m_time * 3600000.0f) }; - } - default: - throw new LuaException( "Unsupported operation" ); - } - } - case 16: // date - { - String format = optString( args, 0, "%c" ); - long time = optLong( args, 1, Instant.now().getEpochSecond() ); - - Instant instant = Instant.ofEpochSecond( time ); - ZonedDateTime date; - ZoneOffset offset; - if( format.startsWith( "!" ) ) - { - offset = ZoneOffset.UTC; - date = ZonedDateTime.ofInstant( instant, offset ); - format = format.substring( 1 ); - } - else - { - ZoneId id = ZoneId.systemDefault(); - offset = id.getRules().getOffset( instant ); - date = ZonedDateTime.ofInstant( instant, id ); - } - - if( format.equals( "*t" ) ) return new Object[] { LuaDateTime.toTable( date, offset, instant ) }; - - DateTimeFormatterBuilder formatter = new DateTimeFormatterBuilder(); - LuaDateTime.format( formatter, format, offset ); - return new Object[] { formatter.toFormatter( Locale.ROOT ).format( date ) }; - } - default: - return null; + int day = time > m_time ? m_day : m_day + 1; + m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) ); + return m_nextAlarmToken++; } } - // Private methods - - private void queueLuaEvent( String event, Object[] args ) + @LuaFunction + public final void cancelAlarm( int token ) { - m_apiEnvironment.queueEvent( event, args ); + synchronized( m_alarms ) + { + m_alarms.remove( token ); + } } - private Object[] trimArray( Object[] array, int skip ) + @LuaFunction( "shutdown" ) + public final void doShutdown() { - return Arrays.copyOfRange( array, skip, array.length ); + apiEnvironment.shutdown(); } - private int getComputerID() + @LuaFunction( "reboot" ) + public final void doReboot() { - return m_apiEnvironment.getComputerID(); + apiEnvironment.reboot(); } + + @LuaFunction( { "getComputerID", "computerID" } ) + public final int getComputerID() + { + return apiEnvironment.getComputerID(); + } + + @LuaFunction( { "getComputerLabel", "computerLabel" } ) + public final Object[] getComputerLabel() + { + String label = apiEnvironment.getLabel(); + return label == null ? null : new Object[] { label }; + } + + @LuaFunction + public final void setComputerLabel( Optional label ) + { + apiEnvironment.setLabel( StringUtil.normaliseLabel( label.orElse( null ) ) ); + } + + @LuaFunction + public final double clock() + { + return m_clock * 0.05; + } + + @LuaFunction + public final Object time( IArguments args ) throws LuaException + { + Object value = args.get( 0 ); + if( value instanceof Map ) return LuaDateTime.fromTable( (Map) value ); + + String param = args.optString( 0, "ingame" ); + switch( param.toLowerCase( Locale.ROOT ) ) + { + case "utc": // Get Hour of day (UTC) + return getTimeForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); + case "local": // Get Hour of day (local time) + return getTimeForCalendar( Calendar.getInstance() ); + case "ingame": // Get in-game hour + return m_time; + default: + throw new LuaException( "Unsupported operation" ); + } + } + + @LuaFunction + public final int day( Optional args ) throws LuaException + { + switch( args.orElse( "ingame" ).toLowerCase( Locale.ROOT ) ) + { + case "utc": // Get numbers of days since 1970-01-01 (utc) + return getDayForCalendar( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); + case "local": // Get numbers of days since 1970-01-01 (local time) + return getDayForCalendar( Calendar.getInstance() ); + case "ingame":// Get game day + return m_day; + default: + throw new LuaException( "Unsupported operation" ); + } + } + + @LuaFunction + public final long epoch( Optional args ) throws LuaException + { + switch( args.orElse( "ingame" ).toLowerCase( Locale.ROOT ) ) + { + case "utc": + { + // Get utc epoch + Calendar c = Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ); + return getEpochForCalendar( c ); + } + case "local": + { + // Get local epoch + Calendar c = Calendar.getInstance(); + return getEpochForCalendar( c ); + } + case "ingame": + // Get in-game epoch + synchronized( m_alarms ) + { + return m_day * 86400000 + (int) (m_time * 3600000.0f); + } + default: + throw new LuaException( "Unsupported operation" ); + } + } + + @LuaFunction + public final Object date( Optional formatA, Optional timeA ) throws LuaException + { + String format = formatA.orElse( "%c" ); + long time = timeA.orElseGet( () -> Instant.now().getEpochSecond() ); + + Instant instant = Instant.ofEpochSecond( time ); + ZonedDateTime date; + ZoneOffset offset; + if( format.startsWith( "!" ) ) + { + offset = ZoneOffset.UTC; + date = ZonedDateTime.ofInstant( instant, offset ); + format = format.substring( 1 ); + } + else + { + ZoneId id = ZoneId.systemDefault(); + offset = id.getRules().getOffset( instant ); + date = ZonedDateTime.ofInstant( instant, id ); + } + + if( format.equals( "*t" ) ) return LuaDateTime.toTable( date, offset, instant ); + + DateTimeFormatterBuilder formatter = new DateTimeFormatterBuilder(); + LuaDateTime.format( formatter, format, offset ); + return formatter.toFormatter( Locale.ROOT ).format( date ); + } + } diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 2d07d58bc..ee37d3ba4 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -7,88 +7,74 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; -import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.*; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IWorkMonitor; import dan200.computercraft.api.peripheral.NotAttachedException; +import dan200.computercraft.core.asm.LuaMethod; +import dan200.computercraft.core.asm.NamedMethod; +import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.tracking.TrackingField; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static dan200.computercraft.api.lua.ArgumentHelper.getString; +import java.util.*; public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener { private class PeripheralWrapper extends ComputerAccess { - private final String m_side; - private final IPeripheral m_peripheral; + private final String side; + private final IPeripheral peripheral; - private String m_type; - private String[] m_methods; - private Map m_methodMap; - private boolean m_attached; + private final String type; + private final Map methodMap; + private boolean attached; PeripheralWrapper( IPeripheral peripheral, String side ) { - super( m_environment ); - m_side = side; - m_peripheral = peripheral; - m_attached = false; + super( environment ); + this.side = side; + this.peripheral = peripheral; + attached = false; - m_type = peripheral.getType(); - m_methods = peripheral.getMethodNames(); - assert m_type != null; - assert m_methods != null; + type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); - m_methodMap = new HashMap<>(); - for( int i = 0; i < m_methods.length; i++ ) - { - if( m_methods[i] != null ) - { - m_methodMap.put( m_methods[i], i ); - } - } + methodMap = PeripheralAPI.getMethods( peripheral ); } public IPeripheral getPeripheral() { - return m_peripheral; + return peripheral; } public String getType() { - return m_type; + return type; } - public String[] getMethods() + public Collection getMethods() { - return m_methods; + return methodMap.keySet(); } public synchronized boolean isAttached() { - return m_attached; + return attached; } public synchronized void attach() { - m_attached = true; - m_peripheral.attach( this ); + attached = true; + peripheral.attach( this ); } public void detach() { // Call detach - m_peripheral.detach( this ); + peripheral.detach( this ); synchronized( this ) { @@ -96,63 +82,56 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange unmountAll(); } - m_attached = false; + attached = false; } - public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException + public MethodResult call( ILuaContext context, String methodName, IArguments arguments ) throws LuaException { - int method = -1; + PeripheralMethod method; synchronized( this ) { - if( m_methodMap.containsKey( methodName ) ) - { - method = m_methodMap.get( methodName ); - } - } - if( method >= 0 ) - { - m_environment.addTrackingChange( TrackingField.PERIPHERAL_OPS ); - return m_peripheral.callMethod( this, context, method, arguments ); - } - else - { - throw new LuaException( "No such method " + methodName ); + method = methodMap.get( methodName ); } + + if( method == null ) throw new LuaException( "No such method " + methodName ); + + environment.addTrackingChange( TrackingField.PERIPHERAL_OPS ); + return method.apply( peripheral, context, this, arguments ); } // IComputerAccess implementation @Override public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName ) { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); return super.mount( desiredLoc, mount, driveName ); } @Override public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName ) { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); return super.mountWritable( desiredLoc, mount, driveName ); } @Override public synchronized void unmount( String location ) { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); super.unmount( location ); } @Override public int getID() { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); return super.getID(); } @Override - public void queueEvent( @Nonnull final String event, final Object[] arguments ) + public void queueEvent( @Nonnull String event, Object... arguments ) { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); super.queueEvent( event, arguments ); } @@ -160,18 +139,18 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public String getAttachmentName() { - if( !m_attached ) throw new NotAttachedException(); - return m_side; + if( !attached ) throw new NotAttachedException(); + return side; } @Nonnull @Override public Map getAvailablePeripherals() { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); Map peripherals = new HashMap<>(); - for( PeripheralWrapper wrapper : m_peripherals ) + for( PeripheralWrapper wrapper : PeripheralAPI.this.peripherals ) { if( wrapper != null && wrapper.isAttached() ) { @@ -186,9 +165,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public IPeripheral getAvailablePeripheral( @Nonnull String name ) { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); - for( PeripheralWrapper wrapper : m_peripherals ) + for( PeripheralWrapper wrapper : peripherals ) { if( wrapper != null && wrapper.isAttached() && wrapper.getAttachmentName().equals( name ) ) { @@ -202,27 +181,20 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public IWorkMonitor getMainThreadMonitor() { - if( !m_attached ) throw new NotAttachedException(); + if( !attached ) throw new NotAttachedException(); return super.getMainThreadMonitor(); } } - private final IAPIEnvironment m_environment; - private final PeripheralWrapper[] m_peripherals; - private boolean m_running; + private final IAPIEnvironment environment; + private final PeripheralWrapper[] peripherals = new PeripheralWrapper[6]; + private boolean running; public PeripheralAPI( IAPIEnvironment environment ) { - m_environment = environment; - m_environment.setPeripheralChangeListener( this ); - - m_peripherals = new PeripheralWrapper[6]; - for( int i = 0; i < 6; i++ ) - { - m_peripherals[i] = null; - } - - m_running = false; + this.environment = environment; + this.environment.setPeripheralChangeListener( this ); + running = false; } // IPeripheralChangeListener @@ -230,37 +202,35 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public void onPeripheralChanged( ComputerSide side, IPeripheral newPeripheral ) { - synchronized( m_peripherals ) + synchronized( peripherals ) { int index = side.ordinal(); - if( m_peripherals[index] != null ) + if( peripherals[index] != null ) { // Queue a detachment - final PeripheralWrapper wrapper = m_peripherals[index]; + final PeripheralWrapper wrapper = peripherals[index]; if( wrapper.isAttached() ) wrapper.detach(); // Queue a detachment event - m_environment.queueEvent( "peripheral_detach", new Object[] { side.getName() } ); + environment.queueEvent( "peripheral_detach", side.getName() ); } // Assign the new peripheral - m_peripherals[index] = newPeripheral == null ? null + peripherals[index] = newPeripheral == null ? null : new PeripheralWrapper( newPeripheral, side.getName() ); - if( m_peripherals[index] != null ) + if( peripherals[index] != null ) { // Queue an attachment - final PeripheralWrapper wrapper = m_peripherals[index]; - if( m_running && !wrapper.isAttached() ) wrapper.attach(); + final PeripheralWrapper wrapper = peripherals[index]; + if( running && !wrapper.isAttached() ) wrapper.attach(); // Queue an attachment event - m_environment.queueEvent( "peripheral", new Object[] { side.getName() } ); + environment.queueEvent( "peripheral", side.getName() ); } } } - // ILuaAPI implementation - @Override public String[] getNames() { @@ -270,12 +240,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public void startup() { - synchronized( m_peripherals ) + synchronized( peripherals ) { - m_running = true; + running = true; for( int i = 0; i < 6; i++ ) { - PeripheralWrapper wrapper = m_peripherals[i]; + PeripheralWrapper wrapper = peripherals[i]; if( wrapper != null && !wrapper.isAttached() ) wrapper.attach(); } } @@ -284,12 +254,12 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange @Override public void shutdown() { - synchronized( m_peripherals ) + synchronized( peripherals ) { - m_running = false; + running = false; for( int i = 0; i < 6; i++ ) { - PeripheralWrapper wrapper = m_peripherals[i]; + PeripheralWrapper wrapper = peripherals[i]; if( wrapper != null && wrapper.isAttached() ) { wrapper.detach(); @@ -298,98 +268,95 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange } } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final boolean isPresent( String sideName ) { - return new String[] { - "isPresent", - "getType", - "getMethods", - "call", - }; + ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); + if( side != null ) + { + synchronized( peripherals ) + { + PeripheralWrapper p = peripherals[side.ordinal()]; + if( p != null ) return true; + } + } + return false; } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException + @LuaFunction + public final Object[] getType( String sideName ) { - switch( method ) + ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); + if( side == null ) return null; + + synchronized( peripherals ) { - case 0: - { - // isPresent - boolean present = false; - ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); - if( side != null ) - { - synchronized( m_peripherals ) - { - PeripheralWrapper p = m_peripherals[side.ordinal()]; - if( p != null ) present = true; - } - } - return new Object[] { present }; - } - case 1: - { - // getType - ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); - if( side != null ) - { - synchronized( m_peripherals ) - { - PeripheralWrapper p = m_peripherals[side.ordinal()]; - if( p != null ) return new Object[] { p.getType() }; - } - } - return null; - } - case 2: - { - // getMethods - ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); - if( side != null ) - { - synchronized( m_peripherals ) - { - PeripheralWrapper p = m_peripherals[side.ordinal()]; - if( p != null ) return new Object[] { p.getMethods() }; - } - } + PeripheralWrapper p = peripherals[side.ordinal()]; + if( p != null ) return new Object[] { p.getType() }; + } + return null; + } - return null; - } - case 3: - { - // call - ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); - String methodName = getString( args, 1 ); - Object[] methodArgs = Arrays.copyOfRange( args, 2, args.length ); + @LuaFunction + public final Object[] getMethods( String sideName ) + { + ComputerSide side = ComputerSide.valueOfInsensitive( sideName ); + if( side == null ) return null; - if( side == null ) throw new LuaException( "No peripheral attached" ); + synchronized( peripherals ) + { + PeripheralWrapper p = peripherals[side.ordinal()]; + if( p != null ) return new Object[] { p.getMethods() }; + } + return null; + } - PeripheralWrapper p; - synchronized( m_peripherals ) - { - p = m_peripherals[side.ordinal()]; - } - if( p == null ) throw new LuaException( "No peripheral attached" ); + @LuaFunction + public final MethodResult call( ILuaContext context, IArguments args ) throws LuaException + { + ComputerSide side = ComputerSide.valueOfInsensitive( args.getString( 0 ) ); + String methodName = args.getString( 1 ); + IArguments methodArgs = args.drop( 2 ); - try - { - return p.call( context, methodName, methodArgs ); - } - catch( LuaException e ) - { - // We increase the error level by one in order to shift the error level to where peripheral.call was - // invoked. It would be possible to do it in Lua code, but would add significantly more overhead. - if( e.getLevel() > 0 ) throw new FastLuaException( e.getMessage(), e.getLevel() + 1 ); - throw e; - } - } - default: - return null; + if( side == null ) throw new LuaException( "No peripheral attached" ); + + PeripheralWrapper p; + synchronized( peripherals ) + { + p = peripherals[side.ordinal()]; + } + if( p == null ) throw new LuaException( "No peripheral attached" ); + + try + { + return p.call( context, methodName, methodArgs ).adjustError( 1 ); + } + catch( LuaException e ) + { + // We increase the error level by one in order to shift the error level to where peripheral.call was + // invoked. It would be possible to do it in Lua code, but would add significantly more overhead. + if( e.getLevel() > 0 ) throw new FastLuaException( e.getMessage(), e.getLevel() + 1 ); + throw e; } } + public static Map getMethods( IPeripheral peripheral ) + { + String[] dynamicMethods = peripheral instanceof IDynamicPeripheral + ? Objects.requireNonNull( ((IDynamicPeripheral) peripheral).getMethodNames(), "Peripheral methods cannot be null" ) + : LuaMethod.EMPTY_METHODS; + + List> methods = PeripheralMethod.GENERATOR.getMethods( peripheral.getClass() ); + + Map methodMap = new HashMap<>( methods.size() + dynamicMethods.length ); + for( int i = 0; i < dynamicMethods.length; i++ ) + { + methodMap.put( dynamicMethods[i], PeripheralMethod.DYNAMIC.get( i ) ); + } + for( NamedMethod method : methods ) + { + methodMap.put( method.getName(), method.getMethod() ); + } + return methodMap; + } } diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index fbb8feffa..ce70fc5d2 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -6,14 +6,10 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.core.computer.ComputerSide; -import javax.annotation.Nonnull; - -import static dan200.computercraft.api.lua.ArgumentHelper.*; - public class RedstoneAPI implements ILuaAPI { private final IAPIEnvironment environment; @@ -29,95 +25,71 @@ public class RedstoneAPI implements ILuaAPI return new String[] { "rs", "redstone" }; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final String[] getSides() { - return new String[] { - "getSides", - "setOutput", - "getOutput", - "getInput", - "setBundledOutput", - "getBundledOutput", - "getBundledInput", - "testBundledInput", - "setAnalogOutput", - "setAnalogueOutput", - "getAnalogOutput", - "getAnalogueOutput", - "getAnalogInput", - "getAnalogueInput", - }; + return ComputerSide.NAMES; } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final void setOutput( ComputerSide side, boolean output ) { - switch( method ) - { - case 0: // getSides - return new Object[] { ComputerSide.NAMES }; - case 1: - { - // setOutput - ComputerSide side = parseSide( args ); - boolean output = getBoolean( args, 1 ); - environment.setOutput( side, output ? 15 : 0 ); - return null; - } - case 2: // getOutput - return new Object[] { environment.getOutput( parseSide( args ) ) > 0 }; - case 3: // getInput - return new Object[] { environment.getInput( parseSide( args ) ) > 0 }; - case 4: - { - // setBundledOutput - ComputerSide side = parseSide( args ); - int output = getInt( args, 1 ); - environment.setBundledOutput( side, output ); - return null; - } - case 5: // getBundledOutput - return new Object[] { environment.getBundledOutput( parseSide( args ) ) }; - case 6: // getBundledInput - return new Object[] { environment.getBundledInput( parseSide( args ) ) }; - case 7: - { - // testBundledInput - ComputerSide side = parseSide( args ); - int mask = getInt( args, 1 ); - int input = environment.getBundledInput( side ); - return new Object[] { (input & mask) == mask }; - } - case 8: - case 9: - { - // setAnalogOutput/setAnalogueOutput - ComputerSide side = parseSide( args ); - int output = getInt( args, 1 ); - if( output < 0 || output > 15 ) - { - throw new LuaException( "Expected number in range 0-15" ); - } - environment.setOutput( side, output ); - return null; - } - case 10: - case 11: // getAnalogOutput/getAnalogueOutput - return new Object[] { environment.getOutput( parseSide( args ) ) }; - case 12: - case 13: // getAnalogInput/getAnalogueInput - return new Object[] { environment.getInput( parseSide( args ) ) }; - default: - return null; - } + environment.setOutput( side, output ? 15 : 0 ); } - private static ComputerSide parseSide( Object[] args ) throws LuaException + @LuaFunction + public final boolean getOutput( ComputerSide side ) { - ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) ); - if( side == null ) throw new LuaException( "Invalid side." ); - return side; + return environment.getOutput( side ) > 0; + } + + @LuaFunction + public final boolean getInput( ComputerSide side ) + { + return environment.getInput( side ) > 0; + } + + @LuaFunction( { "setAnalogOutput", "setAnalogueOutput" } ) + public final void setAnalogOutput( ComputerSide side, int output ) throws LuaException + { + if( output < 0 || output > 15 ) throw new LuaException( "Expected number in range 0-15" ); + environment.setOutput( side, output ); + } + + @LuaFunction( { "getAnalogOutput", "getAnalogueOutput" } ) + public final int getAnalogOutput( ComputerSide side ) + { + return environment.getOutput( side ); + } + + @LuaFunction( { "getAnalogInput", "getAnalogueInput" } ) + public final int getAnalogInput( ComputerSide side ) + { + return environment.getInput( side ); + } + + @LuaFunction + public final void setBundledOutput( ComputerSide side, int output ) + { + environment.setBundledOutput( side, output ); + } + + @LuaFunction + public final int getBundledOutput( ComputerSide side ) + { + return environment.getBundledOutput( side ); + } + + @LuaFunction + public final int getBundledInput( ComputerSide side ) + { + return environment.getBundledOutput( side ); + } + + @LuaFunction + public final boolean testBundledInput( ComputerSide side, int mask ) + { + int input = environment.getBundledInput( side ); + return (input & mask) == mask; } } diff --git a/src/main/java/dan200/computercraft/core/apis/TableHelper.java b/src/main/java/dan200/computercraft/core/apis/TableHelper.java index 4ceae1659..296bfb0a1 100644 --- a/src/main/java/dan200/computercraft/core/apis/TableHelper.java +++ b/src/main/java/dan200/computercraft/core/apis/TableHelper.java @@ -5,14 +5,14 @@ */ package dan200.computercraft.core.apis; -import dan200.computercraft.api.lua.ArgumentHelper; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaValues; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Map; -import static dan200.computercraft.api.lua.ArgumentHelper.getNumericType; +import static dan200.computercraft.api.lua.LuaValues.getNumericType; /** * Various helpers for tables. @@ -27,7 +27,7 @@ public final class TableHelper @Nonnull public static LuaException badKey( @Nonnull String key, @Nonnull String expected, @Nullable Object actual ) { - return badKey( key, expected, ArgumentHelper.getType( actual ) ); + return badKey( key, expected, LuaValues.getType( actual ) ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 6bb290f67..195085331 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -6,27 +6,23 @@ package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.util.Colour; -import dan200.computercraft.shared.util.Palette; -import org.apache.commons.lang3.ArrayUtils; import javax.annotation.Nonnull; -import static dan200.computercraft.api.lua.ArgumentHelper.*; - -public class TermAPI implements ILuaAPI +public class TermAPI extends TermMethods implements ILuaAPI { - private final Terminal m_terminal; - private final IComputerEnvironment m_environment; + private final Terminal terminal; + private final IComputerEnvironment environment; public TermAPI( IAPIEnvironment environment ) { - m_terminal = environment.getTerminal(); - m_environment = environment.getComputerEnvironment(); + terminal = environment.getTerminal(); + this.environment = environment.getComputerEnvironment(); } @Override @@ -35,262 +31,29 @@ public class TermAPI implements ILuaAPI return new String[] { "term" }; } + @LuaFunction( { "nativePaletteColour", "nativePaletteColor" } ) + public final Object[] nativePaletteColour( int colourArg ) throws LuaException + { + int colour = 15 - parseColour( colourArg ); + Colour c = Colour.fromInt( colour ); + + float[] rgb = c.getRGB(); + + Object[] rgbObj = new Object[rgb.length]; + for( int i = 0; i < rgbObj.length; ++i ) rgbObj[i] = rgb[i]; + return rgbObj; + } + @Nonnull @Override - public String[] getMethodNames() + public Terminal getTerminal() { - return new String[] { - "write", - "scroll", - "setCursorPos", - "setCursorBlink", - "getCursorPos", - "getSize", - "clear", - "clearLine", - "setTextColour", - "setTextColor", - "setBackgroundColour", - "setBackgroundColor", - "isColour", - "isColor", - "getTextColour", - "getTextColor", - "getBackgroundColour", - "getBackgroundColor", - "blit", - "setPaletteColour", - "setPaletteColor", - "getPaletteColour", - "getPaletteColor", - "nativePaletteColour", - "nativePaletteColor", - "getCursorBlink", - }; - } - - public static int parseColour( Object[] args ) throws LuaException - { - int colour = getInt( args, 0 ); - if( colour <= 0 ) - { - throw new LuaException( "Colour out of range" ); - } - colour = getHighestBit( colour ) - 1; - if( colour < 0 || colour > 15 ) - { - throw new LuaException( "Colour out of range" ); - } - return colour; - } - - public static Object[] encodeColour( int colour ) throws LuaException - { - return new Object[] { 1 << colour }; - } - - public static void setColour( Terminal terminal, int colour, double r, double g, double b ) - { - if( terminal.getPalette() != null ) - { - terminal.getPalette().setColour( colour, r, g, b ); - terminal.setChanged(); - } + return terminal; } @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + public boolean isColour() { - switch( method ) - { - case 0: - { - // write - String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; - synchronized( m_terminal ) - { - m_terminal.write( text ); - m_terminal.setCursorPos( m_terminal.getCursorX() + text.length(), m_terminal.getCursorY() ); - } - return null; - } - case 1: - { - // scroll - int y = getInt( args, 0 ); - synchronized( m_terminal ) - { - m_terminal.scroll( y ); - } - return null; - } - case 2: - { - // setCursorPos - int x = getInt( args, 0 ) - 1; - int y = getInt( args, 1 ) - 1; - synchronized( m_terminal ) - { - m_terminal.setCursorPos( x, y ); - } - return null; - } - case 3: - { - // setCursorBlink - boolean b = getBoolean( args, 0 ); - synchronized( m_terminal ) - { - m_terminal.setCursorBlink( b ); - } - return null; - } - case 4: - { - // getCursorPos - int x, y; - synchronized( m_terminal ) - { - x = m_terminal.getCursorX(); - y = m_terminal.getCursorY(); - } - return new Object[] { x + 1, y + 1 }; - } - case 5: - { - // getSize - int width, height; - synchronized( m_terminal ) - { - width = m_terminal.getWidth(); - height = m_terminal.getHeight(); - } - return new Object[] { width, height }; - } - case 6: // clear - synchronized( m_terminal ) - { - m_terminal.clear(); - } - return null; - case 7: // clearLine - synchronized( m_terminal ) - { - m_terminal.clearLine(); - } - return null; - case 8: - case 9: - { - // setTextColour/setTextColor - int colour = parseColour( args ); - synchronized( m_terminal ) - { - m_terminal.setTextColour( colour ); - } - return null; - } - case 10: - case 11: - { - // setBackgroundColour/setBackgroundColor - int colour = parseColour( args ); - synchronized( m_terminal ) - { - m_terminal.setBackgroundColour( colour ); - } - return null; - } - case 12: - case 13: // isColour/isColor - return new Object[] { m_environment.isColour() }; - case 14: - case 15: // getTextColour/getTextColor - return encodeColour( m_terminal.getTextColour() ); - case 16: - case 17: // getBackgroundColour/getBackgroundColor - return encodeColour( m_terminal.getBackgroundColour() ); - case 18: - { - // blit - String text = getString( args, 0 ); - String textColour = getString( args, 1 ); - String backgroundColour = getString( args, 2 ); - if( textColour.length() != text.length() || backgroundColour.length() != text.length() ) - { - throw new LuaException( "Arguments must be the same length" ); - } - - synchronized( m_terminal ) - { - m_terminal.blit( text, textColour, backgroundColour ); - m_terminal.setCursorPos( m_terminal.getCursorX() + text.length(), m_terminal.getCursorY() ); - } - return null; - } - case 19: - case 20: - { - // setPaletteColour/setPaletteColor - int colour = 15 - parseColour( args ); - if( args.length == 2 ) - { - int hex = getInt( args, 1 ); - double[] rgb = Palette.decodeRGB8( hex ); - setColour( m_terminal, colour, rgb[0], rgb[1], rgb[2] ); - } - else - { - double r = getFiniteDouble( args, 1 ); - double g = getFiniteDouble( args, 2 ); - double b = getFiniteDouble( args, 3 ); - setColour( m_terminal, colour, r, g, b ); - } - return null; - } - case 21: - case 22: - { - // getPaletteColour/getPaletteColor - int colour = 15 - parseColour( args ); - synchronized( m_terminal ) - { - if( m_terminal.getPalette() != null ) - { - return ArrayUtils.toObject( m_terminal.getPalette().getColour( colour ) ); - } - } - return null; - } - case 23: - case 24: - { - // nativePaletteColour/nativePaletteColor - int colour = 15 - parseColour( args ); - Colour c = Colour.fromInt( colour ); - - float[] rgb = c.getRGB(); - - Object[] rgbObj = new Object[rgb.length]; - for( int i = 0; i < rgbObj.length; ++i ) rgbObj[i] = rgb[i]; - return rgbObj; - } - case 25: - // getCursorBlink - return new Object[] { m_terminal.getCursorBlink() }; - default: - return null; - } - } - - private static int getHighestBit( int group ) - { - int bit = 0; - while( group > 0 ) - { - group >>= 1; - bit++; - } - return bit; + return environment.isColour(); } } diff --git a/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/src/main/java/dan200/computercraft/core/apis/TermMethods.java new file mode 100644 index 000000000..d7674ef3f --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -0,0 +1,222 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.util.Palette; +import dan200.computercraft.shared.util.StringUtil; +import org.apache.commons.lang3.ArrayUtils; + +import javax.annotation.Nonnull; + +/** + * A base class for all objects which interact with a terminal. Namely the {@link TermAPI} and monitors. + */ +public abstract class TermMethods +{ + private static int getHighestBit( int group ) + { + int bit = 0; + while( group > 0 ) + { + group >>= 1; + bit++; + } + return bit; + } + + @Nonnull + public abstract Terminal getTerminal() throws LuaException; + + public abstract boolean isColour() throws LuaException; + + @LuaFunction + public final void write( IArguments arguments ) throws LuaException + { + String text = StringUtil.toString( arguments.get( 0 ) ); + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.write( text ); + terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() ); + } + } + + @LuaFunction + public final void scroll( int y ) throws LuaException + { + getTerminal().scroll( y ); + } + + @LuaFunction + public final Object[] getCursorPos() throws LuaException + { + Terminal terminal = getTerminal(); + return new Object[] { terminal.getCursorX() + 1, terminal.getCursorY() + 1 }; + } + + @LuaFunction + public final void setCursorPos( int x, int y ) throws LuaException + { + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setCursorPos( x - 1, y - 1 ); + } + } + + @LuaFunction + public final boolean getCursorBlink() throws LuaException + { + return getTerminal().getCursorBlink(); + } + + @LuaFunction + public final void setCursorBlink( boolean blink ) throws LuaException + { + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setCursorBlink( blink ); + } + } + + @LuaFunction + public final Object[] getSize() throws LuaException + { + Terminal terminal = getTerminal(); + return new Object[] { terminal.getWidth(), terminal.getHeight() }; + } + + @LuaFunction + public final void clear() throws LuaException + { + getTerminal().clear(); + } + + @LuaFunction + public final void clearLine() throws LuaException + { + getTerminal().clearLine(); + } + + @LuaFunction( { "getTextColour", "getTextColor" } ) + public final int getTextColour() throws LuaException + { + return encodeColour( getTerminal().getTextColour() ); + } + + @LuaFunction( { "setTextColour", "setTextColor" } ) + public final void setTextColour( int colourArg ) throws LuaException + { + int colour = parseColour( colourArg ); + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setTextColour( colour ); + } + } + + @LuaFunction( { "getBackgroundColour", "getBackgroundColor" } ) + public final int getBackgroundColour() throws LuaException + { + return encodeColour( getTerminal().getBackgroundColour() ); + } + + @LuaFunction( { "setBackgroundColour", "setBackgroundColor" } ) + public final void setBackgroundColour( int colourArg ) throws LuaException + { + int colour = parseColour( colourArg ); + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.setBackgroundColour( colour ); + } + } + + @LuaFunction( { "isColour", "isColor" } ) + public final boolean getIsColour() throws LuaException + { + return isColour(); + } + + @LuaFunction + public final void blit( String text, String textColour, String backgroundColour ) throws LuaException + { + if( textColour.length() != text.length() || backgroundColour.length() != text.length() ) + { + throw new LuaException( "Arguments must be the same length" ); + } + + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + terminal.blit( text, textColour, backgroundColour ); + terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() ); + } + } + + @LuaFunction( { "setPaletteColour", "setPaletteColor" } ) + public final void setPaletteColour( IArguments args ) throws LuaException + { + int colour = 15 - parseColour( args.getInt( 0 ) ); + if( args.count() == 2 ) + { + int hex = args.getInt( 1 ); + double[] rgb = Palette.decodeRGB8( hex ); + setColour( getTerminal(), colour, rgb[0], rgb[1], rgb[2] ); + } + else + { + double r = args.getFiniteDouble( 1 ); + double g = args.getFiniteDouble( 2 ); + double b = args.getFiniteDouble( 3 ); + setColour( getTerminal(), colour, r, g, b ); + } + } + + @LuaFunction( { "getPaletteColour", "getPaletteColor" } ) + public final Object[] getPaletteColour( int colourArg ) throws LuaException + { + int colour = 15 - parseColour( colourArg ); + Terminal terminal = getTerminal(); + synchronized( terminal ) + { + if( terminal.getPalette() != null ) + { + return ArrayUtils.toObject( terminal.getPalette().getColour( colour ) ); + } + } + return null; + } + + public static int parseColour( int colour ) throws LuaException + { + if( colour <= 0 ) throw new LuaException( "Colour out of range" ); + colour = getHighestBit( colour ) - 1; + if( colour < 0 || colour > 15 ) throw new LuaException( "Colour out of range" ); + return colour; + } + + + public static int encodeColour( int colour ) + { + return 1 << colour; + } + + public static void setColour( Terminal terminal, int colour, double r, double g, double b ) + { + if( terminal.getPalette() != null ) + { + terminal.getPalette().setColour( colour, r, g, b ); + terminal.setChanged(); + } + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index df0ff48d5..ce9fda477 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -5,11 +5,10 @@ */ package dan200.computercraft.core.apis.handles; -import com.google.common.collect.ObjectArrays; -import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; -import javax.annotation.Nonnull; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; @@ -17,208 +16,205 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; - -import static dan200.computercraft.api.lua.ArgumentHelper.getInt; -import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; +import java.util.Optional; public class BinaryReadableHandle extends HandleGeneric { private static final int BUFFER_SIZE = 8192; - private static final String[] METHOD_NAMES = new String[] { "read", "readAll", "readLine", "close" }; - private static final String[] METHOD_SEEK_NAMES = ObjectArrays.concat( METHOD_NAMES, new String[] { "seek" }, String.class ); - - private final ReadableByteChannel m_reader; - private final SeekableByteChannel m_seekable; + private final ReadableByteChannel reader; + final SeekableByteChannel seekable; private final ByteBuffer single = ByteBuffer.allocate( 1 ); - public BinaryReadableHandle( ReadableByteChannel channel, Closeable closeable ) + protected BinaryReadableHandle( ReadableByteChannel reader, SeekableByteChannel seekable, Closeable closeable ) { super( closeable ); - m_reader = channel; - m_seekable = asSeekable( channel ); + this.reader = reader; + this.seekable = seekable; } - public BinaryReadableHandle( ReadableByteChannel channel ) + public static BinaryReadableHandle of( ReadableByteChannel channel, Closeable closeable ) { - this( channel, channel ); + SeekableByteChannel seekable = asSeekable( channel ); + return seekable == null ? new BinaryReadableHandle( channel, null, closeable ) : new Seekable( seekable, closeable ); } - @Nonnull - @Override - public String[] getMethodNames() + public static BinaryReadableHandle of( ReadableByteChannel channel ) { - return m_seekable == null ? METHOD_NAMES : METHOD_SEEK_NAMES; + return of( channel, channel ); } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final Object[] read( Optional countArg ) throws LuaException { - switch( method ) + checkOpen(); + try { - case 0: // read - checkOpen(); - try - { - if( args.length > 0 && args[0] != null ) - { - int count = getInt( args, 0 ); - if( count < 0 ) - { - throw new LuaException( "Cannot read a negative number of bytes" ); - } - else if( count == 0 && m_seekable != null ) - { - return m_seekable.position() >= m_seekable.size() ? null : new Object[] { "" }; - } - - if( count <= BUFFER_SIZE ) - { - ByteBuffer buffer = ByteBuffer.allocate( count ); - - int read = m_reader.read( buffer ); - if( read < 0 ) return null; - return new Object[] { read < count ? Arrays.copyOf( buffer.array(), read ) : buffer.array() }; - } - else - { - // Read the initial set of characters, failing if none are read. - ByteBuffer buffer = ByteBuffer.allocate( BUFFER_SIZE ); - int read = m_reader.read( buffer ); - if( read < 0 ) return null; - - // If we failed to read "enough" here, let's just abort - if( read >= count || read < BUFFER_SIZE ) - { - return new Object[] { Arrays.copyOf( buffer.array(), read ) }; - } - - // Build up an array of ByteBuffers. Hopefully this means we can perform less allocation - // than doubling up the buffer each time. - int totalRead = read; - List parts = new ArrayList<>( 4 ); - parts.add( buffer ); - while( read >= BUFFER_SIZE && totalRead < count ) - { - buffer = ByteBuffer.allocate( Math.min( BUFFER_SIZE, count - totalRead ) ); - read = m_reader.read( buffer ); - if( read < 0 ) break; - - totalRead += read; - parts.add( buffer ); - } - - // Now just copy all the bytes across! - byte[] bytes = new byte[totalRead]; - int pos = 0; - for( ByteBuffer part : parts ) - { - System.arraycopy( part.array(), 0, bytes, pos, part.position() ); - pos += part.position(); - } - return new Object[] { bytes }; - } - } - else - { - single.clear(); - int b = m_reader.read( single ); - return b == -1 ? null : new Object[] { single.get( 0 ) & 0xFF }; - } - } - catch( IOException e ) - { - return null; - } - case 1: // readAll - checkOpen(); - try - { - int expected = 32; - if( m_seekable != null ) - { - expected = Math.max( expected, (int) (m_seekable.size() - m_seekable.position()) ); - } - ByteArrayOutputStream stream = new ByteArrayOutputStream( expected ); - - ByteBuffer buf = ByteBuffer.allocate( 8192 ); - boolean readAnything = false; - while( true ) - { - buf.clear(); - int r = m_reader.read( buf ); - if( r == -1 ) break; - - readAnything = true; - stream.write( buf.array(), 0, r ); - } - return readAnything ? new Object[] { stream.toByteArray() } : null; - } - catch( IOException e ) - { - return null; - } - case 2: // readLine + if( countArg.isPresent() ) { - checkOpen(); - boolean withTrailing = optBoolean( args, 0, false ); - try + int count = countArg.get(); + if( count < 0 ) throw new LuaException( "Cannot read a negative number of bytes" ); + if( count == 0 && seekable != null ) { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - boolean readAnything = false, readRc = false; - while( true ) - { - single.clear(); - int read = m_reader.read( single ); - if( read <= 0 ) - { - // Nothing else to read, and we saw no \n. Return the array. If we saw a \r, then add it - // back. - if( readRc ) stream.write( '\r' ); - return readAnything ? new Object[] { stream.toByteArray() } : null; - } - - readAnything = true; - - byte chr = single.get( 0 ); - if( chr == '\n' ) - { - if( withTrailing ) - { - if( readRc ) stream.write( '\r' ); - stream.write( chr ); - } - return new Object[] { stream.toByteArray() }; - } - else - { - // We want to skip \r\n, but obviously need to include cases where \r is not followed by \n. - // Note, this behaviour is non-standard compliant (strictly speaking we should have no - // special logic for \r), but we preserve compatibility with EncodedReadableHandle and - // previous behaviour of the io library. - if( readRc ) stream.write( '\r' ); - readRc = chr == '\r'; - if( !readRc ) stream.write( chr ); - } - } + return seekable.position() >= seekable.size() ? null : new Object[] { "" }; } - catch( IOException e ) + + if( count <= BUFFER_SIZE ) { - return null; + ByteBuffer buffer = ByteBuffer.allocate( count ); + + int read = reader.read( buffer ); + if( read < 0 ) return null; + buffer.flip(); + return new Object[] { buffer }; + } + else + { + // Read the initial set of characters, failing if none are read. + ByteBuffer buffer = ByteBuffer.allocate( BUFFER_SIZE ); + int read = reader.read( buffer ); + if( read < 0 ) return null; + + // If we failed to read "enough" here, let's just abort + if( read >= count || read < BUFFER_SIZE ) + { + buffer.flip(); + return new Object[] { buffer }; + } + + // Build up an array of ByteBuffers. Hopefully this means we can perform less allocation + // than doubling up the buffer each time. + int totalRead = read; + List parts = new ArrayList<>( 4 ); + parts.add( buffer ); + while( read >= BUFFER_SIZE && totalRead < count ) + { + buffer = ByteBuffer.allocate( Math.min( BUFFER_SIZE, count - totalRead ) ); + read = reader.read( buffer ); + if( read < 0 ) break; + + totalRead += read; + parts.add( buffer ); + } + + // Now just copy all the bytes across! + byte[] bytes = new byte[totalRead]; + int pos = 0; + for( ByteBuffer part : parts ) + { + System.arraycopy( part.array(), 0, bytes, pos, part.position() ); + pos += part.position(); + } + return new Object[] { bytes }; } } - case 3: // close - checkOpen(); - close(); - return null; - case 4: // seek - checkOpen(); - return handleSeek( m_seekable, args ); - default: - return null; + else + { + single.clear(); + int b = reader.read( single ); + return b == -1 ? null : new Object[] { single.get( 0 ) & 0xFF }; + } + } + catch( IOException e ) + { + return null; + } + } + + @LuaFunction + public final Object[] readAll() throws LuaException + { + checkOpen(); + try + { + int expected = 32; + if( seekable != null ) expected = Math.max( expected, (int) (seekable.size() - seekable.position()) ); + ByteArrayOutputStream stream = new ByteArrayOutputStream( expected ); + + ByteBuffer buf = ByteBuffer.allocate( 8192 ); + boolean readAnything = false; + while( true ) + { + buf.clear(); + int r = reader.read( buf ); + if( r == -1 ) break; + + readAnything = true; + stream.write( buf.array(), 0, r ); + } + return readAnything ? new Object[] { stream.toByteArray() } : null; + } + catch( IOException e ) + { + return null; + } + } + + @LuaFunction + public final Object[] readLine( Optional withTrailingArg ) throws LuaException + { + checkOpen(); + boolean withTrailing = withTrailingArg.orElse( false ); + try + { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + boolean readAnything = false, readRc = false; + while( true ) + { + single.clear(); + int read = reader.read( single ); + if( read <= 0 ) + { + // Nothing else to read, and we saw no \n. Return the array. If we saw a \r, then add it + // back. + if( readRc ) stream.write( '\r' ); + return readAnything ? new Object[] { stream.toByteArray() } : null; + } + + readAnything = true; + + byte chr = single.get( 0 ); + if( chr == '\n' ) + { + if( withTrailing ) + { + if( readRc ) stream.write( '\r' ); + stream.write( chr ); + } + return new Object[] { stream.toByteArray() }; + } + else + { + // We want to skip \r\n, but obviously need to include cases where \r is not followed by \n. + // Note, this behaviour is non-standard compliant (strictly speaking we should have no + // special logic for \r), but we preserve compatibility with EncodedReadableHandle and + // previous behaviour of the io library. + if( readRc ) stream.write( '\r' ); + readRc = chr == '\r'; + if( !readRc ) stream.write( chr ); + } + } + } + catch( IOException e ) + { + return null; + } + } + + public static class Seekable extends BinaryReadableHandle + { + public Seekable( SeekableByteChannel seekable, Closeable closeable ) + { + super( seekable, seekable, closeable ); + } + + @LuaFunction + public final Object[] seek( IArguments arguments ) throws LuaException + { + checkOpen(); + return handleSeek( seekable, arguments ); } } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index 2ab94bd4b..b5b3647bb 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -5,13 +5,11 @@ */ package dan200.computercraft.core.apis.handles; -import com.google.common.collect.ObjectArrays; -import dan200.computercraft.api.lua.ArgumentHelper; -import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.shared.util.StringUtil; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.LuaValues; -import javax.annotation.Nonnull; import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; @@ -21,87 +19,85 @@ import java.nio.channels.WritableByteChannel; public class BinaryWritableHandle extends HandleGeneric { - private static final String[] METHOD_NAMES = new String[] { "write", "flush", "close" }; - private static final String[] METHOD_SEEK_NAMES = ObjectArrays.concat( METHOD_NAMES, new String[] { "seek" }, String.class ); - - private final WritableByteChannel m_writer; - private final SeekableByteChannel m_seekable; + private final WritableByteChannel writer; + final SeekableByteChannel seekable; private final ByteBuffer single = ByteBuffer.allocate( 1 ); - public BinaryWritableHandle( WritableByteChannel channel, Closeable closeable ) + protected BinaryWritableHandle( WritableByteChannel writer, SeekableByteChannel seekable, Closeable closeable ) { super( closeable ); - m_writer = channel; - m_seekable = asSeekable( channel ); + this.writer = writer; + this.seekable = seekable; } - public BinaryWritableHandle( WritableByteChannel channel ) + public static BinaryWritableHandle of( WritableByteChannel channel, Closeable closeable ) { - this( channel, channel ); + SeekableByteChannel seekable = asSeekable( channel ); + return seekable == null ? new BinaryWritableHandle( channel, null, closeable ) : new Seekable( seekable, closeable ); } - @Nonnull - @Override - public String[] getMethodNames() + public static BinaryWritableHandle of( WritableByteChannel channel ) { - return m_seekable == null ? METHOD_NAMES : METHOD_SEEK_NAMES; + return of( channel, channel ); } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final void write( IArguments arguments ) throws LuaException { - switch( method ) + checkOpen(); + try { - case 0: // write - checkOpen(); - try - { - if( args.length > 0 && args[0] instanceof Number ) - { - int number = ((Number) args[0]).intValue(); - single.clear(); - single.put( (byte) number ); - single.flip(); + Object arg = arguments.get( 0 ); + if( arg instanceof Number ) + { + int number = ((Number) arg).intValue(); + single.clear(); + single.put( (byte) number ); + single.flip(); - m_writer.write( single ); - } - else if( args.length > 0 && args[0] instanceof String ) - { - String value = (String) args[0]; - m_writer.write( ByteBuffer.wrap( StringUtil.encodeString( value ) ) ); - } - else - { - throw ArgumentHelper.badArgumentOf( 0, "string or number", args.length > 0 ? args[0] : null ); - } - return null; - } - catch( IOException e ) - { - throw new LuaException( e.getMessage() ); - } - case 1: // flush - checkOpen(); - try - { - // Technically this is not needed - if( m_writer instanceof FileChannel ) ((FileChannel) m_writer).force( false ); + writer.write( single ); + } + else if( arg instanceof String ) + { + writer.write( arguments.getBytes( 0 ) ); + } + else + { + throw LuaValues.badArgumentOf( 0, "string or number", arg ); + } + } + catch( IOException e ) + { + throw new LuaException( e.getMessage() ); + } + } - return null; - } - catch( IOException e ) - { - return null; - } - case 2: // close - checkOpen(); - close(); - return null; - case 3: // seek - checkOpen(); - return handleSeek( m_seekable, args ); - default: - return null; + @LuaFunction + public final void flush() throws LuaException + { + checkOpen(); + try + { + // Technically this is not needed + if( writer instanceof FileChannel ) ((FileChannel) writer).force( false ); + } + catch( IOException ignored ) + { + } + } + + public static class Seekable extends BinaryWritableHandle + { + public Seekable( SeekableByteChannel seekable, Closeable closeable ) + { + super( seekable, seekable, closeable ); + } + + @LuaFunction + public final Object[] seek( IArguments args ) throws LuaException + { + checkOpen(); + return handleSeek( seekable, args ); } } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index af714dbdc..0a935fc22 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.core.apis.handles; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import javax.annotation.Nonnull; import java.io.BufferedReader; @@ -18,20 +18,18 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; - -import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; -import static dan200.computercraft.api.lua.ArgumentHelper.optInt; +import java.util.Optional; public class EncodedReadableHandle extends HandleGeneric { private static final int BUFFER_SIZE = 8192; - private BufferedReader m_reader; + private final BufferedReader reader; public EncodedReadableHandle( @Nonnull BufferedReader reader, @Nonnull Closeable closable ) { super( closable ); - m_reader = reader; + this.reader = reader; } public EncodedReadableHandle( @Nonnull BufferedReader reader ) @@ -39,123 +37,107 @@ public class EncodedReadableHandle extends HandleGeneric this( reader, reader ); } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final Object[] readLine( Optional withTrailingArg ) throws LuaException { - return new String[] { - "readLine", - "readAll", - "read", - "close", - }; + checkOpen(); + boolean withTrailing = withTrailingArg.orElse( false ); + try + { + String line = reader.readLine(); + if( line != null ) + { + // While this is technically inaccurate, it's better than nothing + if( withTrailing ) line += "\n"; + return new Object[] { line }; + } + else + { + return null; + } + } + catch( IOException e ) + { + return null; + } } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final Object[] readAll() throws LuaException { - switch( method ) + checkOpen(); + try { - case 0: // readLine + StringBuilder result = new StringBuilder(); + String line = reader.readLine(); + while( line != null ) { - checkOpen(); - boolean withTrailing = optBoolean( args, 0, false ); - try + result.append( line ); + line = reader.readLine(); + if( line != null ) { - String line = m_reader.readLine(); - if( line != null ) - { - // While this is technically inaccurate, it's better than nothing - if( withTrailing ) line += "\n"; - return new Object[] { line }; - } - else - { - return null; - } - } - catch( IOException e ) - { - return null; + result.append( "\n" ); } } - case 1: // readAll - checkOpen(); - try + return new Object[] { result.toString() }; + } + catch( IOException e ) + { + return null; + } + } + + @LuaFunction + public final Object[] read( Optional countA ) throws LuaException + { + checkOpen(); + try + { + int count = countA.orElse( 1 ); + if( count < 0 ) + { + // Whilst this may seem absurd to allow reading 0 characters, PUC Lua it so + // it seems best to remain somewhat consistent. + throw new LuaException( "Cannot read a negative number of characters" ); + } + else if( count <= BUFFER_SIZE ) + { + // If we've got a small count, then allocate that and read it. + char[] chars = new char[count]; + int read = reader.read( chars ); + + return read < 0 ? null : new Object[] { new String( chars, 0, read ) }; + } + else + { + // If we've got a large count, read in bunches of 8192. + char[] buffer = new char[BUFFER_SIZE]; + + // Read the initial set of characters, failing if none are read. + int read = reader.read( buffer, 0, Math.min( buffer.length, count ) ); + if( read < 0 ) return null; + + StringBuilder out = new StringBuilder( read ); + int totalRead = read; + out.append( buffer, 0, read ); + + // Otherwise read until we either reach the limit or we no longer consume + // the full buffer. + while( read >= BUFFER_SIZE && totalRead < count ) { - StringBuilder result = new StringBuilder(); - String line = m_reader.readLine(); - while( line != null ) - { - result.append( line ); - line = m_reader.readLine(); - if( line != null ) - { - result.append( "\n" ); - } - } - return new Object[] { result.toString() }; + read = reader.read( buffer, 0, Math.min( BUFFER_SIZE, count - totalRead ) ); + if( read < 0 ) break; + + totalRead += read; + out.append( buffer, 0, read ); } - catch( IOException e ) - { - return null; - } - case 2: // read - checkOpen(); - try - { - int count = optInt( args, 0, 1 ); - if( count < 0 ) - { - // Whilst this may seem absurd to allow reading 0 characters, PUC Lua it so - // it seems best to remain somewhat consistent. - throw new LuaException( "Cannot read a negative number of characters" ); - } - else if( count <= BUFFER_SIZE ) - { - // If we've got a small count, then allocate that and read it. - char[] chars = new char[count]; - int read = m_reader.read( chars ); - return read < 0 ? null : new Object[] { new String( chars, 0, read ) }; - } - else - { - // If we've got a large count, read in bunches of 8192. - char[] buffer = new char[BUFFER_SIZE]; - - // Read the initial set of characters, failing if none are read. - int read = m_reader.read( buffer, 0, Math.min( buffer.length, count ) ); - if( read < 0 ) return null; - - StringBuilder out = new StringBuilder( read ); - int totalRead = read; - out.append( buffer, 0, read ); - - // Otherwise read until we either reach the limit or we no longer consume - // the full buffer. - while( read >= BUFFER_SIZE && totalRead < count ) - { - read = m_reader.read( buffer, 0, Math.min( BUFFER_SIZE, count - totalRead ) ); - if( read < 0 ) break; - - totalRead += read; - out.append( buffer, 0, read ); - } - - return new Object[] { out.toString() }; - } - } - catch( IOException e ) - { - return null; - } - case 3: // close - checkOpen(); - close(); - return null; - default: - return null; + return new Object[] { out.toString() }; + } + } + catch( IOException e ) + { + return null; } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java index c9cfb5ba7..61bfe152b 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java @@ -5,8 +5,10 @@ */ package dan200.computercraft.core.apis.handles; -import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.shared.util.StringUtil; import javax.annotation.Nonnull; import java.io.BufferedWriter; @@ -21,85 +23,57 @@ import java.nio.charset.StandardCharsets; public class EncodedWritableHandle extends HandleGeneric { - private BufferedWriter m_writer; + private final BufferedWriter writer; public EncodedWritableHandle( @Nonnull BufferedWriter writer, @Nonnull Closeable closable ) { super( closable ); - m_writer = writer; + this.writer = writer; } - public EncodedWritableHandle( @Nonnull BufferedWriter writer ) + @LuaFunction + public final void write( IArguments args ) throws LuaException { - this( writer, writer ); - } - - @Nonnull - @Override - public String[] getMethodNames() - { - return new String[] { - "write", - "writeLine", - "flush", - "close", - }; - } - - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException - { - switch( method ) + checkOpen(); + String text = StringUtil.toString( args.get( 0 ) ); + try { - case 0: // write - { - checkOpen(); - String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; - try - { - m_writer.write( text, 0, text.length() ); - return null; - } - catch( IOException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 1: // writeLine - { - checkOpen(); - String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; - try - { - m_writer.write( text, 0, text.length() ); - m_writer.newLine(); - return null; - } - catch( IOException e ) - { - throw new LuaException( e.getMessage() ); - } - } - case 2: // flush - checkOpen(); - try - { - m_writer.flush(); - return null; - } - catch( IOException e ) - { - return null; - } - case 3: // close - checkOpen(); - close(); - return null; - default: - return null; + writer.write( text, 0, text.length() ); + } + catch( IOException e ) + { + throw new LuaException( e.getMessage() ); } } + @LuaFunction + public final void writeLine( IArguments args ) throws LuaException + { + checkOpen(); + String text = StringUtil.toString( args.get( 0 ) ); + try + { + writer.write( text, 0, text.length() ); + writer.newLine(); + } + catch( IOException e ) + { + throw new LuaException( e.getMessage() ); + } + } + + @LuaFunction + public final void flush() throws LuaException + { + checkOpen(); + try + { + writer.flush(); + } + catch( IOException ignored ) + { + } + } public static BufferedWriter openUtf8( WritableByteChannel channel ) { diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index 2ebad4202..35b5fd883 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -5,8 +5,9 @@ */ package dan200.computercraft.core.apis.handles; -import dan200.computercraft.api.lua.ILuaObject; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.shared.util.IoUtil; import javax.annotation.Nonnull; @@ -15,36 +16,41 @@ import java.io.IOException; import java.nio.channels.Channel; import java.nio.channels.SeekableByteChannel; -import static dan200.computercraft.api.lua.ArgumentHelper.optLong; -import static dan200.computercraft.api.lua.ArgumentHelper.optString; - -public abstract class HandleGeneric implements ILuaObject +public abstract class HandleGeneric { - private Closeable m_closable; - private boolean m_open = true; + private Closeable closable; + private boolean open = true; protected HandleGeneric( @Nonnull Closeable closable ) { - m_closable = closable; + this.closable = closable; } protected void checkOpen() throws LuaException { - if( !m_open ) throw new LuaException( "attempt to use a closed file" ); + if( !open ) throw new LuaException( "attempt to use a closed file" ); } protected final void close() { - m_open = false; + open = false; - Closeable closeable = m_closable; + Closeable closeable = closable; if( closeable != null ) { IoUtil.closeQuietly( closeable ); - m_closable = null; + closable = null; } } + @LuaFunction( "close" ) + public final void doClose() throws LuaException + { + checkOpen(); + close(); + } + + /** * Shared implementation for various file handle types. * @@ -54,12 +60,12 @@ public abstract class HandleGeneric implements ILuaObject * @throws LuaException If the arguments were invalid * @see {@code file:seek} in the Lua manual. */ - protected static Object[] handleSeek( SeekableByteChannel channel, Object[] args ) throws LuaException + protected static Object[] handleSeek( SeekableByteChannel channel, IArguments args ) throws LuaException { + String whence = args.optString( 0, "cur" ); + long offset = args.optLong( 1, 0 ); try { - String whence = optString( args, 0, "cur" ); - long offset = optLong( args, 1, 0 ); switch( whence ) { case "set": diff --git a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java index ab4b56de2..f92d5926e 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java +++ b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java @@ -47,11 +47,11 @@ public class CheckUrl extends Resource try { NetworkUtils.getAddress( host, 80, false ); - if( tryClose() ) environment.queueEvent( EVENT, new Object[] { address, true } ); + if( tryClose() ) environment.queueEvent( EVENT, address, true ); } catch( HTTPRequestException e ) { - if( tryClose() ) environment.queueEvent( EVENT, new Object[] { address, false, e.getMessage() } ); + if( tryClose() ) environment.queueEvent( EVENT, address, false, e.getMessage() ); } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index b15ce77d5..3af3bacc3 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -6,7 +6,6 @@ package dan200.computercraft.core.apis.http.request; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.ILuaObject; import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.apis.http.HTTPRequestException; import dan200.computercraft.core.apis.http.NetworkUtils; @@ -201,7 +200,7 @@ public class HttpRequest extends Resource void failure( String message ) { - if( tryClose() ) environment.queueEvent( FAILURE_EVENT, new Object[] { address, message } ); + if( tryClose() ) environment.queueEvent( FAILURE_EVENT, address, message ); } void failure( Throwable cause ) @@ -227,14 +226,14 @@ public class HttpRequest extends Resource failure( message ); } - void failure( String message, ILuaObject object ) + void failure( String message, HttpResponseHandle object ) { - if( tryClose() ) environment.queueEvent( FAILURE_EVENT, new Object[] { address, message, object } ); + if( tryClose() ) environment.queueEvent( FAILURE_EVENT, address, message, object ); } - void success( ILuaObject object ) + void success( HttpResponseHandle object ) { - if( tryClose() ) environment.queueEvent( SUCCESS_EVENT, new Object[] { address, object } ); + if( tryClose() ) environment.queueEvent( SUCCESS_EVENT, address, object ); } @Override diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index 866d0d138..d742ec538 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -6,10 +6,10 @@ package dan200.computercraft.core.apis.http.request; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.ILuaObject; import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.core.apis.handles.BinaryReadableHandle; import dan200.computercraft.core.apis.handles.EncodedReadableHandle; +import dan200.computercraft.core.apis.handles.HandleGeneric; import dan200.computercraft.core.apis.http.HTTPRequestException; import dan200.computercraft.core.apis.http.NetworkUtils; import dan200.computercraft.core.tracking.TrackingField; @@ -209,10 +209,10 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler= 200 && status.code() < 400 ) { diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java index bfface4eb..8000a6c1e 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java @@ -5,62 +5,48 @@ */ package dan200.computercraft.core.apis.http.request; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.ILuaObject; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.core.apis.handles.HandleGeneric; +import dan200.computercraft.core.asm.ObjectSource; import javax.annotation.Nonnull; -import java.util.Arrays; +import java.util.Collections; import java.util.Map; /** * Wraps a {@link dan200.computercraft.core.apis.handles.HandleGeneric} and provides additional methods for * getting the response code and headers. */ -public class HttpResponseHandle implements ILuaObject +public class HttpResponseHandle implements ObjectSource { - private final String[] newMethods; - private final int methodOffset; - private final ILuaObject reader; + private final Object reader; private final int responseCode; private final String responseStatus; private final Map responseHeaders; - public HttpResponseHandle( @Nonnull ILuaObject reader, int responseCode, String responseStatus, @Nonnull Map responseHeaders ) + public HttpResponseHandle( @Nonnull HandleGeneric reader, int responseCode, String responseStatus, @Nonnull Map responseHeaders ) { this.reader = reader; this.responseCode = responseCode; this.responseStatus = responseStatus; this.responseHeaders = responseHeaders; - - String[] oldMethods = reader.getMethodNames(); - final int methodOffset = this.methodOffset = oldMethods.length; - - final String[] newMethods = this.newMethods = Arrays.copyOf( oldMethods, oldMethods.length + 2 ); - newMethods[methodOffset + 0] = "getResponseCode"; - newMethods[methodOffset + 1] = "getResponseHeaders"; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final Object[] getResponseCode() { - return newMethods; + return new Object[] { responseCode, responseStatus }; + } + + @LuaFunction + public final Map getResponseHeaders() + { + return responseHeaders; } @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException + public Iterable getExtra() { - if( method < methodOffset ) return reader.callMethod( context, method, args ); - - switch( method - methodOffset ) - { - case 0: // getResponseCode - return new Object[] { responseCode, responseStatus }; - case 1: // getResponseHeaders - return new Object[] { responseHeaders }; - default: - return null; - } + return Collections.singletonList( reader ); } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index 5e1562d04..fe591f592 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -187,7 +187,7 @@ public class Websocket extends Resource if( isClosed() ) return; WebsocketHandle handle = new WebsocketHandle( this, channel ); - environment().queueEvent( SUCCESS_EVENT, new Object[] { address, handle } ); + environment().queueEvent( SUCCESS_EVENT, address, handle ); websocketHandle = createOwnerReference( handle ); checkClosed(); @@ -195,18 +195,16 @@ public class Websocket extends Resource void failure( String message ) { - if( tryClose() ) environment.queueEvent( FAILURE_EVENT, new Object[] { address, message } ); + if( tryClose() ) environment.queueEvent( FAILURE_EVENT, address, message ); } void close( int status, String reason ) { if( tryClose() ) { - environment.queueEvent( CLOSE_EVENT, new Object[] { - address, + environment.queueEvent( CLOSE_EVENT, address, Strings.isNullOrEmpty( reason ) ? null : reason, - status < 0 ? null : status, - } ); + status < 0 ? null : status ); } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index 8433d30c3..78bb17bdf 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -7,10 +7,7 @@ package dan200.computercraft.core.apis.http.websocket; import com.google.common.base.Objects; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.ArgumentHelper; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.ILuaObject; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.*; import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.util.StringUtil; import io.netty.buffer.Unpooled; @@ -19,16 +16,16 @@ import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.Closeable; import java.util.Arrays; +import java.util.Optional; -import static dan200.computercraft.api.lua.ArgumentHelper.optBoolean; +import static dan200.computercraft.api.lua.LuaValues.checkFinite; import static dan200.computercraft.core.apis.IAPIEnvironment.TIMER_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT; -public class WebsocketHandle implements ILuaObject, Closeable +public class WebsocketHandle implements Closeable { private final Websocket websocket; private boolean closed = false; @@ -41,87 +38,45 @@ public class WebsocketHandle implements ILuaObject, Closeable this.channel = channel; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final MethodResult result( Optional timeout ) throws LuaException { - return new String[] { "receive", "send", "close" }; + checkOpen(); + int timeoutId = timeout.isPresent() + ? websocket.environment().startTimer( Math.round( checkFinite( 0, timeout.get() ) / 0.05 ) ) + : -1; + + return new ReceiveCallback( timeoutId ).pull; } - @Nullable - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction + public final void send( IArguments args ) throws LuaException { - switch( method ) + checkOpen(); + + String text = StringUtil.toString( args.get( 0 ) ); + if( ComputerCraft.httpMaxWebsocketMessage != 0 && text.length() > ComputerCraft.httpMaxWebsocketMessage ) { - case 0: // receive - { - checkOpen(); - int timeoutId; - if( arguments.length <= 0 || arguments[0] == null ) - { - // We do this rather odd argument validation to ensure we can tell the difference between a - // negative timeout and an absent one. - timeoutId = -1; - } - else - { - double timeout = ArgumentHelper.getFiniteDouble( arguments, 0 ); - timeoutId = websocket.environment().startTimer( Math.round( timeout / 0.05 ) ); - } - - while( true ) - { - Object[] event = context.pullEvent( null ); - if( event.length >= 3 && Objects.equal( event[0], MESSAGE_EVENT ) && Objects.equal( event[1], websocket.address() ) ) - { - return Arrays.copyOfRange( event, 2, event.length ); - } - else if( event.length >= 2 && Objects.equal( event[0], CLOSE_EVENT ) && Objects.equal( event[1], websocket.address() ) && closed ) - { - // If the socket is closed abort. - return null; - } - else if( event.length >= 2 && timeoutId != -1 && Objects.equal( event[0], TIMER_EVENT ) - && event[1] instanceof Number && ((Number) event[1]).intValue() == timeoutId ) - { - // If we received a matching timer event then abort. - return null; - } - } - } - - case 1: // send - { - checkOpen(); - - String text = arguments.length > 0 && arguments[0] != null ? arguments[0].toString() : ""; - if( ComputerCraft.httpMaxWebsocketMessage != 0 && text.length() > ComputerCraft.httpMaxWebsocketMessage ) - { - throw new LuaException( "Message is too large" ); - } - - boolean binary = optBoolean( arguments, 1, false ); - websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_OUTGOING, text.length() ); - - Channel channel = this.channel; - if( channel != null ) - { - channel.writeAndFlush( binary - ? new BinaryWebSocketFrame( Unpooled.wrappedBuffer( StringUtil.encodeString( text ) ) ) - : new TextWebSocketFrame( text ) ); - } - - return null; - } - - case 2: // close - close(); - websocket.close(); - return null; - default: - return null; + throw new LuaException( "Message is too large" ); } + + boolean binary = args.optBoolean( 1, false ); + websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_OUTGOING, text.length() ); + + Channel channel = this.channel; + if( channel != null ) + { + channel.writeAndFlush( binary + ? new BinaryWebSocketFrame( Unpooled.wrappedBuffer( LuaValues.encode( text ) ) ) + : new TextWebSocketFrame( text ) ); + } + } + + @LuaFunction( "close" ) + public final void doClose() + { + close(); + websocket.close(); } private void checkOpen() throws LuaException @@ -141,4 +96,38 @@ public class WebsocketHandle implements ILuaObject, Closeable this.channel = null; } } + + private final class ReceiveCallback implements ILuaCallback + { + final MethodResult pull = MethodResult.pullEvent( null, this ); + private final int timeoutId; + + ReceiveCallback( int timeoutId ) + { + this.timeoutId = timeoutId; + } + + @Nonnull + @Override + public MethodResult resume( Object[] event ) + { + if( event.length >= 3 && Objects.equal( event[0], MESSAGE_EVENT ) && Objects.equal( event[1], websocket.address() ) ) + { + return MethodResult.of( Arrays.copyOfRange( event, 2, event.length ) ); + } + else if( event.length >= 2 && Objects.equal( event[0], CLOSE_EVENT ) && Objects.equal( event[1], websocket.address() ) && closed ) + { + // If the socket is closed abort. + return MethodResult.of(); + } + else if( event.length >= 2 && timeoutId != -1 && Objects.equal( event[0], TIMER_EVENT ) + && event[1] instanceof Number && ((Number) event[1]).intValue() == timeoutId ) + { + // If we received a matching timer event then abort. + return MethodResult.of(); + } + + return pull; + } + } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java index 70a2e77a6..c3e69d7b9 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java @@ -68,14 +68,14 @@ public class WebsocketHandler extends SimpleChannelInboundHandler String data = ((TextWebSocketFrame) frame).text(); websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, data.length() ); - websocket.environment().queueEvent( MESSAGE_EVENT, new Object[] { websocket.address(), data, false } ); + websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), data, false ); } else if( frame instanceof BinaryWebSocketFrame ) { byte[] converted = NetworkUtils.toBytes( frame.content() ); websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length ); - websocket.environment().queueEvent( MESSAGE_EVENT, new Object[] { websocket.address(), converted, true } ); + websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), converted, true ); } else if( frame instanceof CloseWebSocketFrame ) { diff --git a/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java b/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java new file mode 100644 index 000000000..009a8840e --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java @@ -0,0 +1,24 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import java.security.ProtectionDomain; + +final class DeclaringClassLoader extends ClassLoader +{ + static final DeclaringClassLoader INSTANCE = new DeclaringClassLoader(); + + private DeclaringClassLoader() + { + super( DeclaringClassLoader.class.getClassLoader() ); + } + + Class define( String name, byte[] bytes, ProtectionDomain protectionDomain ) throws ClassFormatError + { + return defineClass( name, bytes, 0, bytes.length, protectionDomain ); + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java new file mode 100644 index 000000000..801969d0c --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -0,0 +1,320 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.primitives.Primitives; +import com.google.common.reflect.TypeToken; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.MethodResult; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; + +import static org.objectweb.asm.Opcodes.*; + +public class Generator +{ + private static final AtomicInteger METHOD_ID = new AtomicInteger(); + + private static final String METHOD_NAME = "apply"; + private static final String[] EXCEPTIONS = new String[] { Type.getInternalName( LuaException.class ) }; + + private static final String INTERNAL_METHOD_RESULT = Type.getInternalName( MethodResult.class ); + private static final String DESC_METHOD_RESULT = Type.getDescriptor( MethodResult.class ); + + private static final String INTERNAL_ARGUMENTS = Type.getInternalName( IArguments.class ); + private static final String DESC_ARGUMENTS = Type.getDescriptor( IArguments.class ); + + private final Class base; + private final List> context; + + private final String[] interfaces; + private final String methodDesc; + + private final Function wrap; + + private final LoadingCache, List>> classCache = CacheBuilder + .newBuilder() + .build( CacheLoader.from( this::build ) ); + + private final LoadingCache> methodCache = CacheBuilder + .newBuilder() + .build( CacheLoader.from( this::build ) ); + + Generator( Class base, List> context, Function wrap ) + { + this.base = base; + this.context = context; + this.interfaces = new String[] { Type.getInternalName( base ) }; + this.wrap = wrap; + + StringBuilder methodDesc = new StringBuilder().append( "(Ljava/lang/Object;" ); + for( Class klass : context ) methodDesc.append( Type.getDescriptor( klass ) ); + methodDesc.append( DESC_ARGUMENTS ).append( ")" ).append( DESC_METHOD_RESULT ); + this.methodDesc = methodDesc.toString(); + } + + @Nonnull + public List> getMethods( @Nonnull Class klass ) + { + try + { + return classCache.get( klass ); + } + catch( ExecutionException e ) + { + ComputerCraft.log.error( "Error getting methods for {}.", klass.getName(), e.getCause() ); + return Collections.emptyList(); + } + } + + @Nonnull + private List> build( Class klass ) + { + ArrayList> methods = null; + for( Method method : klass.getMethods() ) + { + LuaFunction annotation = method.getAnnotation( LuaFunction.class ); + if( annotation == null ) continue; + + T instance = methodCache.getUnchecked( method ).orElse( null ); + if( instance == null ) continue; + + if( methods == null ) methods = new ArrayList<>(); + + if( annotation.mainThread() ) instance = wrap.apply( instance ); + + String[] names = annotation.value(); + boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); + if( names.length == 0 ) + { + methods.add( new NamedMethod<>( method.getName(), instance, isSimple ) ); + } + else + { + for( String name : names ) + { + methods.add( new NamedMethod<>( name, instance, isSimple ) ); + } + } + } + + if( methods == null ) return Collections.emptyList(); + methods.trimToSize(); + return Collections.unmodifiableList( methods ); + } + + @Nonnull + private Optional build( Method method ) + { + String name = method.getDeclaringClass().getName() + "." + method.getName(); + int modifiers = method.getModifiers(); + if( !Modifier.isFinal( modifiers ) ) + { + ComputerCraft.log.warn( "Lua Method {} should be final.", name ); + } + + if( Modifier.isStatic( modifiers ) || !Modifier.isPublic( modifiers ) ) + { + ComputerCraft.log.error( "Lua Method {} should be a public instance method.", name ); + return Optional.empty(); + } + + if( !Modifier.isPublic( method.getDeclaringClass().getModifiers() ) ) + { + ComputerCraft.log.error( "Lua Method {} should be on a public class.", name ); + return Optional.empty(); + } + + ComputerCraft.log.debug( "Generating method wrapper for {}.", name ); + + Class[] exceptions = method.getExceptionTypes(); + for( Class exception : exceptions ) + { + if( exception != LuaException.class ) + { + ComputerCraft.log.error( "Lua Method {} cannot throw {}.", name, exception.getName() ); + return Optional.empty(); + } + } + + try + { + String className = method.getDeclaringClass().getName() + "$cc$" + method.getName() + METHOD_ID.getAndIncrement(); + byte[] bytes = generate( className, method ); + if( bytes == null ) return Optional.empty(); + + Class klass = DeclaringClassLoader.INSTANCE.define( className, bytes, method.getDeclaringClass().getProtectionDomain() ); + return Optional.of( klass.asSubclass( base ).newInstance() ); + } + catch( InstantiationException | IllegalAccessException | ClassFormatError | RuntimeException e ) + { + ComputerCraft.log.error( "Error generating wrapper for {}.", name, e ); + return Optional.empty(); + } + + } + + @Nullable + private byte[] generate( String className, Method method ) + { + String internalName = className.replace( ".", "/" ); + + // Construct a public final class which extends Object and implements MethodInstance.Delegate + ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS ); + cw.visit( V1_8, ACC_PUBLIC | ACC_FINAL, internalName, null, "java/lang/Object", interfaces ); + cw.visitSource( "CC generated method", null ); + + { // Constructor just invokes super. + MethodVisitor mw = cw.visitMethod( ACC_PUBLIC, "", "()V", null, null ); + mw.visitCode(); + mw.visitVarInsn( ALOAD, 0 ); + mw.visitMethodInsn( INVOKESPECIAL, "java/lang/Object", "", "()V", false ); + mw.visitInsn( RETURN ); + mw.visitMaxs( 0, 0 ); + mw.visitEnd(); + } + + { + MethodVisitor mw = cw.visitMethod( ACC_PUBLIC, METHOD_NAME, methodDesc, null, EXCEPTIONS ); + mw.visitCode(); + mw.visitVarInsn( ALOAD, 1 ); + mw.visitTypeInsn( CHECKCAST, Type.getInternalName( method.getDeclaringClass() ) ); + + int argIndex = 0; + for( java.lang.reflect.Type genericArg : method.getGenericParameterTypes() ) + { + Boolean loadedArg = loadArg( mw, method, genericArg, argIndex ); + if( loadedArg == null ) return null; + if( loadedArg ) argIndex++; + } + + mw.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( method.getDeclaringClass() ), method.getName(), + Type.getMethodDescriptor( method ), false ); + + // We allow a reasonable amount of flexibility on the return value's type. Alongside the obvious MethodResult, + // we convert basic types into an immediate result. + Class ret = method.getReturnType(); + if( ret != MethodResult.class ) + { + if( ret == void.class ) + { + mw.visitMethodInsn( INVOKESTATIC, INTERNAL_METHOD_RESULT, "of", "()" + DESC_METHOD_RESULT, false ); + } + else if( ret.isPrimitive() ) + { + Class boxed = Primitives.wrap( ret ); + mw.visitMethodInsn( INVOKESTATIC, Type.getInternalName( boxed ), "valueOf", "(" + Type.getDescriptor( ret ) + ")" + Type.getDescriptor( boxed ), false ); + mw.visitMethodInsn( INVOKESTATIC, INTERNAL_METHOD_RESULT, "of", "(Ljava/lang/Object;)" + DESC_METHOD_RESULT, false ); + } + else if( ret == Object[].class ) + { + mw.visitMethodInsn( INVOKESTATIC, INTERNAL_METHOD_RESULT, "of", "([Ljava/lang/Object;)" + DESC_METHOD_RESULT, false ); + } + else + { + mw.visitMethodInsn( INVOKESTATIC, INTERNAL_METHOD_RESULT, "of", "(Ljava/lang/Object;)" + DESC_METHOD_RESULT, false ); + } + } + + mw.visitInsn( ARETURN ); + + mw.visitMaxs( 0, 0 ); + mw.visitEnd(); + } + + cw.visitEnd(); + + return cw.toByteArray(); + } + + private Boolean loadArg( MethodVisitor mw, Method method, java.lang.reflect.Type genericArg, int argIndex ) + { + Class arg = Reflect.getRawType( method, genericArg, true ); + if( arg == null ) return null; + + if( arg == IArguments.class ) + { + mw.visitVarInsn( ALOAD, 2 + context.size() ); + return false; + } + + int idx = context.indexOf( arg ); + if( idx >= 0 ) + { + mw.visitVarInsn( ALOAD, 2 + idx ); + return false; + } + + if( arg == Optional.class ) + { + Class klass = Reflect.getRawType( method, TypeToken.of( genericArg ).resolveType( Reflect.OPTIONAL_IN ).getType(), false ); + if( klass == null ) return null; + + if( Enum.class.isAssignableFrom( klass ) && klass != Enum.class ) + { + mw.visitVarInsn( ALOAD, 2 + context.size() ); + Reflect.loadInt( mw, argIndex ); + mw.visitLdcInsn( Type.getType( klass ) ); + mw.visitMethodInsn( INVOKEINTERFACE, INTERNAL_ARGUMENTS, "optEnum", "(ILjava/lang/Class;)Ljava/util/Optional;", true ); + return true; + } + + String name = Reflect.getLuaName( Primitives.unwrap( klass ) ); + if( name != null ) + { + mw.visitVarInsn( ALOAD, 2 + context.size() ); + Reflect.loadInt( mw, argIndex ); + mw.visitMethodInsn( INVOKEINTERFACE, INTERNAL_ARGUMENTS, "opt" + name, "(I)Ljava/util/Optional;", true ); + return true; + } + } + + if( Enum.class.isAssignableFrom( arg ) && arg != Enum.class ) + { + mw.visitVarInsn( ALOAD, 2 + context.size() ); + Reflect.loadInt( mw, argIndex ); + mw.visitLdcInsn( Type.getType( arg ) ); + mw.visitMethodInsn( INVOKEINTERFACE, INTERNAL_ARGUMENTS, "getEnum", "(ILjava/lang/Class;)Ljava/lang/Enum;", true ); + mw.visitTypeInsn( CHECKCAST, Type.getInternalName( arg ) ); + return true; + } + + String name = arg == Object.class ? "" : Reflect.getLuaName( arg ); + if( name != null ) + { + if( Reflect.getRawType( method, genericArg, false ) == null ) return null; + + mw.visitVarInsn( ALOAD, 2 + context.size() ); + Reflect.loadInt( mw, argIndex ); + mw.visitMethodInsn( INVOKEINTERFACE, INTERNAL_ARGUMENTS, "get" + name, "(I)" + Type.getDescriptor( arg ), true ); + return true; + } + + ComputerCraft.log.error( "Unknown parameter type {} for method {}.{}.", + arg.getName(), method.getDeclaringClass().getName(), method.getName() ); + return null; + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/IntCache.java b/src/main/java/dan200/computercraft/core/asm/IntCache.java new file mode 100644 index 000000000..d50f54b2a --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/IntCache.java @@ -0,0 +1,41 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import java.util.Arrays; +import java.util.function.IntFunction; + +public final class IntCache +{ + private final IntFunction factory; + private volatile Object[] cache = new Object[16]; + + IntCache( IntFunction factory ) + { + this.factory = factory; + } + + @SuppressWarnings( "unchecked" ) + public T get( int index ) + { + if( index < 0 ) throw new IllegalArgumentException( "index < 0" ); + + if( index <= cache.length ) + { + T current = (T) cache[index]; + if( current != null ) return current; + } + + synchronized( this ) + { + if( index > cache.length ) cache = Arrays.copyOf( cache, Math.max( cache.length * 2, index ) ); + T current = (T) cache[index]; + if( current == null ) cache[index] = current = factory.apply( index ); + return current; + } + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java new file mode 100644 index 000000000..35ad33b76 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java @@ -0,0 +1,30 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.*; + +import javax.annotation.Nonnull; +import java.util.Collections; + +public interface LuaMethod +{ + Generator GENERATOR = new Generator<>( LuaMethod.class, Collections.singletonList( ILuaContext.class ), + m -> ( target, context, args ) -> { + long id = context.issueMainThreadTask( () -> TaskCallback.checkUnwrap( m.apply( target, context, args ) ) ); + return new TaskCallback( id ).pull; + } ); + + IntCache DYNAMIC = new IntCache<>( + method -> ( instance, context, args ) -> ((IDynamicLuaObject) instance).callMethod( context, method, args ) + ); + + String[] EMPTY_METHODS = new String[0]; + + @Nonnull + MethodResult apply( @Nonnull Object target, @Nonnull ILuaContext context, @Nonnull IArguments args ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java new file mode 100644 index 000000000..d7525fc7f --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java @@ -0,0 +1,40 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import javax.annotation.Nonnull; + +public class NamedMethod +{ + private final String name; + private final T method; + private final boolean nonYielding; + + NamedMethod( String name, T method, boolean nonYielding ) + { + this.name = name; + this.method = method; + this.nonYielding = nonYielding; + } + + @Nonnull + public String getName() + { + return name; + } + + @Nonnull + public T getMethod() + { + return method; + } + + public boolean nonYielding() + { + return nonYielding; + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/ObjectSource.java b/src/main/java/dan200/computercraft/core/asm/ObjectSource.java new file mode 100644 index 000000000..f05ac7070 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/ObjectSource.java @@ -0,0 +1,33 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import java.util.function.BiConsumer; + +/** + * A Lua object which exposes additional methods. + * + * This can be used to merge multiple objects together into one. Ideally this'd be part of the API, but I'm not entirely + * happy with the interface - something I'd like to think about first. + */ +public interface ObjectSource +{ + Iterable getExtra(); + + static void allMethods( Generator generator, Object object, BiConsumer> accept ) + { + for( NamedMethod method : generator.getMethods( object.getClass() ) ) accept.accept( object, method ); + + if( object instanceof ObjectSource ) + { + for( Object extra : ((ObjectSource) object).getExtra() ) + { + for( NamedMethod method : generator.getMethods( extra.getClass() ) ) accept.accept( extra, method ); + } + } + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java new file mode 100644 index 000000000..637cfb806 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java @@ -0,0 +1,33 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; + +import javax.annotation.Nonnull; +import java.util.Arrays; + +public interface PeripheralMethod +{ + Generator GENERATOR = new Generator<>( PeripheralMethod.class, Arrays.asList( ILuaContext.class, IComputerAccess.class ), + m -> ( target, context, computer, args ) -> { + long id = context.issueMainThreadTask( () -> TaskCallback.checkUnwrap( m.apply( target, context, computer, args ) ) ); + return new TaskCallback( id ).pull; + } ); + + IntCache DYNAMIC = new IntCache<>( + method -> ( instance, context, computer, args ) -> ((IDynamicPeripheral) instance).callMethod( computer, context, method, args ) + ); + + @Nonnull + MethodResult apply( @Nonnull Object target, @Nonnull ILuaContext context, @Nonnull IComputerAccess computer, @Nonnull IArguments args ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/core/asm/Reflect.java b/src/main/java/dan200/computercraft/core/asm/Reflect.java new file mode 100644 index 000000000..429402206 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/Reflect.java @@ -0,0 +1,95 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.ComputerCraft; +import org.objectweb.asm.MethodVisitor; + +import javax.annotation.Nullable; +import java.lang.reflect.*; +import java.nio.ByteBuffer; +import java.util.Map; +import java.util.Optional; + +import static org.objectweb.asm.Opcodes.ICONST_0; + +final class Reflect +{ + static final java.lang.reflect.Type OPTIONAL_IN = Optional.class.getTypeParameters()[0]; + + private Reflect() + { + } + + @Nullable + static String getLuaName( Class klass ) + { + if( klass.isPrimitive() ) + { + if( klass == int.class ) return "Int"; + if( klass == boolean.class ) return "Boolean"; + if( klass == double.class ) return "Double"; + if( klass == long.class ) return "Long"; + } + else + { + if( klass == Map.class ) return "Table"; + if( klass == String.class ) return "String"; + if( klass == ByteBuffer.class ) return "Bytes"; + } + + return null; + } + + @Nullable + static Class getRawType( Method method, Type root, boolean allowParameter ) + { + Type underlying = root; + while( true ) + { + if( underlying instanceof Class ) return (Class) underlying; + + if( underlying instanceof ParameterizedType ) + { + ParameterizedType type = (ParameterizedType) underlying; + if( !allowParameter ) + { + for( java.lang.reflect.Type arg : type.getActualTypeArguments() ) + { + if( arg instanceof WildcardType ) continue; + if( arg instanceof TypeVariable && ((TypeVariable) arg).getName().startsWith( "capture#" ) ) + { + continue; + } + + ComputerCraft.log.error( "Method {}.{} has generic type {} with non-wildcard argument {}.", method.getDeclaringClass(), method.getName(), root, arg ); + return null; + } + } + + // Continue to extract from this child + underlying = type.getRawType(); + continue; + } + + ComputerCraft.log.error( "Method {}.{} has unknown generic type {}.", method.getDeclaringClass(), method.getName(), root ); + return null; + } + } + + static void loadInt( MethodVisitor visitor, int value ) + { + if( value >= -1 && value <= 5 ) + { + visitor.visitInsn( ICONST_0 + value ); + } + else + { + visitor.visitLdcInsn( value ); + } + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java new file mode 100644 index 000000000..9ea4e67ad --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java @@ -0,0 +1,58 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.ILuaCallback; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.MethodResult; + +import javax.annotation.Nonnull; +import java.util.Arrays; + +class TaskCallback implements ILuaCallback +{ + final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); + private final long task; + + TaskCallback( long task ) + { + this.task = task; + } + + @Nonnull + @Override + public MethodResult resume( Object[] response ) throws LuaException + { + if( response.length < 3 || !(response[1] instanceof Number) || !(response[2] instanceof Boolean) ) + { + return pull; + } + + if( ((Number) response[1]).longValue() != task ) return pull; + + if( (Boolean) response[2] ) + { + // Extract the return values from the event and return them + return MethodResult.of( Arrays.copyOfRange( response, 3, response.length ) ); + } + else if( response.length >= 4 && response[3] instanceof String ) + { + // Extract the error message from the event and raise it + throw new LuaException( (String) response[3] ); + } + else + { + throw new LuaException( "error" ); + } + } + + public static Object[] checkUnwrap( MethodResult result ) + { + if( result.getCallback() != null ) throw new IllegalStateException( "Cannot return MethodResult currently" ); + return result.getResult(); + } +} diff --git a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java index 96be03c3e..693045dfe 100644 --- a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java +++ b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java @@ -6,11 +6,6 @@ package dan200.computercraft.core.computer; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * A wrapper for {@link ILuaAPI}s which cleans up after a {@link ComputerSystem} when the computer is shutdown. @@ -51,17 +46,8 @@ final class ApiWrapper implements ILuaAPI system.unmountAll(); } - @Nonnull - @Override - public String[] getMethodNames() + public ILuaAPI getDelegate() { - return delegate.getMethodNames(); - } - - @Nullable - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException - { - return delegate.callMethod( context, method, arguments ); + return delegate; } } diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index 55f02086d..8affb0f01 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -44,7 +44,7 @@ public class Computer // Additional state about the computer and its environment. private boolean m_blinking = false; private final Environment internalEnvironment = new Environment( this ); - private AtomicBoolean externalOutputChanged = new AtomicBoolean(); + private final AtomicBoolean externalOutputChanged = new AtomicBoolean(); private boolean startRequested; private int m_ticksSinceStart = -1; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index 811168b80..021c4b473 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -388,8 +388,8 @@ final class ComputerExecutor // Create the lua machine ILuaMachine machine = new CobaltLuaMachine( computer, timeout ); - // Add the APIs - for( ILuaAPI api : apis ) machine.addAPI( api ); + // Add the APIs. We unwrap them (yes, this is horrible) to get access to the underlying object. + for( ILuaAPI api : apis ) machine.addAPI( api instanceof ApiWrapper ? ((ApiWrapper) api).getDelegate() : api ); // Start the machine running the bios resource MachineResult result = machine.loadBios( biosStream ); diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index 819997c92..041973fef 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -111,7 +111,7 @@ public final class Environment implements IAPIEnvironment } @Override - public void queueEvent( String event, Object[] args ) + public void queueEvent( String event, Object... args ) { computer.queueEvent( event, args ); } @@ -226,7 +226,7 @@ public final class Environment implements IAPIEnvironment if( inputChanged ) { inputChanged = false; - queueEvent( "redstone", null ); + queueEvent( "redstone" ); } synchronized( timers ) @@ -241,7 +241,7 @@ public final class Environment implements IAPIEnvironment if( timer.ticksLeft <= 0 ) { // Queue the "timer" event - queueEvent( TIMER_EVENT, new Object[] { entry.getIntKey() } ); + queueEvent( TIMER_EVENT, entry.getIntKey() ); it.remove(); } } diff --git a/src/main/java/dan200/computercraft/core/lua/BasicFunction.java b/src/main/java/dan200/computercraft/core/lua/BasicFunction.java new file mode 100644 index 000000000..3c988f025 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/lua/BasicFunction.java @@ -0,0 +1,75 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.lua; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.core.asm.LuaMethod; +import org.squiddev.cobalt.LuaError; +import org.squiddev.cobalt.LuaState; +import org.squiddev.cobalt.Varargs; +import org.squiddev.cobalt.function.VarArgFunction; + +/** + * An "optimised" version of {@link ResultInterpreterFunction} which is guaranteed to never yield. + * + * As we never yield, we do not need to push a function to the stack, which removes a small amount of overhead. + */ +class BasicFunction extends VarArgFunction +{ + private final CobaltLuaMachine machine; + private final LuaMethod method; + private final Object instance; + private final ILuaContext context; + private final String name; + + BasicFunction( CobaltLuaMachine machine, LuaMethod method, Object instance, ILuaContext context, String name ) + { + this.machine = machine; + this.method = method; + this.instance = instance; + this.context = context; + this.name = name; + } + + @Override + public Varargs invoke( LuaState luaState, Varargs args ) throws LuaError + { + IArguments arguments = CobaltLuaMachine.toArguments( args ); + MethodResult results; + try + { + results = method.apply( instance, context, arguments ); + } + catch( LuaException e ) + { + throw wrap( e ); + } + catch( Throwable t ) + { + if( ComputerCraft.logPeripheralErrors ) + { + ComputerCraft.log.error( "Error calling " + name + " on " + instance, t ); + } + throw new LuaError( "Java Exception Thrown: " + t, 0 ); + } + + if( results.getCallback() != null ) + { + throw new IllegalStateException( "Cannot have a yielding non-yielding function" ); + } + return machine.toValues( results.getResult() ); + } + + public static LuaError wrap( LuaException exception ) + { + return exception.hasLevel() ? new LuaError( exception.getMessage() ) : new LuaError( exception.getMessage(), exception.getLevel() ); + } +} diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 8e5e88bb0..dc8291b21 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -7,6 +7,8 @@ package dan200.computercraft.core.lua; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.*; +import dan200.computercraft.core.asm.LuaMethod; +import dan200.computercraft.core.asm.ObjectSource; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.computer.TimeoutState; @@ -20,13 +22,13 @@ import org.squiddev.cobalt.debug.DebugFrame; import org.squiddev.cobalt.debug.DebugHandler; import org.squiddev.cobalt.debug.DebugState; import org.squiddev.cobalt.function.LuaFunction; -import org.squiddev.cobalt.function.VarArgFunction; import org.squiddev.cobalt.lib.*; import org.squiddev.cobalt.lib.platform.VoidResourceManipulator; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.InputStream; +import java.nio.ByteBuffer; import java.util.*; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -116,11 +118,14 @@ public class CobaltLuaMachine implements ILuaMachine { // Add the methods of an API to the global table LuaTable table = wrapLuaObject( api ); - String[] names = api.getNames(); - for( String name : names ) + if( table == null ) { - m_globals.rawset( name, table ); + ComputerCraft.log.warn( "API {} does not provide any methods", api ); + table = new LuaTable(); } + + String[] names = api.getNames(); + for( String name : names ) m_globals.rawset( name, table ); } @Override @@ -216,54 +221,38 @@ public class CobaltLuaMachine implements ILuaMachine m_globals = null; } - private LuaTable wrapLuaObject( ILuaObject object ) + @Nullable + private LuaTable wrapLuaObject( Object object ) { + String[] dynamicMethods = object instanceof IDynamicLuaObject + ? Objects.requireNonNull( ((IDynamicLuaObject) object).getMethodNames(), "Methods cannot be null" ) + : LuaMethod.EMPTY_METHODS; + LuaTable table = new LuaTable(); - String[] methods = object.getMethodNames(); - for( int i = 0; i < methods.length; i++ ) + for( int i = 0; i < dynamicMethods.length; i++ ) { - if( methods[i] != null ) - { - final int method = i; - final ILuaObject apiObject = object; - final String methodName = methods[i]; - table.rawset( methodName, new VarArgFunction() - { - @Override - public Varargs invoke( final LuaState state, Varargs args ) throws LuaError - { - Object[] arguments = toObjects( args, 1 ); - Object[] results; - try - { - results = apiObject.callMethod( context, method, arguments ); - } - catch( InterruptedException e ) - { - throw new InterruptedError( e ); - } - catch( LuaException e ) - { - throw new LuaError( e.getMessage(), e.getLevel() ); - } - catch( Throwable t ) - { - if( ComputerCraft.logPeripheralErrors ) - { - ComputerCraft.log.error( "Error calling " + methodName + " on " + apiObject, t ); - } - throw new LuaError( "Java Exception Thrown: " + t, 0 ); - } - return toValues( results ); - } - } ); - } + String method = dynamicMethods[i]; + table.rawset( method, new ResultInterpreterFunction( this, LuaMethod.DYNAMIC.get( i ), object, context, method ) ); } + + ObjectSource.allMethods( LuaMethod.GENERATOR, object, ( instance, method ) -> + table.rawset( method.getName(), method.nonYielding() + ? new BasicFunction( this, method.getMethod(), instance, context, method.getName() ) + : new ResultInterpreterFunction( this, method.getMethod(), instance, context, method.getName() ) ) ); + + try + { + if( table.keyCount() == 0 ) return null; + } + catch( LuaError ignored ) + { + } + return table; } @Nonnull - private LuaValue toValue( @Nullable Object object, @Nonnull Map values ) + private LuaValue toValue( @Nullable Object object, @Nullable Map values ) { if( object == null ) return Constants.NIL; if( object instanceof Number ) return valueOf( ((Number) object).doubleValue() ); @@ -274,13 +263,22 @@ public class CobaltLuaMachine implements ILuaMachine byte[] b = (byte[]) object; return valueOf( Arrays.copyOf( b, b.length ) ); } + if( object instanceof ByteBuffer ) + { + ByteBuffer b = (ByteBuffer) object; + byte[] bytes = new byte[b.remaining()]; + b.get( bytes ); + return valueOf( bytes ); + } + if( values == null ) values = new IdentityHashMap<>( 1 ); LuaValue result = values.get( object ); if( result != null ) return result; - if( object instanceof ILuaObject ) + if( object instanceof IDynamicLuaObject ) { - LuaValue wrapped = wrapLuaObject( (ILuaObject) object ); + LuaValue wrapped = wrapLuaObject( object ); + if( wrapped == null ) wrapped = new LuaTable(); values.put( object, wrapped ); return wrapped; } @@ -318,6 +316,13 @@ public class CobaltLuaMachine implements ILuaMachine return table; } + LuaTable wrapped = wrapLuaObject( object ); + if( wrapped != null ) + { + values.put( object, wrapped ); + return wrapped; + } + if( ComputerCraft.logPeripheralErrors ) { ComputerCraft.log.warn( "Received unknown type '{}', returning nil.", object.getClass().getName() ); @@ -325,9 +330,10 @@ public class CobaltLuaMachine implements ILuaMachine return Constants.NIL; } - private Varargs toValues( Object[] objects ) + Varargs toValues( Object[] objects ) { if( objects == null || objects.length == 0 ) return Constants.NONE; + if( objects.length == 1 ) return toValue( objects[0], null ); Map result = new IdentityHashMap<>( 0 ); LuaValue[] values = new LuaValue[objects.length]; @@ -339,7 +345,7 @@ public class CobaltLuaMachine implements ILuaMachine return varargsOf( values ); } - private static Object toObject( LuaValue value, Map objects ) + static Object toObject( LuaValue value, Map objects ) { switch( value.type() ) { @@ -359,11 +365,12 @@ public class CobaltLuaMachine implements ILuaMachine // Start remembering stuff if( objects == null ) { - objects = new IdentityHashMap<>(); + objects = new IdentityHashMap<>( 1 ); } - else if( objects.containsKey( value ) ) + else { - return objects.get( value ); + Object existing = objects.get( value ); + if( existing != null ) return existing; } Map table = new HashMap<>(); objects.put( value, table ); @@ -384,10 +391,7 @@ public class CobaltLuaMachine implements ILuaMachine break; } k = keyValue.first(); - if( k.isNil() ) - { - break; - } + if( k.isNil() ) break; LuaValue v = keyValue.arg( 2 ); Object keyObject = toObject( k, objects ); @@ -404,19 +408,19 @@ public class CobaltLuaMachine implements ILuaMachine } } - private static Object[] toObjects( Varargs values, int startIdx ) + static Object[] toObjects( Varargs values ) { int count = values.count(); - Object[] objects = new Object[count - startIdx + 1]; - for( int n = startIdx; n <= count; n++ ) - { - int i = n - startIdx; - LuaValue value = values.arg( n ); - objects[i] = toObject( value, null ); - } + Object[] objects = new Object[count]; + for( int i = 0; i < count; i++ ) objects[i] = toObject( values.arg( i + 1 ), null ); return objects; } + static IArguments toArguments( Varargs values ) + { + return values == Constants.NONE ? VarargArguments.EMPTY : new VarargArguments( values ); + } + /** * A {@link DebugHandler} which observes the {@link TimeoutState} and responds accordingly. */ @@ -500,23 +504,6 @@ public class CobaltLuaMachine implements ILuaMachine private class CobaltLuaContext implements ILuaContext { - @Nonnull - @Override - public Object[] yield( Object[] yieldArgs ) throws InterruptedException - { - try - { - LuaState state = m_state; - if( state == null ) throw new InterruptedException(); - Varargs results = LuaThread.yieldBlocking( state, toValues( yieldArgs ) ); - return toObjects( results, 1 ); - } - catch( LuaError e ) - { - throw new IllegalStateException( e.getMessage() ); - } - } - @Override public long issueMainThreadTask( @Nonnull final ILuaTask task ) throws LuaException { @@ -560,45 +547,6 @@ public class CobaltLuaMachine implements ILuaMachine throw new LuaException( "Task limit exceeded" ); } } - - @Override - public Object[] executeMainThreadTask( @Nonnull final ILuaTask task ) throws LuaException, InterruptedException - { - // Issue task - final long taskID = issueMainThreadTask( task ); - - // Wait for response - while( true ) - { - Object[] response = pullEvent( "task_complete" ); - if( response.length >= 3 && response[1] instanceof Number && response[2] instanceof Boolean ) - { - if( ((Number) response[1]).intValue() == taskID ) - { - Object[] returnValues = new Object[response.length - 3]; - if( (Boolean) response[2] ) - { - // Extract the return values from the event and return them - System.arraycopy( response, 3, returnValues, 0, returnValues.length ); - return returnValues; - } - else - { - // Extract the error message from the event and raise it - if( response.length >= 4 && response[3] instanceof String ) - { - throw new LuaException( (String) response[3] ); - } - else - { - throw new LuaException(); - } - } - } - } - } - - } } private static final class HardAbortError extends Error diff --git a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java index 4ca5d4b07..5c9de9cb3 100644 --- a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.core.lua; +import dan200.computercraft.api.lua.IDynamicLuaObject; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaObject; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -21,13 +21,13 @@ import java.io.InputStream; * mechanism for registering these. * * This should provide implementations of {@link dan200.computercraft.api.lua.ILuaContext}, and the ability to convert - * {@link ILuaObject}s into something the VM understands, as well as handling method calls. + * {@link IDynamicLuaObject}s into something the VM understands, as well as handling method calls. */ public interface ILuaMachine { /** * Inject an API into the global environment of this machine. This should construct an object, as it would for any - * {@link ILuaObject} and set it to all names in {@link ILuaAPI#getNames()}. + * {@link IDynamicLuaObject} and set it to all names in {@link ILuaAPI#getNames()}. * * Called before {@link #loadBios(InputStream)}. * diff --git a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java new file mode 100644 index 000000000..09e6ecd0b --- /dev/null +++ b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java @@ -0,0 +1,121 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.lua; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.*; +import dan200.computercraft.core.asm.LuaMethod; +import org.squiddev.cobalt.*; +import org.squiddev.cobalt.debug.DebugFrame; +import org.squiddev.cobalt.function.ResumableVarArgFunction; + +import javax.annotation.Nonnull; + +/** + * Calls a {@link LuaMethod}, and interprets the resulting {@link MethodResult}, either returning the result or yielding + * and resuming the supplied continuation. + */ +class ResultInterpreterFunction extends ResumableVarArgFunction +{ + @Nonnull + static class Container + { + ILuaCallback callback; + int errorAdjust; + + Container( ILuaCallback callback, int errorAdjust ) + { + this.callback = callback; + this.errorAdjust = errorAdjust; + } + } + + private final CobaltLuaMachine machine; + private final LuaMethod method; + private final Object instance; + private final ILuaContext context; + private final String name; + + ResultInterpreterFunction( CobaltLuaMachine machine, LuaMethod method, Object instance, ILuaContext context, String name ) + { + this.machine = machine; + this.method = method; + this.instance = instance; + this.context = context; + this.name = name; + } + + @Override + protected Varargs invoke( LuaState state, DebugFrame debugFrame, Varargs args ) throws LuaError, UnwindThrowable + { + IArguments arguments = CobaltLuaMachine.toArguments( args ); + MethodResult results; + try + { + results = method.apply( instance, context, arguments ); + } + catch( LuaException e ) + { + throw wrap( e, 0 ); + } + catch( Throwable t ) + { + if( ComputerCraft.logPeripheralErrors ) + { + ComputerCraft.log.error( "Error calling " + name + " on " + instance, t ); + } + throw new LuaError( "Java Exception Thrown: " + t, 0 ); + } + + ILuaCallback callback = results.getCallback(); + Varargs ret = machine.toValues( results.getResult() ); + + if( callback == null ) return ret; + + debugFrame.state = new Container( callback, results.getErrorAdjust() ); + return LuaThread.yield( state, ret ); + } + + @Override + protected Varargs resumeThis( LuaState state, Container container, Varargs args ) throws LuaError, UnwindThrowable + { + MethodResult results; + Object[] arguments = CobaltLuaMachine.toObjects( args ); + try + { + results = container.callback.resume( arguments ); + } + catch( LuaException e ) + { + throw wrap( e, container.errorAdjust ); + } + catch( Throwable t ) + { + if( ComputerCraft.logPeripheralErrors ) + { + ComputerCraft.log.error( "Error calling " + name + " on " + container.callback, t ); + } + throw new LuaError( "Java Exception Thrown: " + t, 0 ); + } + + Varargs ret = machine.toValues( results.getResult() ); + + ILuaCallback callback = results.getCallback(); + if( callback == null ) return ret; + + container.callback = callback; + return LuaThread.yield( state, ret ); + } + + public static LuaError wrap( LuaException exception, int adjust ) + { + if( !exception.hasLevel() && adjust == 0 ) return new LuaError( exception.getMessage() ); + + int level = exception.getLevel(); + return new LuaError( exception.getMessage(), level <= 0 ? level : level + adjust + 1 ); + } +} diff --git a/src/main/java/dan200/computercraft/core/lua/VarargArguments.java b/src/main/java/dan200/computercraft/core/lua/VarargArguments.java new file mode 100644 index 000000000..4ad8d58a4 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/lua/VarargArguments.java @@ -0,0 +1,102 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.lua; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaValues; +import org.squiddev.cobalt.*; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.util.Optional; + +class VarargArguments implements IArguments +{ + static final IArguments EMPTY = new VarargArguments( Constants.NONE ); + + private final Varargs varargs; + private Object[] cache; + + VarargArguments( Varargs varargs ) + { + this.varargs = varargs; + } + + @Override + public int count() + { + return varargs.count(); + } + + @Nullable + @Override + public Object get( int index ) + { + if( index < 0 || index >= varargs.count() ) return null; + + Object[] cache = this.cache; + if( cache == null ) + { + cache = this.cache = new Object[varargs.count()]; + } + else + { + Object existing = cache[index]; + if( existing != null ) return existing; + } + + return cache[index] = CobaltLuaMachine.toObject( varargs.arg( index + 1 ), null ); + } + + @Override + public IArguments drop( int count ) + { + if( count < 0 ) throw new IllegalStateException( "count cannot be negative" ); + if( count == 0 ) return this; + return new VarargArguments( varargs.subargs( count + 1 ) ); + } + + @Override + public double getDouble( int index ) throws LuaException + { + LuaValue value = varargs.arg( index + 1 ); + if( !(value instanceof LuaNumber) ) throw LuaValues.badArgument( index, "number", value.typeName() ); + return value.toDouble(); + } + + @Override + public long getLong( int index ) throws LuaException + { + LuaValue value = varargs.arg( index + 1 ); + if( !(value instanceof LuaNumber) ) throw LuaValues.badArgument( index, "number", value.typeName() ); + return value instanceof LuaInteger ? value.toInteger() : (long) LuaValues.checkFinite( index, value.toDouble() ); + } + + @Nonnull + @Override + public ByteBuffer getBytes( int index ) throws LuaException + { + LuaValue value = varargs.arg( index + 1 ); + if( !(value instanceof LuaString) ) throw LuaValues.badArgument( index, "string", value.typeName() ); + + LuaString str = (LuaString) value; + return ByteBuffer.wrap( str.bytes, str.offset, str.length ).asReadOnlyBuffer(); + } + + @Override + public Optional optBytes( int index ) throws LuaException + { + LuaValue value = varargs.arg( index + 1 ); + if( value.isNil() ) return Optional.empty(); + if( !(value instanceof LuaString) ) throw LuaValues.badArgument( index, "string", value.typeName() ); + + LuaString str = (LuaString) value; + return Optional.of( ByteBuffer.wrap( str.bytes, str.offset, str.length ).asReadOnlyBuffer() ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index b9c3e7b65..c7ef8986a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -9,9 +9,7 @@ import com.google.common.collect.ImmutableMap; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.*; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.block.Block; @@ -26,43 +24,23 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.registries.ForgeRegistries; -import javax.annotation.Nonnull; import java.util.*; -import static dan200.computercraft.api.lua.ArgumentHelper.getInt; -import static dan200.computercraft.api.lua.ArgumentHelper.getString; - public class CommandAPI implements ILuaAPI { - private TileCommandComputer m_computer; + private final TileCommandComputer computer; public CommandAPI( TileCommandComputer computer ) { - m_computer = computer; + this.computer = computer; } - // ILuaAPI implementation - @Override public String[] getNames() { return new String[] { "commands" }; } - @Nonnull - @Override - public String[] getMethodNames() - { - return new String[] { - "exec", - "execAsync", - "list", - "getBlockPosition", - "getBlockInfos", - "getBlockInfo", - }; - } - private static Object createOutput( String output ) { return new Object[] { output }; @@ -70,18 +48,18 @@ public class CommandAPI implements ILuaAPI private Object[] doCommand( String command ) { - MinecraftServer server = m_computer.getWorld().getServer(); + MinecraftServer server = computer.getWorld().getServer(); if( server == null || !server.isCommandBlockEnabled() ) { return new Object[] { false, createOutput( "Command blocks disabled by server" ) }; } Commands commandManager = server.getCommandManager(); - TileCommandComputer.CommandReceiver receiver = m_computer.getReceiver(); + TileCommandComputer.CommandReceiver receiver = computer.getReceiver(); try { receiver.clearOutput(); - int result = commandManager.handleCommand( m_computer.getSource(), command ); + int result = commandManager.handleCommand( computer.getSource(), command ); return new Object[] { result > 0, receiver.copyOutput(), result }; } catch( Throwable t ) @@ -91,7 +69,7 @@ public class CommandAPI implements ILuaAPI } } - private static Object getBlockInfo( World world, BlockPos pos ) + private static Map getBlockInfo( World world, BlockPos pos ) { // Get the details of the block BlockState state = world.getBlockState( pos ); @@ -121,121 +99,100 @@ public class CommandAPI implements ILuaAPI return property.getName( value ); } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction( mainThread = true ) + public final Object[] exec( String command ) { - switch( method ) + return doCommand( command ); + } + + @LuaFunction + public final long execAsync( ILuaContext context, String command ) throws LuaException + { + return context.issueMainThreadTask( () -> doCommand( command ) ); + } + + @LuaFunction( mainThread = true ) + public final List list( IArguments args ) throws LuaException + { + MinecraftServer server = computer.getWorld().getServer(); + + if( server == null ) return Collections.emptyList(); + CommandNode node = server.getCommandManager().getDispatcher().getRoot(); + for( int j = 0; j < args.count(); j++ ) { - case 0: // exec + String name = args.getString( j ); + node = node.getChild( name ); + if( !(node instanceof LiteralCommandNode) ) return Collections.emptyList(); + } + + List result = new ArrayList<>(); + for( CommandNode child : node.getChildren() ) + { + if( child instanceof LiteralCommandNode ) result.add( child.getName() ); + } + return result; + } + + @LuaFunction + public final Object[] getBlockPosition() + { + // This is probably safe to do on the Lua thread. Probably. + BlockPos pos = computer.getPos(); + return new Object[] { pos.getX(), pos.getY(), pos.getZ() }; + } + + @LuaFunction( mainThread = true ) + public final List> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException + { + // Get the details of the block + World world = computer.getWorld(); + BlockPos min = new BlockPos( + Math.min( minX, maxX ), + Math.min( minY, maxY ), + Math.min( minZ, maxZ ) + ); + BlockPos max = new BlockPos( + Math.max( minX, maxX ), + Math.max( minY, maxY ), + Math.max( minZ, maxZ ) + ); + if( !World.isValid( min ) || !World.isValid( max ) ) + { + throw new LuaException( "Co-ordinates out of range" ); + } + + int blocks = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1); + if( blocks > 4096 ) throw new LuaException( "Too many blocks" ); + + List> results = new ArrayList<>( blocks ); + for( int y = min.getY(); y <= max.getY(); y++ ) + { + for( int z = min.getZ(); z <= max.getZ(); z++ ) { - final String command = getString( arguments, 0 ); - return context.executeMainThreadTask( () -> doCommand( command ) ); - } - case 1: // execAsync - { - final String command = getString( arguments, 0 ); - long taskID = context.issueMainThreadTask( () -> doCommand( command ) ); - return new Object[] { taskID }; - } - case 2: - // list - return context.executeMainThreadTask( () -> + for( int x = min.getX(); x <= max.getX(); x++ ) { - MinecraftServer server = m_computer.getWorld().getServer(); - - if( server == null ) return new Object[] { Collections.emptyMap() }; - CommandNode node = server.getCommandManager().getDispatcher().getRoot(); - for( int j = 0; j < arguments.length; j++ ) - { - String name = getString( arguments, j ); - node = node.getChild( name ); - if( !(node instanceof LiteralCommandNode) ) return new Object[] { Collections.emptyMap() }; - } - - List result = new ArrayList<>(); - for( CommandNode child : node.getChildren() ) - { - if( child instanceof LiteralCommandNode ) result.add( child.getName() ); - } - return new Object[] { result }; - } ); - case 3: // getBlockPosition - { - // This is probably safe to do on the Lua thread. Probably. - BlockPos pos = m_computer.getPos(); - return new Object[] { pos.getX(), pos.getY(), pos.getZ() }; + BlockPos pos = new BlockPos( x, y, z ); + results.add( getBlockInfo( world, pos ) ); + } } - case 4: - { - // getBlockInfos - final int minX = getInt( arguments, 0 ); - final int minY = getInt( arguments, 1 ); - final int minZ = getInt( arguments, 2 ); - final int maxX = getInt( arguments, 3 ); - final int maxY = getInt( arguments, 4 ); - final int maxZ = getInt( arguments, 5 ); - return context.executeMainThreadTask( () -> - { - // Get the details of the block - World world = m_computer.getWorld(); - BlockPos min = new BlockPos( - Math.min( minX, maxX ), - Math.min( minY, maxY ), - Math.min( minZ, maxZ ) - ); - BlockPos max = new BlockPos( - Math.max( minX, maxX ), - Math.max( minY, maxY ), - Math.max( minZ, maxZ ) - ); - if( !World.isValid( min ) || !World.isValid( max ) ) - { - throw new LuaException( "Co-ordinates out of range" ); - } + } - int blocks = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1); - if( blocks > 4096 ) throw new LuaException( "Too many blocks" ); + return results; + } - List results = new ArrayList<>( blocks ); - for( int y = min.getY(); y <= max.getY(); y++ ) - { - for( int z = min.getZ(); z <= max.getZ(); z++ ) - { - for( int x = min.getX(); x <= max.getX(); x++ ) - { - BlockPos pos = new BlockPos( x, y, z ); - results.add( getBlockInfo( world, pos ) ); - } - } - } - return new Object[] { results }; - } ); - } - case 5: - { - // getBlockInfo - final int x = getInt( arguments, 0 ); - final int y = getInt( arguments, 1 ); - final int z = getInt( arguments, 2 ); - return context.executeMainThreadTask( () -> - { - // Get the details of the block - World world = m_computer.getWorld(); - BlockPos position = new BlockPos( x, y, z ); - if( World.isValid( position ) ) - { - return new Object[] { getBlockInfo( world, position ) }; - } - else - { - throw new LuaException( "Co-ordinates out of range" ); - } - } ); - } - default: - { - return null; - } + @LuaFunction( mainThread = true ) + public final Map getBlockInfo( int x, int y, int z ) throws LuaException + { + // Get the details of the block + World world = computer.getWorld(); + BlockPos position = new BlockPos( x, y, z ); + if( World.isValid( position ) ) + { + return getBlockInfo( world, position ); + } + else + { + throw new LuaException( "Co-ordinates out of range" ); } } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java index a536a9e29..71b394256 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java @@ -5,69 +5,63 @@ */ package dan200.computercraft.shared.computer.blocks; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import javax.annotation.Nonnull; public class ComputerPeripheral implements IPeripheral { - private final String m_type; - private final ComputerProxy m_computer; + private final String type; + private final ComputerProxy computer; public ComputerPeripheral( String type, ComputerProxy computer ) { - m_type = type; - m_computer = computer; + this.type = type; + this.computer = computer; } - // IPeripheral implementation - @Nonnull @Override public String getType() { - return m_type; + return type; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final void turnOn() { - return new String[] { - "turnOn", - "shutdown", - "reboot", - "getID", - "isOn", - "getLabel", - }; + computer.turnOn(); } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) + @LuaFunction + public final void shutdown() { - switch( method ) - { - case 0: // turnOn - m_computer.turnOn(); - return null; - case 1: // shutdown - m_computer.shutdown(); - return null; - case 2: // reboot - m_computer.reboot(); - return null; - case 3: // getID - return new Object[] { m_computer.assignID() }; - case 4: // isOn - return new Object[] { m_computer.isOn() }; - case 5: // getLabel - return new Object[] { m_computer.getLabel() }; - default: - return null; - } + computer.shutdown(); + } + + @LuaFunction + public final void reboot() + { + computer.reboot(); + } + + @LuaFunction + public final int getID() + { + return computer.assignID(); + } + + @LuaFunction + public final boolean isOn() + { + return computer.isOn(); + } + + @LuaFunction + public final String getLabel() + { + return computer.getLabel(); } @Override @@ -80,6 +74,6 @@ public class ComputerPeripheral implements IPeripheral @Override public Object getTarget() { - return m_computer.getTile(); + return computer.getTile(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index 2ed7dd1ea..383f65f62 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -5,27 +5,21 @@ */ package dan200.computercraft.shared.peripheral.commandblock; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.tileentity.CommandBlockTileEntity; import javax.annotation.Nonnull; -import static dan200.computercraft.api.lua.ArgumentHelper.getString; - public class CommandBlockPeripheral implements IPeripheral { - private final CommandBlockTileEntity m_commandBlock; + private final CommandBlockTileEntity commandBlock; public CommandBlockPeripheral( CommandBlockTileEntity commandBlock ) { - m_commandBlock = commandBlock; + this.commandBlock = commandBlock; } - // IPeripheral methods - @Nonnull @Override public String getType() @@ -33,54 +27,25 @@ public class CommandBlockPeripheral implements IPeripheral return "command"; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction( mainThread = true ) + public final String getCommand() { - return new String[] { - "getCommand", - "setCommand", - "runCommand", - }; + return commandBlock.getCommandBlockLogic().getCommand(); } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull final Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction( mainThread = true ) + public final void setCommand( String command ) { - switch( method ) - { - case 0: // getCommand - return context.executeMainThreadTask( () -> new Object[] { - m_commandBlock.getCommandBlockLogic().getCommand(), - } ); - case 1: - { - // setCommand - final String command = getString( arguments, 0 ); - context.issueMainThreadTask( () -> - { - m_commandBlock.getCommandBlockLogic().setCommand( command ); - m_commandBlock.getCommandBlockLogic().updateCommand(); - return null; - } ); - return null; - } - case 2: // runCommand - return context.executeMainThreadTask( () -> - { - m_commandBlock.getCommandBlockLogic().trigger( m_commandBlock.getWorld() ); - int result = m_commandBlock.getCommandBlockLogic().getSuccessCount(); - if( result > 0 ) - { - return new Object[] { true }; - } - else - { - return new Object[] { false, "Command failed" }; - } - } ); - } - return null; + commandBlock.getCommandBlockLogic().setCommand( command ); + commandBlock.getCommandBlockLogic().updateCommand(); + } + + @LuaFunction( mainThread = true ) + public final Object runCommand() + { + commandBlock.getCommandBlockLogic().trigger( commandBlock.getWorld() ); + int result = commandBlock.getCommandBlockLogic().getSuccessCount(); + return result > 0 ? new Object[] { true } : new Object[] { false, "Command failed" }; } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 97d7ef2cf..1a56cd236 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.shared.peripheral.diskdrive; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; @@ -16,16 +16,15 @@ import dan200.computercraft.shared.util.StringUtil; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; +import java.util.Optional; -import static dan200.computercraft.api.lua.ArgumentHelper.optString; - -class DiskDrivePeripheral implements IPeripheral +public class DiskDrivePeripheral implements IPeripheral { - private final TileDiskDrive m_diskDrive; + private final TileDiskDrive diskDrive; DiskDrivePeripheral( TileDiskDrive diskDrive ) { - m_diskDrive = diskDrive; + this.diskDrive = diskDrive; } @Nonnull @@ -35,114 +34,110 @@ class DiskDrivePeripheral implements IPeripheral return "drive"; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final boolean isDiskPresent() { - return new String[] { - "isDiskPresent", - "getDiskLabel", - "setDiskLabel", - "hasData", - "getMountPath", - "hasAudio", - "getAudioTitle", - "playAudio", - "stopAudio", - "ejectDisk", - "getDiskID", - }; + return !diskDrive.getDiskStack().isEmpty(); } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction + public final Object[] getDiskLabel() { - switch( method ) + ItemStack stack = diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + return media == null ? null : new Object[] { media.getLabel( stack ) }; + } + + @LuaFunction( mainThread = true ) + public final void setDiskLabel( Optional labelA ) throws LuaException + { + String label = labelA.orElse( null ); + ItemStack stack = diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + if( media == null ) return; + + if( !media.setLabel( stack, StringUtil.normaliseLabel( label ) ) ) { - case 0: // isDiskPresent - return new Object[] { !m_diskDrive.getDiskStack().isEmpty() }; - case 1: // getDiskLabel - { - ItemStack stack = m_diskDrive.getDiskStack(); - IMedia media = MediaProviders.get( stack ); - return media == null ? null : new Object[] { media.getLabel( stack ) }; - } - case 2: // setDiskLabel - { - String label = optString( arguments, 0, null ); - - return context.executeMainThreadTask( () -> { - ItemStack stack = m_diskDrive.getDiskStack(); - IMedia media = MediaProviders.get( stack ); - if( media == null ) return null; - - if( !media.setLabel( stack, StringUtil.normaliseLabel( label ) ) ) - { - throw new LuaException( "Disk label cannot be changed" ); - } - m_diskDrive.setDiskStack( stack ); - return null; - } ); - } - case 3: // hasData - return new Object[] { m_diskDrive.getDiskMountPath( computer ) != null }; - case 4: // getMountPath - return new Object[] { m_diskDrive.getDiskMountPath( computer ) }; - case 5: - { - // hasAudio - ItemStack stack = m_diskDrive.getDiskStack(); - IMedia media = MediaProviders.get( stack ); - return new Object[] { media != null && media.getAudio( stack ) != null }; - } - case 6: - { - // getAudioTitle - ItemStack stack = m_diskDrive.getDiskStack(); - IMedia media = MediaProviders.get( stack ); - return new Object[] { media != null ? media.getAudioTitle( stack ) : false }; - } - case 7: // playAudio - m_diskDrive.playDiskAudio(); - return null; - case 8: // stopAudio - m_diskDrive.stopDiskAudio(); - return null; - case 9: // eject - m_diskDrive.ejectDisk(); - return null; - case 10: // getDiskID - { - ItemStack disk = m_diskDrive.getDiskStack(); - return disk.getItem() instanceof ItemDisk ? new Object[] { ItemDisk.getDiskID( disk ) } : null; - } - default: - return null; + throw new LuaException( "Disk label cannot be changed" ); } + diskDrive.setDiskStack( stack ); + } + + @LuaFunction + public final boolean hasData( IComputerAccess computer ) + { + return diskDrive.getDiskMountPath( computer ) != null; + } + + @LuaFunction + public final String getMountPath( IComputerAccess computer ) + { + return diskDrive.getDiskMountPath( computer ); + } + + @LuaFunction + public final boolean hasAudio() + { + ItemStack stack = diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + return media != null && media.getAudio( stack ) != null; + } + + @LuaFunction + public final Object getAudioTitle() + { + ItemStack stack = diskDrive.getDiskStack(); + IMedia media = MediaProviders.get( stack ); + return media != null ? media.getAudioTitle( stack ) : false; + } + + @LuaFunction + public final void playAudio() + { + diskDrive.playDiskAudio(); + } + + @LuaFunction + public final void stopAudio() + { + diskDrive.stopDiskAudio(); + } + + @LuaFunction + public final void eject() + { + diskDrive.ejectDisk(); + } + + @LuaFunction + public final Object[] getDiskID() + { + ItemStack disk = diskDrive.getDiskStack(); + return disk.getItem() instanceof ItemDisk ? new Object[] { ItemDisk.getDiskID( disk ) } : null; } @Override public void attach( @Nonnull IComputerAccess computer ) { - m_diskDrive.mount( computer ); + diskDrive.mount( computer ); } @Override public void detach( @Nonnull IComputerAccess computer ) { - m_diskDrive.unmount( computer ); + diskDrive.unmount( computer ); } @Override public boolean equals( IPeripheral other ) { - return this == other || other instanceof DiskDrivePeripheral && ((DiskDrivePeripheral) other).m_diskDrive == m_diskDrive; + return this == other || other instanceof DiskDrivePeripheral && ((DiskDrivePeripheral) other).diskDrive == diskDrive; } @Nonnull @Override public Object getTarget() { - return m_diskDrive; + return diskDrive; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 79a8422a4..a6337d1dc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -434,7 +434,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory info.mountPath = null; } } - computer.queueEvent( "disk", new Object[] { computer.getAttachmentName() } ); + computer.queueEvent( "disk", computer.getAttachmentName() ); } } @@ -449,7 +449,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory computer.unmount( info.mountPath ); info.mountPath = null; } - computer.queueEvent( "disk_eject", new Object[] { computer.getAttachmentName() } ); + computer.queueEvent( "disk_eject", computer.getAttachmentName() ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 7a29744a7..32df37b98 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.shared.peripheral.modem; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.api.network.IPacketReceiver; import dan200.computercraft.api.network.IPacketSender; @@ -20,8 +20,6 @@ import javax.annotation.Nonnull; import java.util.HashSet; import java.util.Set; -import static dan200.computercraft.api.lua.ArgumentHelper.getInt; - public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver { private IPacketNetwork m_network; @@ -52,11 +50,6 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa if( m_network != null ) m_network.addReceiver( this ); } - protected void switchNetwork() - { - setNetwork( getNetwork() ); - } - public void destroy() { setNetwork( null ); @@ -71,9 +64,8 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa { for( IComputerAccess computer : m_computers ) { - computer.queueEvent( "modem_message", new Object[] { - computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance, - } ); + computer.queueEvent( "modem_message", + computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance ); } } } @@ -87,17 +79,14 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa { for( IComputerAccess computer : m_computers ) { - computer.queueEvent( "modem_message", new Object[] { - computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), - } ); + computer.queueEvent( "modem_message", + computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload() ); } } } protected abstract IPacketNetwork getNetwork(); - // IPeripheral implementation - @Nonnull @Override public String getType() @@ -105,90 +94,64 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return "modem"; } - @Nonnull - @Override - public String[] getMethodNames() + private static int parseChannel( int channel ) throws LuaException { - return new String[] { - "open", - "isOpen", - "close", - "closeAll", - "transmit", - "isWireless", - }; - } - - private static int parseChannel( Object[] arguments, int index ) throws LuaException - { - int channel = getInt( arguments, index ); - if( channel < 0 || channel > 65535 ) - { - throw new LuaException( "Expected number in range 0-65535" ); - } + if( channel < 0 || channel > 65535 ) throw new LuaException( "Expected number in range 0-65535" ); return channel; } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction + public final void open( int channel ) throws LuaException { - switch( method ) + m_state.open( parseChannel( channel ) ); + } + + @LuaFunction + public final boolean isOpen( int channel ) throws LuaException + { + return m_state.isOpen( parseChannel( channel ) ); + } + + @LuaFunction + public final void close( int channel ) throws LuaException + { + m_state.close( parseChannel( channel ) ); + } + + @LuaFunction + public final void closeAll() + { + m_state.closeAll(); + } + + @LuaFunction + public final void transmit( int channel, int replyChannel, Object payload ) throws LuaException + { + parseChannel( channel ); + parseChannel( replyChannel ); + + World world = getWorld(); + Vec3d position = getPosition(); + IPacketNetwork network = m_network; + + if( world == null || position == null || network == null ) return; + + Packet packet = new Packet( channel, replyChannel, payload, this ); + if( isInterdimensional() ) { - case 0: - { - // open - int channel = parseChannel( arguments, 0 ); - m_state.open( channel ); - return null; - } - case 1: - { - // isOpen - int channel = parseChannel( arguments, 0 ); - return new Object[] { m_state.isOpen( channel ) }; - } - case 2: - { - // close - int channel = parseChannel( arguments, 0 ); - m_state.close( channel ); - return null; - } - case 3: // closeAll - m_state.closeAll(); - return null; - case 4: - { - // transmit - int channel = parseChannel( arguments, 0 ); - int replyChannel = parseChannel( arguments, 1 ); - Object payload = arguments.length > 2 ? arguments[2] : null; - World world = getWorld(); - Vec3d position = getPosition(); - IPacketNetwork network = m_network; - if( world != null && position != null && network != null ) - { - Packet packet = new Packet( channel, replyChannel, payload, this ); - if( isInterdimensional() ) - { - network.transmitInterdimensional( packet ); - } - else - { - network.transmitSameDimension( packet, getRange() ); - } - } - return null; - } - case 5: - { - // isWireless - IPacketNetwork network = m_network; - return new Object[] { network != null && network.isWireless() }; - } - default: - return null; + network.transmitInterdimensional( packet ); } + else + { + network.transmitSameDimension( packet, getRange() ); + } + } + + @LuaFunction + public final boolean isWireless() + { + IPacketNetwork network = m_network; + return network != null && network.isWireless(); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 88223b71d..620f02cbd 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -8,27 +8,28 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.*; import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.network.wired.IWiredSender; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IWorkMonitor; +import dan200.computercraft.core.apis.PeripheralAPI; +import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static dan200.computercraft.api.lua.ArgumentHelper.getString; - public abstract class WiredModemPeripheral extends ModemPeripheral implements IWiredSender { private final WiredModemElement modem; @@ -71,93 +72,51 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW protected abstract WiredModemLocalPeripheral getLocalPeripheral(); //endregion - //region IPeripheral - @Nonnull - @Override - public String[] getMethodNames() + //region Peripheral methods + @LuaFunction + public final Collection getNamesRemote( IComputerAccess computer ) { - String[] methods = super.getMethodNames(); - String[] newMethods = new String[methods.length + 6]; - System.arraycopy( methods, 0, newMethods, 0, methods.length ); - newMethods[methods.length] = "getNamesRemote"; - newMethods[methods.length + 1] = "isPresentRemote"; - newMethods[methods.length + 2] = "getTypeRemote"; - newMethods[methods.length + 3] = "getMethodsRemote"; - newMethods[methods.length + 4] = "callRemote"; - newMethods[methods.length + 5] = "getNameLocal"; - return newMethods; + return getWrappers( computer ).keySet(); } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction + public final boolean isPresentRemote( IComputerAccess computer, String name ) { - String[] methods = super.getMethodNames(); - switch( method - methods.length ) - { - case 0: - { - // getNamesRemote - Map wrappers = getWrappers( computer ); - Map table = new HashMap<>(); - if( wrappers != null ) - { - int idx = 1; - for( String name : wrappers.keySet() ) table.put( idx++, name ); - } - return new Object[] { table }; - } - case 1: - { - // isPresentRemote - String name = getString( arguments, 0 ); - return new Object[] { getWrapper( computer, name ) != null }; - } - case 2: - { - // getTypeRemote - String name = getString( arguments, 0 ); - RemotePeripheralWrapper wrapper = getWrapper( computer, name ); - return wrapper != null ? new Object[] { wrapper.getType() } : null; - } - case 3: - { - // getMethodsRemote - String name = getString( arguments, 0 ); - RemotePeripheralWrapper wrapper = getWrapper( computer, name ); - if( wrapper == null ) return null; + return getWrapper( computer, name ) != null; + } - String[] methodNames = wrapper.getMethodNames(); - Map table = new HashMap<>(); - for( int i = 0; i < methodNames.length; i++ ) - { - table.put( i + 1, methodNames[i] ); - } - return new Object[] { table }; - } - case 4: - { - // callRemote - String remoteName = getString( arguments, 0 ); - String methodName = getString( arguments, 1 ); - RemotePeripheralWrapper wrapper = getWrapper( computer, remoteName ); - if( wrapper == null ) throw new LuaException( "No peripheral: " + remoteName ); + @LuaFunction + public final Object[] getTypeRemote( IComputerAccess computer, String name ) + { + RemotePeripheralWrapper wrapper = getWrapper( computer, name ); + return wrapper != null ? new Object[] { wrapper.getType() } : null; + } - Object[] methodArgs = new Object[arguments.length - 2]; - System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 ); - return wrapper.callMethod( context, methodName, methodArgs ); - } - case 5: - { - // getNameLocal - String local = getLocalPeripheral().getConnectedName(); - return local == null ? null : new Object[] { local }; - } - default: - { - // The regular modem methods - return super.callMethod( computer, context, method, arguments ); - } - } + @LuaFunction + public final Object[] getMethodsRemote( IComputerAccess computer, String name ) + { + RemotePeripheralWrapper wrapper = getWrapper( computer, name ); + if( wrapper == null ) return null; + + return new Object[] { wrapper.getMethodNames() }; + } + + @LuaFunction + public final MethodResult callRemote( IComputerAccess computer, ILuaContext context, IArguments arguments ) throws LuaException + { + String remoteName = arguments.getString( 0 ); + String methodName = arguments.getString( 1 ); + RemotePeripheralWrapper wrapper = getWrapper( computer, remoteName ); + if( wrapper == null ) throw new LuaException( "No peripheral: " + remoteName ); + + return wrapper.callMethod( context, methodName, arguments.drop( 2 ) ); + } + + @LuaFunction + public final Object[] getNameLocal() + { + String local = getLocalPeripheral().getConnectedName(); + return local == null ? null : new Object[] { local }; } @Override @@ -267,67 +226,52 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW private static class RemotePeripheralWrapper implements IComputerAccess { - private final WiredModemElement m_element; - private final IPeripheral m_peripheral; - private final IComputerAccess m_computer; - private final String m_name; + private final WiredModemElement element; + private final IPeripheral peripheral; + private final IComputerAccess computer; + private final String name; - private final String m_type; - private final String[] m_methods; - private final Map m_methodMap; + private final String type; + private final Map methodMap; RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name ) { - m_element = element; - m_peripheral = peripheral; - m_computer = computer; - m_name = name; + this.element = element; + this.peripheral = peripheral; + this.computer = computer; + this.name = name; - m_type = peripheral.getType(); - m_methods = peripheral.getMethodNames(); - assert m_type != null; - assert m_methods != null; - - m_methodMap = new HashMap<>(); - for( int i = 0; i < m_methods.length; i++ ) - { - if( m_methods[i] != null ) - { - m_methodMap.put( m_methods[i], i ); - } - } + type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); + methodMap = PeripheralAPI.getMethods( peripheral ); } public void attach() { - m_peripheral.attach( this ); - m_computer.queueEvent( "peripheral", new Object[] { getAttachmentName() } ); + peripheral.attach( this ); + computer.queueEvent( "peripheral", getAttachmentName() ); } public void detach() { - m_peripheral.detach( this ); - m_computer.queueEvent( "peripheral_detach", new Object[] { getAttachmentName() } ); + peripheral.detach( this ); + computer.queueEvent( "peripheral_detach", getAttachmentName() ); } public String getType() { - return m_type; + return type; } - public String[] getMethodNames() + public Collection getMethodNames() { - return m_methods; + return methodMap.keySet(); } - public Object[] callMethod( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException + public MethodResult callMethod( ILuaContext context, String methodName, IArguments arguments ) throws LuaException { - if( m_methodMap.containsKey( methodName ) ) - { - int method = m_methodMap.get( methodName ); - return m_peripheral.callMethod( this, context, method, arguments ); - } - throw new LuaException( "No such method " + methodName ); + PeripheralMethod method = methodMap.get( methodName ); + if( method == null ) throw new LuaException( "No such method " + methodName ); + return method.apply( peripheral, context, this, arguments ); } // IComputerAccess implementation @@ -335,66 +279,66 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW @Override public String mount( @Nonnull String desiredLocation, @Nonnull IMount mount ) { - return m_computer.mount( desiredLocation, mount, m_name ); + return computer.mount( desiredLocation, mount, name ); } @Override public String mount( @Nonnull String desiredLocation, @Nonnull IMount mount, @Nonnull String driveName ) { - return m_computer.mount( desiredLocation, mount, driveName ); + return computer.mount( desiredLocation, mount, driveName ); } @Override public String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount ) { - return m_computer.mountWritable( desiredLocation, mount, m_name ); + return computer.mountWritable( desiredLocation, mount, name ); } @Override public String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount, @Nonnull String driveName ) { - return m_computer.mountWritable( desiredLocation, mount, driveName ); + return computer.mountWritable( desiredLocation, mount, driveName ); } @Override public void unmount( String location ) { - m_computer.unmount( location ); + computer.unmount( location ); } @Override public int getID() { - return m_computer.getID(); + return computer.getID(); } @Override - public void queueEvent( @Nonnull String event, Object[] arguments ) + public void queueEvent( @Nonnull String event, Object... arguments ) { - m_computer.queueEvent( event, arguments ); + computer.queueEvent( event, arguments ); } @Nonnull @Override public IWorkMonitor getMainThreadMonitor() { - return m_computer.getMainThreadMonitor(); + return computer.getMainThreadMonitor(); } @Nonnull @Override public String getAttachmentName() { - return m_name; + return name; } @Nonnull @Override public Map getAvailablePeripherals() { - synchronized( m_element.getRemotePeripherals() ) + synchronized( element.getRemotePeripherals() ) { - return ImmutableMap.copyOf( m_element.getRemotePeripherals() ); + return ImmutableMap.copyOf( element.getRemotePeripherals() ); } } @@ -402,9 +346,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW @Override public IPeripheral getAvailablePeripheral( @Nonnull String name ) { - synchronized( m_element.getRemotePeripherals() ) + synchronized( element.getRemotePeripherals() ) { - return m_element.getRemotePeripherals().get( name ); + return element.getRemotePeripherals().get( name ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index a6db98161..1bd677a8c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -14,7 +14,7 @@ import net.minecraft.world.World; public abstract class WirelessModemPeripheral extends ModemPeripheral { - private boolean m_advanced; + private final boolean m_advanced; public WirelessModemPeripheral( ModemState state, boolean advanced ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java index 17246c424..67c88dc40 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java @@ -5,26 +5,23 @@ */ package dan200.computercraft.shared.peripheral.monitor; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.LuaValues; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.core.apis.TermAPI; +import dan200.computercraft.core.apis.TermMethods; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.shared.util.Palette; -import org.apache.commons.lang3.ArrayUtils; import javax.annotation.Nonnull; -import static dan200.computercraft.api.lua.ArgumentHelper.*; - -public class MonitorPeripheral implements IPeripheral +public class MonitorPeripheral extends TermMethods implements IPeripheral { - private final TileMonitor m_monitor; + private final TileMonitor monitor; public MonitorPeripheral( TileMonitor monitor ) { - m_monitor = monitor; + this.monitor = monitor; } @Nonnull @@ -34,201 +31,58 @@ public class MonitorPeripheral implements IPeripheral return "monitor"; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final void setTextScale( double scaleArg ) throws LuaException { - return new String[] { - "write", - "scroll", - "setCursorPos", - "setCursorBlink", - "getCursorPos", - "getSize", - "clear", - "clearLine", - "setTextScale", - "setTextColour", - "setTextColor", - "setBackgroundColour", - "setBackgroundColor", - "isColour", - "isColor", - "getTextColour", - "getTextColor", - "getBackgroundColour", - "getBackgroundColor", - "blit", - "setPaletteColour", - "setPaletteColor", - "getPaletteColour", - "getPaletteColor", - "getTextScale", - "getCursorBlink", - }; + int scale = (int) (LuaValues.checkFinite( 0, scaleArg ) * 2.0); + if( scale < 1 || scale > 10 ) throw new LuaException( "Expected number in range 0.5-5" ); + getMonitor().setTextScale( scale ); } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException + @LuaFunction + public final double getTextScale() throws LuaException { - ServerMonitor monitor = m_monitor.getCachedServerMonitor(); - if( monitor == null ) throw new LuaException( "Monitor has been detached" ); - - Terminal terminal = monitor.getTerminal(); - if( terminal == null ) throw new LuaException( "Monitor has been detached" ); - - switch( method ) - { - case 0: - { - // write - String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; - terminal.write( text ); - terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() ); - return null; - } - case 1: - { - // scroll - int value = getInt( args, 0 ); - terminal.scroll( value ); - return null; - } - case 2: - { - // setCursorPos - int x = getInt( args, 0 ) - 1; - int y = getInt( args, 1 ) - 1; - terminal.setCursorPos( x, y ); - return null; - } - case 3: - { - // setCursorBlink - boolean blink = getBoolean( args, 0 ); - terminal.setCursorBlink( blink ); - return null; - } - case 4: // getCursorPos - return new Object[] { terminal.getCursorX() + 1, terminal.getCursorY() + 1 }; - case 5: // getSize - return new Object[] { terminal.getWidth(), terminal.getHeight() }; - case 6: // clear - terminal.clear(); - return null; - case 7: // clearLine - terminal.clearLine(); - return null; - case 8: - { - // setTextScale - int scale = (int) (getFiniteDouble( args, 0 ) * 2.0); - if( scale < 1 || scale > 10 ) - { - throw new LuaException( "Expected number in range 0.5-5" ); - } - monitor.setTextScale( scale ); - return null; - } - case 9: - case 10: - { - // setTextColour/setTextColor - int colour = TermAPI.parseColour( args ); - terminal.setTextColour( colour ); - return null; - } - case 11: - case 12: - { - // setBackgroundColour/setBackgroundColor - int colour = TermAPI.parseColour( args ); - terminal.setBackgroundColour( colour ); - return null; - } - case 13: - case 14: // isColour/isColor - return new Object[] { monitor.isColour() }; - case 15: - case 16: // getTextColour/getTextColor - return TermAPI.encodeColour( terminal.getTextColour() ); - case 17: - case 18: // getBackgroundColour/getBackgroundColor - return TermAPI.encodeColour( terminal.getBackgroundColour() ); - case 19: - { - // blit - String text = getString( args, 0 ); - String textColour = getString( args, 1 ); - String backgroundColour = getString( args, 2 ); - if( textColour.length() != text.length() || backgroundColour.length() != text.length() ) - { - throw new LuaException( "Arguments must be the same length" ); - } - - terminal.blit( text, textColour, backgroundColour ); - terminal.setCursorPos( terminal.getCursorX() + text.length(), terminal.getCursorY() ); - return null; - } - case 20: - case 21: - { - // setPaletteColour/setPaletteColor - int colour = 15 - TermAPI.parseColour( args ); - if( args.length == 2 ) - { - int hex = getInt( args, 1 ); - double[] rgb = Palette.decodeRGB8( hex ); - TermAPI.setColour( terminal, colour, rgb[0], rgb[1], rgb[2] ); - } - else - { - double r = getFiniteDouble( args, 1 ); - double g = getFiniteDouble( args, 2 ); - double b = getFiniteDouble( args, 3 ); - TermAPI.setColour( terminal, colour, r, g, b ); - } - return null; - } - case 22: - case 23: - { - // getPaletteColour/getPaletteColor - Palette palette = terminal.getPalette(); - - int colour = 15 - TermAPI.parseColour( args ); - - if( palette != null ) - { - return ArrayUtils.toObject( palette.getColour( colour ) ); - } - return null; - } - case 24: // getTextScale - return new Object[] { monitor.getTextScale() / 2.0 }; - case 25: - // getCursorBlink - return new Object[] { terminal.getCursorBlink() }; - default: - return null; - } + return getMonitor().getTextScale() / 2.0; } @Override public void attach( @Nonnull IComputerAccess computer ) { - m_monitor.addComputer( computer ); + monitor.addComputer( computer ); } @Override public void detach( @Nonnull IComputerAccess computer ) { - m_monitor.removeComputer( computer ); + monitor.removeComputer( computer ); } @Override public boolean equals( IPeripheral other ) { - return other instanceof MonitorPeripheral && m_monitor == ((MonitorPeripheral) other).m_monitor; + return other instanceof MonitorPeripheral && monitor == ((MonitorPeripheral) other).monitor; + } + + @Nonnull + private ServerMonitor getMonitor() throws LuaException + { + ServerMonitor monitor = this.monitor.getCachedServerMonitor(); + if( monitor == null ) throw new LuaException( "Monitor has been detached" ); + return monitor; + } + + @Nonnull + @Override + public Terminal getTerminal() throws LuaException + { + Terminal terminal = getMonitor().getTerminal(); + if( terminal == null ) throw new LuaException( "Monitor has been detached" ); + return terminal; + } + + @Override + public boolean isColour() throws LuaException + { + return getMonitor().isColour(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index fa692be17..ff185fffc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -165,9 +165,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile for( IComputerAccess computer : monitor.m_computers ) { - computer.queueEvent( "monitor_resize", new Object[] { - computer.getAttachmentName(), - } ); + computer.queueEvent( "monitor_resize", computer.getAttachmentName() ); } } } @@ -635,9 +633,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile for( IComputerAccess computer : monitor.m_computers ) { - computer.queueEvent( "monitor_touch", new Object[] { - computer.getAttachmentName(), xCharPos, yCharPos, - } ); + computer.queueEvent( "monitor_touch", computer.getAttachmentName(), xCharPos, yCharPos ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index b699b8eb5..ee83959d4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -5,25 +5,22 @@ */ package dan200.computercraft.shared.peripheral.printer; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.util.StringUtil; import javax.annotation.Nonnull; - -import static dan200.computercraft.api.lua.ArgumentHelper.getInt; -import static dan200.computercraft.api.lua.ArgumentHelper.optString; +import java.util.Optional; public class PrinterPeripheral implements IPeripheral { - private final TilePrinter m_printer; + private final TilePrinter printer; public PrinterPeripheral( TilePrinter printer ) { - m_printer = printer; + this.printer = printer; } @Nonnull @@ -33,108 +30,94 @@ public class PrinterPeripheral implements IPeripheral return "printer"; } - @Nonnull - @Override - public String[] getMethodNames() + // FIXME: There's a theoretical race condition here between getCurrentPage and then using the page. Ideally + // we'd lock on the page, consume it, and unlock. + + // FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be + // persisted correctly. + + public final void write( Object[] args ) throws LuaException { - return new String[] { - "write", - "setCursorPos", - "getCursorPos", - "getPageSize", - "newPage", - "endPage", - "getInkLevel", - "setPageTitle", - "getPaperLevel", - }; + String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; + Terminal page = getCurrentPage(); + page.write( text ); + page.setCursorPos( page.getCursorX() + text.length(), page.getCursorY() ); } - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException + @LuaFunction + public final Object[] getCursorPos() throws LuaException { - // FIXME: There's a theoretical race condition here between getCurrentPage and then using the page. Ideally - // we'd lock on the page, consume it, and unlock. + Terminal page = getCurrentPage(); + int x = page.getCursorX(); + int y = page.getCursorY(); + return new Object[] { x + 1, y + 1 }; + } - // FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be - // persisted correctly. - switch( method ) - { - case 0: // write - { - String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; - Terminal page = getCurrentPage(); - page.write( text ); - page.setCursorPos( page.getCursorX() + text.length(), page.getCursorY() ); - return null; - } - case 1: - { - // setCursorPos - int x = getInt( args, 0 ) - 1; - int y = getInt( args, 1 ) - 1; - Terminal page = getCurrentPage(); - page.setCursorPos( x, y ); - return null; - } - case 2: - { - // getCursorPos - Terminal page = getCurrentPage(); - int x = page.getCursorX(); - int y = page.getCursorY(); - return new Object[] { x + 1, y + 1 }; - } - case 3: - { - // getPageSize - Terminal page = getCurrentPage(); - int width = page.getWidth(); - int height = page.getHeight(); - return new Object[] { width, height }; - } - case 4: // newPage - return context.executeMainThreadTask( () -> new Object[] { m_printer.startNewPage() } ); - case 5: // endPage - getCurrentPage(); - return context.executeMainThreadTask( () -> { - getCurrentPage(); - return new Object[] { m_printer.endCurrentPage() }; - } ); - case 6: // getInkLevel - return new Object[] { m_printer.getInkLevel() }; - case 7: - { - // setPageTitle - String title = optString( args, 0, "" ); - getCurrentPage(); - m_printer.setPageTitle( StringUtil.normaliseLabel( title ) ); - return null; - } - case 8: // getPaperLevel - return new Object[] { m_printer.getPaperLevel() }; - default: - return null; - } + @LuaFunction + public final void setCursorPos( int x, int y ) throws LuaException + { + Terminal page = getCurrentPage(); + page.setCursorPos( x - 1, y - 1 ); + } + + @LuaFunction + public final Object[] getPageSize() throws LuaException + { + Terminal page = getCurrentPage(); + int width = page.getWidth(); + int height = page.getHeight(); + return new Object[] { width, height }; + } + + @LuaFunction( mainThread = true ) + public final boolean newPage() + { + return printer.startNewPage(); + } + + @LuaFunction( mainThread = true ) + public final boolean endPage() throws LuaException + { + getCurrentPage(); + return printer.endCurrentPage(); + } + + @LuaFunction + public final void setPageTitle( Optional title ) throws LuaException + { + getCurrentPage(); + printer.setPageTitle( StringUtil.normaliseLabel( title.orElse( "" ) ) ); + } + + @LuaFunction + public final int getInkLevel() + { + return printer.getInkLevel(); + } + + @LuaFunction + public final int getPaperLevel() + { + return printer.getPaperLevel(); } @Override public boolean equals( IPeripheral other ) { - return other instanceof PrinterPeripheral && ((PrinterPeripheral) other).m_printer == m_printer; + return other instanceof PrinterPeripheral && ((PrinterPeripheral) other).printer == printer; } @Nonnull @Override public Object getTarget() { - return m_printer; + return printer; } @Nonnull private Terminal getCurrentPage() throws LuaException { - Terminal currentPage = m_printer.getCurrentPage(); + Terminal currentPage = printer.getCurrentPage(); if( currentPage == null ) throw new LuaException( "Page not started" ); return currentPage; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 0352c8163..4920e7260 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import net.minecraft.network.play.server.SPlaySoundPacket; import net.minecraft.server.MinecraftServer; @@ -20,10 +20,10 @@ import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import javax.annotation.Nonnull; +import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; -import static dan200.computercraft.api.lua.ArgumentHelper.getString; -import static dan200.computercraft.api.lua.ArgumentHelper.optFiniteDouble; +import static dan200.computercraft.api.lua.LuaValues.checkFinite; public abstract class SpeakerPeripheral implements IPeripheral { @@ -53,54 +53,30 @@ public abstract class SpeakerPeripheral implements IPeripheral return "speaker"; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final boolean playSound( ILuaContext context, String name, Optional volumeA, Optional pitchA ) throws LuaException { - return new String[] { - "playSound", - "playNote", - }; - } + float volume = (float) checkFinite( 1, volumeA.orElse( 1.0 ) ); + float pitch = (float) checkFinite( 2, pitchA.orElse( 1.0 ) ); - @Override - public Object[] callMethod( @Nonnull IComputerAccess computerAccess, @Nonnull ILuaContext context, int methodIndex, @Nonnull Object[] args ) throws LuaException - { - switch( methodIndex ) + ResourceLocation identifier; + try { - case 0: // playSound - { - String name = getString( args, 0 ); - float volume = (float) optFiniteDouble( args, 1, 1.0 ); - float pitch = (float) optFiniteDouble( args, 2, 1.0 ); - - ResourceLocation identifier; - try - { - identifier = new ResourceLocation( name ); - } - catch( ResourceLocationException e ) - { - throw new LuaException( "Malformed sound name '" + name + "' " ); - } - - return new Object[] { playSound( context, identifier, volume, pitch, false ) }; - } - - case 1: // playNote - return playNote( args, context ); - - default: - throw new IllegalStateException( "Method index out of range!" ); + identifier = new ResourceLocation( name ); } + catch( ResourceLocationException e ) + { + throw new LuaException( "Malformed sound name '" + name + "' " ); + } + + return playSound( context, identifier, volume, pitch, false ); } - @Nonnull - private synchronized Object[] playNote( Object[] arguments, ILuaContext context ) throws LuaException + @LuaFunction + public final synchronized boolean playNote( ILuaContext context, String name, Optional volumeA, Optional pitchA ) throws LuaException { - String name = getString( arguments, 0 ); - float volume = (float) optFiniteDouble( arguments, 1, 1.0 ); - float pitch = (float) optFiniteDouble( arguments, 2, 1.0 ); + float volume = (float) checkFinite( 1, volumeA.orElse( 1.0 ) ); + float pitch = (float) checkFinite( 2, pitchA.orElse( 1.0 ) ); NoteBlockInstrument instrument = null; for( NoteBlockInstrument testInstrument : NoteBlockInstrument.values() ) @@ -113,16 +89,12 @@ public abstract class SpeakerPeripheral implements IPeripheral } // Check if the note exists - if( instrument == null ) - { - throw new LuaException( "Invalid instrument, \"" + name + "\"!" ); - } + if( instrument == null ) throw new LuaException( "Invalid instrument, \"" + name + "\"!" ); // If the resource location for note block notes changes, this method call will need to be updated boolean success = playSound( context, instrument.getSound().getRegistryName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); - if( success ) m_notesThisTick.incrementAndGet(); - return new Object[] { success }; + return success; } private synchronized boolean playSound( ILuaContext context, ResourceLocation name, float volume, float pitch, boolean isNote ) throws LuaException diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 9d481758b..15f8df2c0 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -6,8 +6,7 @@ package dan200.computercraft.shared.pocket.apis; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.pocket.core.PocketServerComputer; @@ -20,15 +19,13 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; import net.minecraftforge.items.wrapper.PlayerMainInvWrapper; -import javax.annotation.Nonnull; - public class PocketAPI implements ILuaAPI { - private final PocketServerComputer m_computer; + private final PocketServerComputer computer; public PocketAPI( PocketServerComputer computer ) { - m_computer = computer; + this.computer = computer; } @Override @@ -37,89 +34,68 @@ public class PocketAPI implements ILuaAPI return new String[] { "pocket" }; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction( mainThread = true ) + public final Object[] equipBack() { - return new String[] { - "equipBack", - "unequipBack", - }; + Entity entity = computer.getEntity(); + if( !(entity instanceof PlayerEntity) ) return new Object[] { false, "Cannot find player" }; + PlayerEntity player = (PlayerEntity) entity; + PlayerInventory inventory = player.inventory; + IPocketUpgrade previousUpgrade = computer.getUpgrade(); + + // Attempt to find the upgrade, starting in the main segment, and then looking in the opposite + // one. We start from the position the item is currently in and loop round to the start. + IPocketUpgrade newUpgrade = findUpgrade( inventory.mainInventory, inventory.currentItem, previousUpgrade ); + if( newUpgrade == null ) + { + newUpgrade = findUpgrade( inventory.offHandInventory, 0, previousUpgrade ); + } + if( newUpgrade == null ) return new Object[] { false, "Cannot find a valid upgrade" }; + + // Remove the current upgrade + if( previousUpgrade != null ) + { + ItemStack stack = previousUpgrade.getCraftingItem(); + if( !stack.isEmpty() ) + { + stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); + if( !stack.isEmpty() ) + { + WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() ); + } + } + } + + // Set the new upgrade + computer.setUpgrade( newUpgrade ); + + return new Object[] { true }; } - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction( mainThread = true ) + public final Object[] unequipBack() { - switch( method ) + Entity entity = computer.getEntity(); + if( !(entity instanceof PlayerEntity) ) return new Object[] { false, "Cannot find player" }; + PlayerEntity player = (PlayerEntity) entity; + PlayerInventory inventory = player.inventory; + IPocketUpgrade previousUpgrade = computer.getUpgrade(); + + if( previousUpgrade == null ) return new Object[] { false, "Nothing to unequip" }; + + computer.setUpgrade( null ); + + ItemStack stack = previousUpgrade.getCraftingItem(); + if( !stack.isEmpty() ) { - case 0: - // equipBack - return context.executeMainThreadTask( () -> - { - Entity entity = m_computer.getEntity(); - if( !(entity instanceof PlayerEntity) ) return new Object[] { false, "Cannot find player" }; - PlayerEntity player = (PlayerEntity) entity; - PlayerInventory inventory = player.inventory; - IPocketUpgrade previousUpgrade = m_computer.getUpgrade(); - - // Attempt to find the upgrade, starting in the main segment, and then looking in the opposite - // one. We start from the position the item is currently in and loop round to the start. - IPocketUpgrade newUpgrade = findUpgrade( inventory.mainInventory, inventory.currentItem, previousUpgrade ); - if( newUpgrade == null ) - { - newUpgrade = findUpgrade( inventory.offHandInventory, 0, previousUpgrade ); - } - if( newUpgrade == null ) return new Object[] { false, "Cannot find a valid upgrade" }; - - // Remove the current upgrade - if( previousUpgrade != null ) - { - ItemStack stack = previousUpgrade.getCraftingItem(); - if( !stack.isEmpty() ) - { - stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); - if( !stack.isEmpty() ) - { - WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() ); - } - } - } - - // Set the new upgrade - m_computer.setUpgrade( newUpgrade ); - - return new Object[] { true }; - } ); - - case 1: - // unequipBack - return context.executeMainThreadTask( () -> - { - Entity entity = m_computer.getEntity(); - if( !(entity instanceof PlayerEntity) ) return new Object[] { false, "Cannot find player" }; - PlayerEntity player = (PlayerEntity) entity; - PlayerInventory inventory = player.inventory; - IPocketUpgrade previousUpgrade = m_computer.getUpgrade(); - - if( previousUpgrade == null ) return new Object[] { false, "Nothing to unequip" }; - - m_computer.setUpgrade( null ); - - ItemStack stack = previousUpgrade.getCraftingItem(); - if( !stack.isEmpty() ) - { - stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); - if( stack.isEmpty() ) - { - WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() ); - } - } - - return new Object[] { true }; - } ); - default: - return null; + stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem ); + if( stack.isEmpty() ) + { + WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() ); + } } + + return new Object[] { true }; } private static IPocketUpgrade findUpgrade( NonNullList inv, int start, IPocketUpgrade previous ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index a124d8e76..ddd19fcea 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -5,9 +5,7 @@ */ package dan200.computercraft.shared.turtle.apis; -import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.*; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; @@ -22,343 +20,333 @@ import net.minecraft.item.ItemStack; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.registries.ForgeRegistries; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; - -import static dan200.computercraft.api.lua.ArgumentHelper.*; +import java.util.Optional; public class TurtleAPI implements ILuaAPI { - private IAPIEnvironment m_environment; - private ITurtleAccess m_turtle; + private final IAPIEnvironment environment; + private final ITurtleAccess turtle; public TurtleAPI( IAPIEnvironment environment, ITurtleAccess turtle ) { - m_environment = environment; - m_turtle = turtle; + this.environment = environment; + this.turtle = turtle; } - // ILuaAPI implementation - @Override public String[] getNames() { return new String[] { "turtle" }; } - @Nonnull - @Override - public String[] getMethodNames() + private MethodResult trackCommand( ITurtleCommand command ) { - return new String[] { - "forward", - "back", - "up", - "down", - "turnLeft", - "turnRight", - "dig", - "digUp", - "digDown", - "place", - "placeUp", - "placeDown", - "drop", - "select", - "getItemCount", - "getItemSpace", - "detect", - "detectUp", - "detectDown", - "compare", - "compareUp", - "compareDown", - "attack", - "attackUp", - "attackDown", - "dropUp", - "dropDown", - "suck", - "suckUp", - "suckDown", - "getFuelLevel", - "refuel", - "compareTo", - "transferTo", - "getSelectedSlot", - "getFuelLimit", - "equipLeft", - "equipRight", - "inspect", - "inspectUp", - "inspectDown", - "getItemDetail", - }; + environment.addTrackingChange( TrackingField.TURTLE_OPS ); + return turtle.executeCommand( command ); } - private Object[] tryCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException + @LuaFunction + public final MethodResult forward() { - return m_turtle.executeCommand( context, command ); + return trackCommand( new TurtleMoveCommand( MoveDirection.FORWARD ) ); } - private int parseSlotNumber( Object[] arguments, int index ) throws LuaException + @LuaFunction + public final MethodResult back() + { + return trackCommand( new TurtleMoveCommand( MoveDirection.BACK ) ); + } + + @LuaFunction + public final MethodResult up() + { + return trackCommand( new TurtleMoveCommand( MoveDirection.UP ) ); + } + + @LuaFunction + public final MethodResult down() + { + return trackCommand( new TurtleMoveCommand( MoveDirection.DOWN ) ); + } + + @LuaFunction + public final MethodResult turnLeft() + { + return trackCommand( new TurtleTurnCommand( TurnDirection.LEFT ) ); + } + + @LuaFunction + public final MethodResult turnRight() + { + return trackCommand( new TurtleTurnCommand( TurnDirection.RIGHT ) ); + } + + @LuaFunction + public final MethodResult dig( Optional side ) + { + environment.addTrackingChange( TrackingField.TURTLE_OPS ); + return trackCommand( TurtleToolCommand.dig( InteractDirection.FORWARD, side.orElse( null ) ) ); + } + + @LuaFunction + public final MethodResult digUp( Optional side ) + { + environment.addTrackingChange( TrackingField.TURTLE_OPS ); + return trackCommand( TurtleToolCommand.dig( InteractDirection.UP, side.orElse( null ) ) ); + } + + @LuaFunction + public final MethodResult digDown( Optional side ) + { + environment.addTrackingChange( TrackingField.TURTLE_OPS ); + return trackCommand( TurtleToolCommand.dig( InteractDirection.DOWN, side.orElse( null ) ) ); + } + + @LuaFunction + public final MethodResult place( IArguments args ) + { + return trackCommand( new TurtlePlaceCommand( InteractDirection.FORWARD, args.getAll() ) ); + } + + @LuaFunction + public final MethodResult placeUp( IArguments args ) + { + return trackCommand( new TurtlePlaceCommand( InteractDirection.UP, args.getAll() ) ); + } + + @LuaFunction + public final MethodResult placeDown( IArguments args ) + { + return trackCommand( new TurtlePlaceCommand( InteractDirection.DOWN, args.getAll() ) ); + } + + @LuaFunction + public final MethodResult drop( Optional count ) throws LuaException + { + return trackCommand( new TurtleDropCommand( InteractDirection.FORWARD, checkCount( count ) ) ); + } + + @LuaFunction + public final MethodResult dropUp( Optional count ) throws LuaException + { + return trackCommand( new TurtleDropCommand( InteractDirection.UP, checkCount( count ) ) ); + } + + @LuaFunction + public final MethodResult dropDown( Optional count ) throws LuaException + { + return trackCommand( new TurtleDropCommand( InteractDirection.DOWN, checkCount( count ) ) ); + } + + @LuaFunction + public final MethodResult select( int slot ) throws LuaException + { + int actualSlot = checkSlot( slot ); + return turtle.executeCommand( turtle -> { + turtle.setSelectedSlot( actualSlot ); + return TurtleCommandResult.success(); + } ); + } + + @LuaFunction + public final int getItemCount( Optional slot ) throws LuaException + { + int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); + return turtle.getInventory().getStackInSlot( actualSlot ).getCount(); + } + + @LuaFunction + public final int getItemSpace( Optional slot ) throws LuaException + { + int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); + ItemStack stack = turtle.getInventory().getStackInSlot( actualSlot ); + return stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount(); + } + + @LuaFunction + public final MethodResult detect() + { + return trackCommand( new TurtleDetectCommand( InteractDirection.FORWARD ) ); + } + + @LuaFunction + public final MethodResult detectUp() + { + return trackCommand( new TurtleDetectCommand( InteractDirection.UP ) ); + } + + @LuaFunction + public final MethodResult detectDown() + { + return trackCommand( new TurtleDetectCommand( InteractDirection.DOWN ) ); + } + + @LuaFunction + public final MethodResult compare() + { + return trackCommand( new TurtleCompareCommand( InteractDirection.FORWARD ) ); + } + + @LuaFunction + public final MethodResult compareUp() + { + return trackCommand( new TurtleCompareCommand( InteractDirection.UP ) ); + } + + @LuaFunction + public final MethodResult compareDown() + { + return trackCommand( new TurtleCompareCommand( InteractDirection.DOWN ) ); + } + + @LuaFunction + public final MethodResult attack( Optional side ) + { + return trackCommand( TurtleToolCommand.attack( InteractDirection.FORWARD, side.orElse( null ) ) ); + } + + @LuaFunction + public final MethodResult attackUp( Optional side ) + { + return trackCommand( TurtleToolCommand.attack( InteractDirection.UP, side.orElse( null ) ) ); + } + + @LuaFunction + public final MethodResult attackDown( Optional side ) + { + return trackCommand( TurtleToolCommand.attack( InteractDirection.DOWN, side.orElse( null ) ) ); + } + + @LuaFunction + public final MethodResult suck( Optional count ) throws LuaException + { + return trackCommand( new TurtleSuckCommand( InteractDirection.FORWARD, checkCount( count ) ) ); + } + + @LuaFunction + public final MethodResult suckUp( Optional count ) throws LuaException + { + return trackCommand( new TurtleSuckCommand( InteractDirection.UP, checkCount( count ) ) ); + } + + @LuaFunction + public final MethodResult suckDown( Optional count ) throws LuaException + { + return trackCommand( new TurtleSuckCommand( InteractDirection.DOWN, checkCount( count ) ) ); + } + + @LuaFunction + public final Object getFuelLevel() + { + return turtle.isFuelNeeded() ? turtle.getFuelLevel() : "unlimited"; + } + + @LuaFunction + public final MethodResult refuel( Optional countA ) throws LuaException + { + int count = countA.orElse( Integer.MAX_VALUE ); + if( count < 0 ) throw new LuaException( "Refuel count " + count + " out of range" ); + return trackCommand( new TurtleRefuelCommand( count ) ); + } + + @LuaFunction + public final MethodResult compareTo( int slot ) throws LuaException + { + return trackCommand( new TurtleCompareToCommand( checkSlot( slot ) ) ); + } + + @LuaFunction + public final MethodResult transferTo( int slotArg, Optional countArg ) throws LuaException + { + int slot = checkSlot( slotArg ); + int count = checkCount( countArg ); + return trackCommand( new TurtleTransferToCommand( slot, count ) ); + } + + @LuaFunction + public final int getSelectedSlot() + { + return turtle.getSelectedSlot() + 1; + } + + @LuaFunction + public final Object getFuelLimit() + { + return turtle.isFuelNeeded() ? turtle.getFuelLimit() : "unlimited"; + } + + @LuaFunction + public final MethodResult equipLeft() + { + return trackCommand( new TurtleEquipCommand( TurtleSide.LEFT ) ); + } + + @LuaFunction + public final MethodResult equipRight() + { + return trackCommand( new TurtleEquipCommand( TurtleSide.RIGHT ) ); + } + + @LuaFunction + public final MethodResult inspect() + { + return trackCommand( new TurtleInspectCommand( InteractDirection.FORWARD ) ); + } + + @LuaFunction + public final MethodResult inspectUp() + { + return trackCommand( new TurtleInspectCommand( InteractDirection.UP ) ); + } + + @LuaFunction + public final MethodResult inspectDown() + { + return trackCommand( new TurtleInspectCommand( InteractDirection.DOWN ) ); + } + + @LuaFunction + public final Object[] getItemDetail( Optional slotArg ) throws LuaException + { + // FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...) + // on another thread. The obvious solution is to move this into a command, but some programs rely + // on this having a 0-tick delay. + int slot = checkSlot( slotArg ).orElse( turtle.getSelectedSlot() ); + ItemStack stack = turtle.getInventory().getStackInSlot( slot ); + if( stack.isEmpty() ) return new Object[] { null }; + + Item item = stack.getItem(); + String name = ForgeRegistries.ITEMS.getKey( item ).toString(); + int count = stack.getCount(); + + Map table = new HashMap<>(); + table.put( "name", name ); + table.put( "count", count ); + + TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table ); + if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() }; + + return new Object[] { table }; + } + + + private static int checkSlot( int slot ) throws LuaException { - int slot = getInt( arguments, index ); if( slot < 1 || slot > 16 ) throw new LuaException( "Slot number " + slot + " out of range" ); return slot - 1; } - private int parseOptionalSlotNumber( Object[] arguments, int index, int fallback ) throws LuaException + private static Optional checkSlot( Optional slot ) throws LuaException { - if( index >= arguments.length || arguments[index] == null ) return fallback; - return parseSlotNumber( arguments, index ); + return slot.isPresent() ? Optional.of( checkSlot( slot.get() ) ) : Optional.empty(); } - private static int parseCount( Object[] arguments, int index ) throws LuaException + private static int checkCount( Optional countArg ) throws LuaException { - int count = optInt( arguments, index, 64 ); + int count = countArg.orElse( 64 ); if( count < 0 || count > 64 ) throw new LuaException( "Item count " + count + " out of range" ); return count; } - - @Nullable - private static TurtleSide parseSide( Object[] arguments, int index ) throws LuaException - { - String side = optString( arguments, index, null ); - if( side == null ) - { - return null; - } - else if( side.equalsIgnoreCase( "left" ) ) - { - return TurtleSide.LEFT; - } - else if( side.equalsIgnoreCase( "right" ) ) - { - return TurtleSide.RIGHT; - } - else - { - throw new LuaException( "Invalid side" ); - } - } - - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException - { - switch( method ) - { - case 0: // forward - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.FORWARD ) ); - case 1: // back - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.BACK ) ); - case 2: // up - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.UP ) ); - case 3: // down - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleMoveCommand( MoveDirection.DOWN ) ); - case 4: // turnLeft - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleTurnCommand( TurnDirection.LEFT ) ); - case 5: // turnRight - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleTurnCommand( TurnDirection.RIGHT ) ); - case 6: - { - // dig - TurtleSide side = parseSide( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.dig( InteractDirection.FORWARD, side ) ); - } - case 7: - { - // digUp - TurtleSide side = parseSide( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.dig( InteractDirection.UP, side ) ); - } - case 8: - { - // digDown - TurtleSide side = parseSide( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.dig( InteractDirection.DOWN, side ) ); - } - case 9: // place - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtlePlaceCommand( InteractDirection.FORWARD, args ) ); - case 10: // placeUp - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtlePlaceCommand( InteractDirection.UP, args ) ); - case 11: // placeDown - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtlePlaceCommand( InteractDirection.DOWN, args ) ); - case 12: - { - // drop - int count = parseCount( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleDropCommand( InteractDirection.FORWARD, count ) ); - } - case 13: - { - // select - int slot = parseSlotNumber( args, 0 ); - return tryCommand( context, turtle -> { - turtle.setSelectedSlot( slot ); - return TurtleCommandResult.success(); - } ); - } - case 14: - { - // getItemCount - int slot = parseOptionalSlotNumber( args, 0, m_turtle.getSelectedSlot() ); - ItemStack stack = m_turtle.getInventory().getStackInSlot( slot ); - return new Object[] { stack.getCount() }; - } - case 15: - { - // getItemSpace - int slot = parseOptionalSlotNumber( args, 0, m_turtle.getSelectedSlot() ); - ItemStack stack = m_turtle.getInventory().getStackInSlot( slot ); - return new Object[] { stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount() }; - } - case 16: // detect - return tryCommand( context, new TurtleDetectCommand( InteractDirection.FORWARD ) ); - case 17: // detectUp - return tryCommand( context, new TurtleDetectCommand( InteractDirection.UP ) ); - case 18: // detectDown - return tryCommand( context, new TurtleDetectCommand( InteractDirection.DOWN ) ); - case 19: // compare - return tryCommand( context, new TurtleCompareCommand( InteractDirection.FORWARD ) ); - case 20: // compareUp - return tryCommand( context, new TurtleCompareCommand( InteractDirection.UP ) ); - case 21: // compareDown - return tryCommand( context, new TurtleCompareCommand( InteractDirection.DOWN ) ); - case 22: - { - // attack - TurtleSide side = parseSide( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.attack( InteractDirection.FORWARD, side ) ); - } - case 23: - { - // attackUp - TurtleSide side = parseSide( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.attack( InteractDirection.UP, side ) ); - } - case 24: - { - // attackDown - TurtleSide side = parseSide( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, TurtleToolCommand.attack( InteractDirection.DOWN, side ) ); - } - case 25: - { - // dropUp - int count = parseCount( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleDropCommand( InteractDirection.UP, count ) ); - } - case 26: - { - // dropDown - int count = parseCount( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleDropCommand( InteractDirection.DOWN, count ) ); - } - case 27: - { - // suck - int count = parseCount( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleSuckCommand( InteractDirection.FORWARD, count ) ); - } - case 28: - { - // suckUp - int count = parseCount( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleSuckCommand( InteractDirection.UP, count ) ); - } - case 29: - { - // suckDown - int count = parseCount( args, 0 ); - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleSuckCommand( InteractDirection.DOWN, count ) ); - } - case 30: // getFuelLevel - return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLevel() : "unlimited" }; - case 31: - { - // refuel - int count = optInt( args, 0, Integer.MAX_VALUE ); - if( count < 0 ) throw new LuaException( "Refuel count " + count + " out of range" ); - return tryCommand( context, new TurtleRefuelCommand( count ) ); - } - case 32: - { - // compareTo - int slot = parseSlotNumber( args, 0 ); - return tryCommand( context, new TurtleCompareToCommand( slot ) ); - } - case 33: - { - // transferTo - int slot = parseSlotNumber( args, 0 ); - int count = parseCount( args, 1 ); - return tryCommand( context, new TurtleTransferToCommand( slot, count ) ); - } - case 34: // getSelectedSlot - return new Object[] { m_turtle.getSelectedSlot() + 1 }; - case 35: // getFuelLimit - return new Object[] { m_turtle.isFuelNeeded() ? m_turtle.getFuelLimit() : "unlimited" }; - case 36: // equipLeft - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleEquipCommand( TurtleSide.LEFT ) ); - case 37: // equipRight - m_environment.addTrackingChange( TrackingField.TURTLE_OPS ); - return tryCommand( context, new TurtleEquipCommand( TurtleSide.RIGHT ) ); - case 38: // inspect - return tryCommand( context, new TurtleInspectCommand( InteractDirection.FORWARD ) ); - case 39: // inspectUp - return tryCommand( context, new TurtleInspectCommand( InteractDirection.UP ) ); - case 40: // inspectDown - return tryCommand( context, new TurtleInspectCommand( InteractDirection.DOWN ) ); - case 41: // getItemDetail - { - // FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...) - // on another thread. The obvious solution is to move this into a command, but some programs rely - // on this having a 0-tick delay. - int slot = parseOptionalSlotNumber( args, 0, m_turtle.getSelectedSlot() ); - ItemStack stack = m_turtle.getInventory().getStackInSlot( slot ); - if( stack.isEmpty() ) return new Object[] { null }; - - Item item = stack.getItem(); - String name = ForgeRegistries.ITEMS.getKey( item ).toString(); - int count = stack.getCount(); - - Map table = new HashMap<>(); - table.put( "name", name ); - table.put( "count", count ); - - TurtleActionEvent event = new TurtleInspectItemEvent( m_turtle, stack, table ); - if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() }; - - return new Object[] { table }; - } - - default: - return null; - } - } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 44ab1e5b8..28eaded9b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -8,8 +8,8 @@ package dan200.computercraft.shared.turtle.core; import com.google.common.base.Objects; import com.mojang.authlib.GameProfile; import dan200.computercraft.ComputerCraft; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.ILuaCallback; +import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; import dan200.computercraft.core.computer.ComputerSide; @@ -517,27 +517,13 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public Object[] executeCommand( @Nonnull ILuaContext context, @Nonnull ITurtleCommand command ) throws LuaException, InterruptedException + public MethodResult executeCommand( @Nonnull ITurtleCommand command ) { if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot run commands on the client" ); // Issue command int commandID = issueCommand( command ); - - // Wait for response - while( true ) - { - Object[] response = context.pullEvent( "turtle_response" ); - if( response.length >= 3 && response[1] instanceof Number && response[2] instanceof Boolean ) - { - if( ((Number) response[1]).intValue() == commandID ) - { - Object[] returnValues = new Object[response.length - 2]; - System.arraycopy( response, 2, returnValues, 0, returnValues.length ); - return returnValues; - } - } - } + return new CommandCallback( commandID ).pull; } @Override @@ -951,4 +937,29 @@ public class TurtleBrain implements ITurtleAccess float previous = (float) m_lastAnimationProgress / ANIM_DURATION; return previous + (next - previous) * f; } + + private static final class CommandCallback implements ILuaCallback + { + final MethodResult pull = MethodResult.pullEvent( "turtle_response", this ); + private final int command; + + CommandCallback( int command ) + { + this.command = command; + } + + @Nonnull + @Override + public MethodResult resume( Object[] response ) + { + if( response.length < 3 || !(response[1] instanceof Number) || !(response[2] instanceof Boolean) ) + { + return pull; + } + + if( ((Number) response[1]).intValue() != command ) return pull; + + return MethodResult.of( Arrays.copyOfRange( response, 2, response.length ) ); + } + } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index f33762694..9b5238f85 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -5,16 +5,15 @@ */ package dan200.computercraft.shared.turtle.upgrades; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.shared.turtle.core.TurtleCraftCommand; import javax.annotation.Nonnull; - -import static dan200.computercraft.api.lua.ArgumentHelper.optInt; +import java.util.Optional; public class CraftingTablePeripheral implements IPeripheral { @@ -32,41 +31,17 @@ public class CraftingTablePeripheral implements IPeripheral return "workbench"; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final MethodResult craft( Optional count ) throws LuaException { - return new String[] { - "craft", - }; - } - - private static int parseCount( Object[] arguments ) throws LuaException - { - int count = optInt( arguments, 0, 64 ); - if( count < 0 || count > 64 ) throw new LuaException( "Crafting count " + count + " out of range" ); - return count; - } - - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException - { - switch( method ) - { - case 0: - { - // craft - final int limit = parseCount( arguments ); - return turtle.executeCommand( context, new TurtleCraftCommand( limit ) ); - } - default: - return null; - } + int limit = count.orElse( 65 ); + if( limit < 0 || limit > 64 ) throw new LuaException( "Crafting count " + limit + " out of range" ); + return turtle.executeCommand( new TurtleCraftCommand( limit ) ); } @Override public boolean equals( IPeripheral other ) { - return this == other || other instanceof CraftingTablePeripheral; + return other instanceof CraftingTablePeripheral; } } diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index 57ea7d488..64a7f1e2d 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -5,6 +5,8 @@ */ package dan200.computercraft.shared.util; +import javax.annotation.Nullable; + public final class StringUtil { private StringUtil() {} @@ -31,16 +33,8 @@ public final class StringUtil return builder.toString(); } - public static byte[] encodeString( String string ) + public static String toString( @Nullable Object value ) { - byte[] chars = new byte[string.length()]; - - for( int i = 0; i < chars.length; i++ ) - { - char c = string.charAt( i ); - chars[i] = c < 256 ? (byte) c : 63; - } - - return chars; + return value == null ? "" : value.toString(); } } diff --git a/src/test/java/dan200/computercraft/ContramapMatcher.java b/src/test/java/dan200/computercraft/ContramapMatcher.java new file mode 100644 index 000000000..35e7117fa --- /dev/null +++ b/src/test/java/dan200/computercraft/ContramapMatcher.java @@ -0,0 +1,54 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeDiagnosingMatcher; + +import java.util.function.Function; + +public class ContramapMatcher extends TypeSafeDiagnosingMatcher +{ + private final String desc; + private final Function convert; + private final Matcher matcher; + + public ContramapMatcher( String desc, Function convert, Matcher matcher ) + { + this.desc = desc; + this.convert = convert; + this.matcher = matcher; + } + + @Override + protected boolean matchesSafely( T item, Description mismatchDescription ) + { + U converted = convert.apply( item ); + if( matcher.matches( converted ) ) return true; + + mismatchDescription.appendText( desc ).appendText( " " ); + matcher.describeMismatch( converted, mismatchDescription ); + return false; + } + + @Override + public void describeTo( Description description ) + { + description.appendText( desc ).appendText( " " ).appendDescriptionOf( 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 ); + } +} diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index f2d2453a7..91fdc4cad 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -8,8 +8,8 @@ package dan200.computercraft.core; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.BasicEnvironment; import dan200.computercraft.core.computer.Computer; @@ -44,8 +44,7 @@ import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Stream; -import static dan200.computercraft.api.lua.ArgumentHelper.getTable; -import static dan200.computercraft.api.lua.ArgumentHelper.getType; +import static dan200.computercraft.api.lua.LuaValues.getType; /** * Loads tests from {@code test-rom/spec} and executes them. @@ -107,189 +106,7 @@ public class ComputerTestDelegate computer = new Computer( new BasicEnvironment( mount ), term, 0 ); computer.getEnvironment().setPeripheral( ComputerSide.TOP, new FakeModem() ); - computer.addApi( new ILuaAPI() - { - @Override - public String[] getNames() - { - return new String[] { "cct_test" }; - } - - @Nonnull - @Override - public String[] getMethodNames() - { - return new String[] { "start", "submit", "finish" }; - } - - @Override - public void startup() - { - try - { - computer.getAPIEnvironment().getFileSystem().mount( - "test-rom", "test-rom", - BasicEnvironment.createMount( ComputerTestDelegate.class, "test-rom", "test" ) - ); - } - catch( FileSystemException e ) - { - throw new IllegalStateException( e ); - } - } - - @Nullable - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException - { - switch( method ) - { - case 0: // start: Submit several tests and signal for #get to run - { - LOG.info( "Received tests from computer" ); - DynamicNodeBuilder root = new DynamicNodeBuilder( "" ); - for( Object key : getTable( arguments, 0 ).keySet() ) - { - if( !(key instanceof String) ) throw new LuaException( "Non-key string " + getType( key ) ); - - String name = (String) key; - String[] parts = name.split( "\0" ); - DynamicNodeBuilder builder = root; - for( int i = 0; i < parts.length - 1; i++ ) builder = builder.get( parts[i] ); - builder.runs( parts[parts.length - 1], () -> { - // Run it - lock.lockInterruptibly(); - try - { - // Set the current test - runResult = null; - runFinished = false; - currentTest = name; - - // Tell the computer to run it - LOG.info( "Starting '{}'", formatName( name ) ); - computer.queueEvent( "cct_test_run", new Object[] { name } ); - - long remaining = TIMEOUT; - while( remaining > 0 && computer.isOn() && !runFinished ) - { - tick(); - - long waiting = hasRun.awaitNanos( TICK_TIME ); - if( waiting > 0 ) break; - remaining -= TICK_TIME; - } - - LOG.info( "Finished '{}'", formatName( name ) ); - - if( remaining <= 0 ) - { - throw new IllegalStateException( "Timed out waiting for test" ); - } - else if( !computer.isOn() ) - { - throw new IllegalStateException( "Computer turned off mid-execution" ); - } - - if( runResult != null ) throw runResult; - } - finally - { - lock.unlock(); - currentTest = null; - } - } ); - } - - lock.lockInterruptibly(); - try - { - tests = root; - hasTests.signal(); - } - finally - { - lock.unlock(); - } - - return null; - } - case 1: // submit: Submit the result of a test, allowing the test executor to continue - { - Map tbl = getTable( arguments, 0 ); - String name = (String) tbl.get( "name" ); - String status = (String) tbl.get( "status" ); - String message = (String) tbl.get( "message" ); - String trace = (String) tbl.get( "trace" ); - - StringBuilder wholeMessage = new StringBuilder(); - if( message != null ) wholeMessage.append( message ); - if( trace != null ) - { - if( wholeMessage.length() != 0 ) wholeMessage.append( '\n' ); - wholeMessage.append( trace ); - } - - lock.lockInterruptibly(); - try - { - LOG.info( "'{}' finished with {}", formatName( name ), status ); - - // Skip if a test mismatch - if( !name.equals( currentTest ) ) - { - LOG.warn( "Skipping test '{}', as we're currently executing '{}'", formatName( name ), formatName( currentTest ) ); - return null; - } - - switch( status ) - { - case "ok": - case "pending": - break; - case "fail": - runResult = new AssertionFailedError( wholeMessage.toString() ); - break; - case "error": - runResult = new IllegalStateException( wholeMessage.toString() ); - break; - } - - runFinished = true; - hasRun.signal(); - } - finally - { - lock.unlock(); - } - - return null; - } - case 2: // finish: Signal to after that execution has finished - LOG.info( "Finished" ); - lock.lockInterruptibly(); - try - { - finished = true; - if( arguments.length > 0 ) - { - @SuppressWarnings( "unchecked" ) - Map> finished = (Map>) arguments[0]; - finishedWith = finished; - } - - hasFinished.signal(); - } - finally - { - lock.unlock(); - } - return null; - default: - return null; - } - } - } ); + computer.addApi( new CctTestAPI() ); computer.turnOn(); } @@ -475,4 +292,198 @@ public class ComputerTestDelegate return this == other; } } + + public class CctTestAPI implements ILuaAPI + { + @Override + public String[] getNames() + { + return new String[] { "cct_test" }; + } + + @Override + public void startup() + { + try + { + computer.getAPIEnvironment().getFileSystem().mount( + "test-rom", "test-rom", + BasicEnvironment.createMount( ComputerTestDelegate.class, "test-rom", "test" ) + ); + } + catch( FileSystemException e ) + { + throw new IllegalStateException( e ); + } + } + + @LuaFunction + public final void start( Map tests ) throws LuaException + { + // Submit several tests and signal for #get to run + LOG.info( "Received tests from computer" ); + DynamicNodeBuilder root = new DynamicNodeBuilder( "" ); + for( Object key : tests.keySet() ) + { + if( !(key instanceof String) ) throw new LuaException( "Non-key string " + getType( key ) ); + + String name = (String) key; + String[] parts = name.split( "\0" ); + DynamicNodeBuilder builder = root; + for( int i = 0; i < parts.length - 1; i++ ) builder = builder.get( parts[i] ); + builder.runs( parts[parts.length - 1], () -> { + // Run it + lock.lockInterruptibly(); + try + { + // Set the current test + runResult = null; + runFinished = false; + currentTest = name; + + // Tell the computer to run it + LOG.info( "Starting '{}'", formatName( name ) ); + computer.queueEvent( "cct_test_run", new Object[] { name } ); + + long remaining = TIMEOUT; + while( remaining > 0 && computer.isOn() && !runFinished ) + { + tick(); + + long waiting = hasRun.awaitNanos( TICK_TIME ); + if( waiting > 0 ) break; + remaining -= TICK_TIME; + } + + LOG.info( "Finished '{}'", formatName( name ) ); + + if( remaining <= 0 ) + { + throw new IllegalStateException( "Timed out waiting for test" ); + } + else if( !computer.isOn() ) + { + throw new IllegalStateException( "Computer turned off mid-execution" ); + } + + if( runResult != null ) throw runResult; + } + finally + { + lock.unlock(); + currentTest = null; + } + } ); + } + + try + { + lock.lockInterruptibly(); + } + catch( InterruptedException e ) + { + throw new RuntimeException( e ); + } + try + { + ComputerTestDelegate.this.tests = root; + hasTests.signal(); + } + finally + { + lock.unlock(); + } + } + + @LuaFunction + public final void submit( Map tbl ) + { + // Submit the result of a test, allowing the test executor to continue + String name = (String) tbl.get( "name" ); + if( name == null ) + { + ComputerCraft.log.error( "Oh no: {}", tbl ); + } + String status = (String) tbl.get( "status" ); + String message = (String) tbl.get( "message" ); + String trace = (String) tbl.get( "trace" ); + + StringBuilder wholeMessage = new StringBuilder(); + if( message != null ) wholeMessage.append( message ); + if( trace != null ) + { + if( wholeMessage.length() != 0 ) wholeMessage.append( '\n' ); + wholeMessage.append( trace ); + } + + try + { + lock.lockInterruptibly(); + } + catch( InterruptedException e ) + { + throw new RuntimeException( e ); + } + try + { + LOG.info( "'{}' finished with {}", formatName( name ), status ); + + // Skip if a test mismatch + if( !name.equals( currentTest ) ) + { + LOG.warn( "Skipping test '{}', as we're currently executing '{}'", formatName( name ), formatName( currentTest ) ); + return; + } + + switch( status ) + { + case "ok": + case "pending": + break; + case "fail": + runResult = new AssertionFailedError( wholeMessage.toString() ); + break; + case "error": + runResult = new IllegalStateException( wholeMessage.toString() ); + break; + } + + runFinished = true; + hasRun.signal(); + } + finally + { + lock.unlock(); + } + } + + @LuaFunction + public final void finish( Optional> result ) + { + @SuppressWarnings( "unchecked" ) + Map> finishedResult = (Map>) result.orElse( null ); + LOG.info( "Finished" ); + + // Signal to after that execution has finished + try + { + lock.lockInterruptibly(); + } + catch( InterruptedException e ) + { + throw new RuntimeException( e ); + } + try + { + finished = true; + if( finishedResult != null ) finishedWith = finishedResult; + + hasFinished.signal(); + } + finally + { + lock.unlock(); + } + } + } } diff --git a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java index cd7684270..a01cc639a 100644 --- a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java +++ b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java @@ -5,52 +5,47 @@ */ package dan200.computercraft.core.apis; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.ILuaObject; -import dan200.computercraft.api.lua.ILuaTask; -import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.*; +import dan200.computercraft.core.asm.LuaMethod; +import dan200.computercraft.core.asm.NamedMethod; import javax.annotation.Nonnull; -import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; public class ObjectWrapper implements ILuaContext { - private final ILuaObject object; - private final String[] methods; + private final Object object; + private final Map methodMap; - public ObjectWrapper( ILuaObject object ) + public ObjectWrapper( Object object ) { this.object = object; - this.methods = object.getMethodNames(); - } + String[] dynamicMethods = object instanceof IDynamicLuaObject + ? Objects.requireNonNull( ((IDynamicLuaObject) object).getMethodNames(), "Methods cannot be null" ) + : LuaMethod.EMPTY_METHODS; - private int findMethod( String method ) - { - for( int i = 0; i < methods.length; i++ ) + List> methods = LuaMethod.GENERATOR.getMethods( object.getClass() ); + + Map methodMap = this.methodMap = new HashMap<>( methods.size() + dynamicMethods.length ); + for( int i = 0; i < dynamicMethods.length; i++ ) { - if( method.equals( methods[i] ) ) return i; + methodMap.put( dynamicMethods[i], LuaMethod.DYNAMIC.get( i ) ); + } + for( NamedMethod method : methods ) + { + methodMap.put( method.getName(), method.getMethod() ); } - return -1; - } - - public boolean hasMethod( String method ) - { - return findMethod( method ) >= 0; } public Object[] call( String name, Object... args ) throws LuaException { - int method = findMethod( name ); - if( method < 0 ) throw new IllegalStateException( "No such method '" + name + "'" ); + LuaMethod method = methodMap.get( name ); + if( method == null ) throw new IllegalStateException( "No such method '" + name + "'" ); - try - { - return object.callMethod( this, method, args ); - } - catch( InterruptedException e ) - { - throw new IllegalStateException( "Should never be interrupted", e ); - } + return method.apply( object, this, new ObjectArguments( args ) ).getResult(); } @SuppressWarnings( "unchecked" ) @@ -64,34 +59,6 @@ public class ObjectWrapper implements ILuaContext return klass.cast( call( name, args )[0] ); } - @Nonnull - @Override - public Object[] pullEvent( @Nullable String filter ) - { - throw new IllegalStateException( "Method should never yield" ); - } - - @Nonnull - @Override - public Object[] pullEventRaw( @Nullable String filter ) - { - throw new IllegalStateException( "Method should never yield" ); - } - - @Nonnull - @Override - public Object[] yield( @Nullable Object[] arguments ) - { - throw new IllegalStateException( "Method should never yield" ); - } - - @Nullable - @Override - public Object[] executeMainThreadTask( @Nonnull ILuaTask task ) - { - throw new IllegalStateException( "Method should never yield" ); - } - @Override public long issueMainThreadTask( @Nonnull ILuaTask task ) { diff --git a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java index 3def2ce9f..ad272c9aa 100644 --- a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java @@ -9,6 +9,7 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.core.apis.ObjectWrapper; import org.junit.jupiter.api.Test; +import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -27,17 +28,16 @@ public class BinaryReadableHandleTest public void testReadShortComplete() throws LuaException { ObjectWrapper wrapper = fromLength( 10 ); - assertEquals( 5, wrapper.callOf( "read", 5 ).length ); + assertEquals( 5, wrapper.callOf( "read", 5 ).remaining() ); } @Test public void testReadShortPartial() throws LuaException { ObjectWrapper wrapper = fromLength( 5 ); - assertEquals( 5, wrapper.callOf( "read", 10 ).length ); + assertEquals( 5, wrapper.callOf( "read", 10 ).remaining() ); } - @Test public void testReadLongComplete() throws LuaException { @@ -56,13 +56,13 @@ public class BinaryReadableHandleTest public void testReadLongPartialSmaller() throws LuaException { ObjectWrapper wrapper = fromLength( 1000 ); - assertEquals( 1000, wrapper.callOf( "read", 11000 ).length ); + assertEquals( 1000, wrapper.callOf( "read", 11000 ).remaining() ); } @Test public void testReadLine() throws LuaException { - ObjectWrapper wrapper = new ObjectWrapper( new BinaryReadableHandle( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) ); + ObjectWrapper wrapper = new ObjectWrapper( BinaryReadableHandle.of( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) ); assertArrayEquals( "hello".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine" ) ); assertArrayEquals( "world\r!".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine" ) ); assertNull( wrapper.call( "readLine" ) ); @@ -71,7 +71,7 @@ public class BinaryReadableHandleTest @Test public void testReadLineTrailing() throws LuaException { - ObjectWrapper wrapper = new ObjectWrapper( new BinaryReadableHandle( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) ); + ObjectWrapper wrapper = new ObjectWrapper( BinaryReadableHandle.of( new ArrayByteChannel( "hello\r\nworld\r!".getBytes( StandardCharsets.UTF_8 ) ) ) ); assertArrayEquals( "hello\r\n".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine", true ) ); assertArrayEquals( "world\r!".getBytes( StandardCharsets.UTF_8 ), wrapper.callOf( "readLine", true ) ); assertNull( wrapper.call( "readLine", true ) ); @@ -81,6 +81,6 @@ public class BinaryReadableHandleTest { byte[] input = new byte[length]; Arrays.fill( input, (byte) 'A' ); - return new ObjectWrapper( new BinaryReadableHandle( new ArrayByteChannel( input ) ) ); + return new ObjectWrapper( BinaryReadableHandle.of( new ArrayByteChannel( input ) ) ); } } diff --git a/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java b/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java new file mode 100644 index 000000000..8104fa4a1 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java @@ -0,0 +1,253 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.*; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.core.computer.ComputerSide; +import org.hamcrest.Matcher; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static dan200.computercraft.ContramapMatcher.contramap; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class GeneratorTest +{ + @Test + public void testBasic() + { + List> methods = LuaMethod.GENERATOR.getMethods( Basic.class ); + assertThat( methods, contains( + allOf( + named( "go" ), + contramap( is( true ), "non-yielding", NamedMethod::nonYielding ) + ) + ) ); + } + + @Test + public void testIdentical() + { + List> methods = LuaMethod.GENERATOR.getMethods( Basic.class ); + List> methods2 = LuaMethod.GENERATOR.getMethods( Basic.class ); + assertThat( methods, sameInstance( methods2 ) ); + } + + @Test + public void testIdenticalMethods() + { + List> methods = LuaMethod.GENERATOR.getMethods( Basic.class ); + List> methods2 = LuaMethod.GENERATOR.getMethods( Basic2.class ); + assertThat( methods, contains( named( "go" ) ) ); + assertThat( methods.get( 0 ).getMethod(), sameInstance( methods2.get( 0 ).getMethod() ) ); + } + + @Test + public void testEmptyClass() + { + assertThat( LuaMethod.GENERATOR.getMethods( Empty.class ), is( empty() ) ); + } + + @Test + public void testNonPublicClass() + { + assertThat( LuaMethod.GENERATOR.getMethods( NonPublic.class ), is( empty() ) ); + } + + @Test + public void testNonInstance() + { + assertThat( LuaMethod.GENERATOR.getMethods( NonInstance.class ), is( empty() ) ); + } + + @Test + public void testIllegalThrows() + { + assertThat( LuaMethod.GENERATOR.getMethods( IllegalThrows.class ), is( empty() ) ); + } + + @Test + public void testCustomNames() + { + List> methods = LuaMethod.GENERATOR.getMethods( CustomNames.class ); + assertThat( methods, contains( named( "go1" ), named( "go2" ) ) ); + } + + @Test + public void testArgKinds() + { + List> methods = LuaMethod.GENERATOR.getMethods( ArgKinds.class ); + assertThat( methods, containsInAnyOrder( + named( "objectArg" ), named( "intArg" ), named( "optIntArg" ), + named( "context" ), named( "arguments" ) + ) ); + } + + @Test + public void testEnum() throws LuaException + { + List> methods = LuaMethod.GENERATOR.getMethods( EnumMethods.class ); + assertThat( methods, containsInAnyOrder( named( "getEnum" ), named( "optEnum" ) ) ); + + assertThat( apply( methods, new EnumMethods(), "getEnum", "front" ), one( is( "FRONT" ) ) ); + assertThat( apply( methods, new EnumMethods(), "optEnum", "front" ), one( is( "FRONT" ) ) ); + assertThat( apply( methods, new EnumMethods(), "optEnum" ), one( is( "?" ) ) ); + assertThrows( LuaException.class, () -> apply( methods, new EnumMethods(), "getEnum", "not as side" ) ); + } + + @Test + public void testMainThread() throws LuaException + { + List> methods = LuaMethod.GENERATOR.getMethods( MainThread.class ); + assertThat( methods, contains( allOf( + named( "go" ), + contramap( is( false ), "non-yielding", NamedMethod::nonYielding ) + ) ) ); + + assertThat( apply( methods, new MainThread(), "go" ), + contramap( notNullValue(), "callback", MethodResult::getCallback ) ); + } + + public static class Basic + { + @LuaFunction + public final void go() + { } + } + + public static class Basic2 extends Basic + { + } + + public static class Empty + { + } + + static class NonPublic + { + @LuaFunction + public final void go() + { } + } + + public static class NonInstance + { + @LuaFunction + public static void go() + { } + } + + public static class IllegalThrows + { + @LuaFunction + public final void go() throws IOException + { + throw new IOException(); + } + } + + public static class CustomNames + { + @LuaFunction( { "go1", "go2" } ) + public final void go() + { } + } + + public static class ArgKinds + { + @LuaFunction + public final void objectArg( Object arg ) + { } + + @LuaFunction + public final void intArg( int arg ) + { } + + @LuaFunction + public final void optIntArg( Optional arg ) + { } + + @LuaFunction + public final void context( ILuaContext arg ) + { } + + @LuaFunction + public final void arguments( IArguments arg ) + { } + + @LuaFunction + public final void unknown( IComputerAccess arg ) + { } + + @LuaFunction + public final void illegalMap( Map arg ) + { } + + @LuaFunction + public final void optIllegalMap( Optional> arg ) + { } + } + + public static class EnumMethods + { + @LuaFunction + public final String getEnum( ComputerSide side ) + { + return side.name(); + } + + @LuaFunction + public final String optEnum( Optional side ) + { + return side.map( ComputerSide::name ).orElse( "?" ); + } + } + + public static class MainThread + { + @LuaFunction( mainThread = true ) + public final void go() + { } + } + + private static T find( Collection> methods, String name ) + { + return methods.stream() + .filter( x -> x.getName().equals( name ) ) + .map( NamedMethod::getMethod ) + .findAny() + .orElseThrow( NullPointerException::new ); + } + + public static MethodResult apply( Collection> methods, Object instance, String name, Object... args ) throws LuaException + { + return find( methods, name ).apply( instance, CONTEXT, new ObjectArguments( args ) ); + } + + public static Matcher one( Matcher object ) + { + return allOf( + contramap( nullValue(), "callback", MethodResult::getCallback ), + contramap( array( object ), "result", MethodResult::getResult ) + ); + } + + public static Matcher> named( String method ) + { + return contramap( is( method ), "name", NamedMethod::getName ); + } + + private static final ILuaContext CONTEXT = task -> 0; +} diff --git a/src/test/java/dan200/computercraft/core/asm/MethodTest.java b/src/test/java/dan200/computercraft/core/asm/MethodTest.java new file mode 100644 index 000000000..58be91ecd --- /dev/null +++ b/src/test/java/dan200/computercraft/core/asm/MethodTest.java @@ -0,0 +1,208 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.api.lua.*; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.computer.ComputerBootstrap; +import dan200.computercraft.core.computer.ComputerSide; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Collections; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +public class MethodTest +{ + @Test + public void testMainThread() + { + ComputerBootstrap.run( "assert(main_thread.go() == 123)", x -> x.addApi( new MainThread() ), 50 ); + } + + @Test + public void testMainThreadPeripheral() + { + ComputerBootstrap.run( "assert(peripheral.call('top', 'go') == 123)", + x -> x.getEnvironment().setPeripheral( ComputerSide.TOP, new MainThread() ), + 50 ); + } + + @Test + public void testDynamic() + { + ComputerBootstrap.run( + "assert(dynamic.foo() == 123, 'foo: ' .. tostring(dynamic.foo()))\n" + + "assert(dynamic.bar() == 321, 'bar: ' .. tostring(dynamic.bar()))", + x -> x.addApi( new Dynamic() ), 50 ); + } + + @Test + public void testDynamicPeripheral() + { + ComputerBootstrap.run( + "local dynamic = peripheral.wrap('top')\n" + + "assert(dynamic.foo() == 123, 'foo: ' .. tostring(dynamic.foo()))\n" + + "assert(dynamic.bar() == 321, 'bar: ' .. tostring(dynamic.bar()))", + x -> x.getEnvironment().setPeripheral( ComputerSide.TOP, new Dynamic() ), + 50 + ); + } + + @Test + public void testExtra() + { + ComputerBootstrap.run( "assert(extra.go, 'go')\nassert(extra.go2, 'go2')", + x -> x.addApi( new ExtraObject() ), + 50 ); + } + + @Test + public void testPeripheralThrow() + { + ComputerBootstrap.run( + "local throw = peripheral.wrap('top')\n" + + "local _, err = pcall(throw.thisThread) assert(err == 'pcall: !', err)\n" + + "local _, err = pcall(throw.mainThread) assert(err == 'pcall: !', err)", + x -> x.getEnvironment().setPeripheral( ComputerSide.TOP, new PeripheralThrow() ), + 50 + ); + } + + public static class MainThread implements ILuaAPI, IPeripheral + { + public final String thread = Thread.currentThread().getName(); + + @Override + public String[] getNames() + { + return new String[] { "main_thread" }; + } + + @LuaFunction( mainThread = true ) + public final int go() + { + assertThat( Thread.currentThread().getName(), is( thread ) ); + return 123; + } + + @Nonnull + @Override + public String getType() + { + return "main_thread"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + public static class Dynamic implements IDynamicLuaObject, ILuaAPI, IDynamicPeripheral + { + @Nonnull + @Override + public String[] getMethodNames() + { + return new String[] { "foo" }; + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) + { + return MethodResult.of( 123 ); + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) + { + return callMethod( context, method, arguments ); + } + + @LuaFunction + public final int bar() + { + return 321; + } + + @Override + public String[] getNames() + { + return new String[] { "dynamic" }; + } + + @Nonnull + @Override + public String getType() + { + return "dynamic"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } + + public static class ExtraObject implements ObjectSource, ILuaAPI + { + @Override + public String[] getNames() + { + return new String[] { "extra" }; + } + + @LuaFunction + public final void go2() + { + } + + @Override + public Iterable getExtra() + { + return Collections.singletonList( new GeneratorTest.Basic() ); + } + } + + public static class PeripheralThrow implements IPeripheral + { + @LuaFunction + public final void thisThread() throws LuaException + { + throw new LuaException( "!" ); + } + + @LuaFunction( mainThread = true ) + public final void mainThread() throws LuaException + { + throw new LuaException( "!" ); + } + + @Nonnull + @Override + public String getType() + { + return "throw"; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + return this == other; + } + } +} diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 6ac8a7b55..e2deba3cb 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -7,16 +7,14 @@ package dan200.computercraft.core.computer; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.ILuaAPI; -import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.ArgumentHelper; +import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.core.filesystem.MemoryMount; import dan200.computercraft.core.terminal.Terminal; import org.junit.jupiter.api.Assertions; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.Arrays; import java.util.function.Consumer; @@ -26,20 +24,26 @@ import java.util.function.Consumer; public class ComputerBootstrap { private static final int TPS = 20; - private static final int MAX_TIME = 10; + public static final int MAX_TIME = 10; - public static void run( String program ) + public static void run( String program, Consumer setup, int maxTimes ) { MemoryMount mount = new MemoryMount() .addFile( "test.lua", program ) - .addFile( "startup", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()" ); + .addFile( "startup.lua", "assertion.assert(pcall(loadfile('test.lua', nil, _ENV))) os.shutdown()" ); - run( mount, x -> { } ); + run( mount, setup, maxTimes ); } - public static void run( IWritableMount mount, Consumer setup ) + public static void run( String program, int maxTimes ) + { + run( program, x -> { }, maxTimes ); + } + + public static void run( IWritableMount mount, Consumer setup, int maxTicks ) { ComputerCraft.logPeripheralErrors = true; + ComputerCraft.maxMainComputerTime = ComputerCraft.maxMainGlobalTime = Integer.MAX_VALUE; Terminal term = new Terminal( ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); final Computer computer = new Computer( new BasicEnvironment( mount ), term, 0 ); @@ -54,7 +58,7 @@ public class ComputerBootstrap computer.turnOn(); boolean everOn = false; - for( int tick = 0; tick < TPS * MAX_TIME; tick++ ) + for( int tick = 0; tick < TPS * maxTicks; tick++ ) { long start = System.currentTimeMillis(); @@ -99,7 +103,7 @@ public class ComputerBootstrap } } - private static class AssertApi implements ILuaAPI + public static class AssertApi implements ILuaAPI { boolean didAssert; String message; @@ -110,39 +114,25 @@ public class ComputerBootstrap return new String[] { "assertion" }; } - @Nonnull - @Override - public String[] getMethodNames() + @LuaFunction + public final void log( IArguments arguments ) { - return new String[] { "assert", "log" }; + ComputerCraft.log.info( "[Computer] {}", Arrays.toString( arguments.getAll() ) ); } - @Nullable - @Override - public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + @LuaFunction( "assert" ) + public final Object[] doAssert( IArguments arguments ) throws LuaException { - switch( method ) + didAssert = true; + + Object arg = arguments.get( 0 ); + if( arg == null || arg == Boolean.FALSE ) { - case 0: // assert - { - didAssert = true; - - Object arg = arguments.length >= 1 ? arguments[0] : null; - if( arg == null || arg == Boolean.FALSE ) - { - message = ArgumentHelper.optString( arguments, 1, "Assertion failed" ); - throw new LuaException( message ); - } - - return arguments; - } - case 1: - ComputerCraft.log.info( "[Computer] {}", Arrays.toString( arguments ) ); - return null; - - default: - return null; + message = arguments.optString( 1, "Assertion failed" ); + throw new LuaException( message ); } + + return arguments.getAll(); } } } diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java index d2d6d744c..830e27305 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java @@ -5,9 +5,15 @@ */ package dan200.computercraft.core.computer; +import com.google.common.io.CharStreams; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + import static java.time.Duration.ofSeconds; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; @@ -19,7 +25,7 @@ public class ComputerTest assertTimeoutPreemptively( ofSeconds( 20 ), () -> { try { - ComputerBootstrap.run( "print('Hello') while true do end" ); + ComputerBootstrap.run( "print('Hello') while true do end", ComputerBootstrap.MAX_TIME ); } catch( AssertionError e ) { @@ -30,4 +36,14 @@ public class ComputerTest Assertions.fail( "Expected computer to timeout" ); } ); } + + public static void main( String[] args ) throws Exception + { + InputStream stream = ComputerTest.class.getClassLoader().getResourceAsStream( "benchmark.lua" ); + try( InputStreamReader reader = new InputStreamReader( Objects.requireNonNull( stream ), StandardCharsets.UTF_8 ) ) + { + String contents = CharStreams.toString( reader ); + ComputerBootstrap.run( contents, 1000 ); + } + } } diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java index deb403e5a..73aaaccda 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -27,8 +27,8 @@ public class FileSystemTest * Ensures writing a file truncates it. * * @throws FileSystemException When the file system cannot be constructed. - * @throws LuaException When Lua functions fail. - * @throws IOException When reading and writing from strings + * @throws LuaException When Lua functions fail. + * @throws IOException When reading and writing from strings */ @Test public void testWriteTruncates() throws FileSystemException, LuaException, IOException diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 829432c83..174558001 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -8,13 +8,10 @@ package dan200.computercraft.shared.wired; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import dan200.computercraft.api.ComputerCraftAPI; -import dan200.computercraft.api.lua.ILuaContext; -import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNetwork; import dan200.computercraft.api.network.wired.IWiredNetworkChange; import dan200.computercraft.api.network.wired.IWiredNode; -import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.util.DirectionUtil; import net.minecraft.util.Direction; @@ -397,20 +394,6 @@ public class NetworkTest return "test"; } - @Nonnull - @Override - public String[] getMethodNames() - { - return new String[0]; - } - - @Nullable - @Override - public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException - { - return new Object[0]; - } - @Override public boolean equals( @Nullable IPeripheral other ) { diff --git a/src/test/resources/benchmark.lua b/src/test/resources/benchmark.lua new file mode 100644 index 000000000..dbbef23a1 --- /dev/null +++ b/src/test/resources/benchmark.lua @@ -0,0 +1,24 @@ +local function log(msg) + print(msg) + if assertion then assertion.log(msg) end +end + +local function run(name, n, f, ...) + sleep(0) + local s = os.epoch("utc") + for _ = 1, n do f(...) end + local e = os.epoch("utc") - s + log(("%10s %.2fs %.fop/s"):format(name, e*1e-3, n/e)) +end + +local function run5(...) for _ = 1, 5 do run(...) end end + +local native = term.native() +local x, y = native.getCursorPos() + +log("Starting the benchmark") +run5("redstone.getAnalogInput", 1e7, redstone.getAnalogInput, "top") +run5("term.getCursorPos", 2e7, native.getCursorPos) +run5("term.setCursorPos", 2e7, native.setCursorPos, x, y) + +if assertion then assertion.assert(true) end diff --git a/src/test/resources/test-rom/spec/apis/redstone_spec.lua b/src/test/resources/test-rom/spec/apis/redstone_spec.lua index 17d8acab0..148d08700 100644 --- a/src/test/resources/test-rom/spec/apis/redstone_spec.lua +++ b/src/test/resources/test-rom/spec/apis/redstone_spec.lua @@ -2,7 +2,7 @@ local function it_side(func, ...) local arg = table.pack(...) it("requires a specific side", function() expect.error(func, 0):eq("bad argument #1 (string expected, got number)") - expect.error(func, "blah", table.unpack(arg)):eq("Invalid side.") + expect.error(func, "blah", table.unpack(arg)):eq("bad argument #1 (unknown option blah)") func("top", table.unpack(arg)) func("Top", table.unpack(arg)) From 5409d441b5ef49c4b86db11f73c80bc3c67af4c9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 17:09:12 +0100 Subject: [PATCH 234/711] Expose peripherals as a capability This registers IPeripheral as a capability. As a result, all (Minecraft facing) functionality operates using LazyOptional<_>s instead. Peripheral providers should now return a LazyOptional too. Hopefully this will allow custom peripherals to mark themselves as invalid (say, because a dependency has changed). While peripheral providers are somewhat redundant, they still have their usages. If a peripheral is applied to a large number of blocks (for instance, all inventories) then using capabilities does incur some memory overhead. We also make the following changes based on the above: - Remove the default implementation for IWiredElement, migrating the definition to a common "Capabilities" class. - Remove IPeripheralTile - we'll exclusively use capabilities now. Absurdly this is the most complex change, as all TEs needed to be migrated too. I'm not 100% sure of the correctness of this changes so far - I've tested it pretty well, but blocks with more complex peripheral logic (wired/wireless modems and turtles) are still a little messy. - Remove the "command block" peripheral provider, attaching a capability instead. --- config/checkstyle/checkstyle.xml | 4 +- .../computercraft/ComputerCraftAPIImpl.java | 5 +- .../api/peripheral/IPeripheral.java | 8 +- .../api/peripheral/IPeripheralProvider.java | 11 +- .../api/peripheral/IPeripheralTile.java | 32 ------ .../computercraft/shared/Capabilities.java | 25 +++++ .../computercraft/shared/Peripherals.java | 26 ++++- .../shared/common/BlockGeneric.java | 6 +- .../computer/blocks/ComputerPeripheral.java | 2 +- .../shared/computer/blocks/ComputerProxy.java | 16 ++- .../shared/computer/blocks/TileComputer.java | 52 +++++---- .../computer/blocks/TileComputerBase.java | 26 ++--- .../commandblock/CommandBlockPeripheral.java | 49 ++++++++- .../peripheral/diskdrive/TileDiskDrive.java | 30 +++--- .../modem/wired/CableModemVariant.java | 2 + .../peripheral/modem/wired/TileCable.java | 90 +++++++++------- .../modem/wired/TileWiredModemFull.java | 101 +++++++++--------- .../wired/WiredModemLocalPeripheral.java | 13 ++- .../modem/wireless/TileWirelessModem.java | 48 +++++---- .../peripheral/monitor/TileMonitor.java | 37 +++++-- .../peripheral/printer/TilePrinter.java | 54 +++------- .../peripheral/speaker/TileSpeaker.java | 33 ++++-- .../proxy/ComputerCraftProxyCommon.java | 25 ++--- .../shared/turtle/blocks/TileTurtle.java | 31 +++--- .../shared/turtle/core/TurtleBrain.java | 21 +--- .../shared/util/CapabilityUtil.java | 47 ++++++++ .../shared/util/NullStorage.java | 25 +++++ .../computercraft/shared/util/SidedCaps.java | 68 ++++++++++++ .../shared/wired/CapabilityWiredElement.java | 87 --------------- 29 files changed, 567 insertions(+), 407 deletions(-) delete mode 100644 src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java create mode 100644 src/main/java/dan200/computercraft/shared/Capabilities.java create mode 100644 src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java create mode 100644 src/main/java/dan200/computercraft/shared/util/NullStorage.java create mode 100644 src/main/java/dan200/computercraft/shared/util/SidedCaps.java delete mode 100644 src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 6cc5fe765..03959f78e 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -114,11 +114,11 @@ - + - + diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index f8bf288d8..1610ea5fb 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -24,7 +24,6 @@ import dan200.computercraft.core.filesystem.ResourceMount; import dan200.computercraft.shared.*; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.util.IDAssigner; -import dan200.computercraft.shared.wired.CapabilityWiredElement; import dan200.computercraft.shared.wired.WiredNode; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.tileentity.TileEntity; @@ -41,6 +40,8 @@ import java.io.File; import java.lang.ref.WeakReference; import java.util.Map; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT; + public final class ComputerCraftAPIImpl implements IComputerCraftAPI { public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl(); @@ -147,6 +148,6 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI public LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side ) { TileEntity tile = world.getTileEntity( pos ); - return tile == null ? LazyOptional.empty() : tile.getCapability( CapabilityWiredElement.CAPABILITY, side ); + return tile == null ? LazyOptional.empty() : tile.getCapability( CAPABILITY_WIRED_ELEMENT, side ); } } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index a361848c3..04cfa6440 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -6,13 +6,17 @@ package dan200.computercraft.api.peripheral; import dan200.computercraft.api.lua.LuaFunction; +import net.minecraftforge.common.capabilities.Capability; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * The interface that defines a peripheral. See {@link IPeripheralProvider} for how to associate blocks with - * peripherals. + * The interface that defines a peripheral. + * + * In order to expose a peripheral for your block or tile entity, you may either attach a {@link Capability}, or + * register a {@link IPeripheralProvider}. It is not recommended to implement {@link IPeripheral} directly on + * the tile. * * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing * {@link IDynamicPeripheral}. diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index 3df8aa708..2be4f613e 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -9,14 +9,15 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * This interface is used to create peripheral implementations for blocks. * - * If you have a {@link TileEntity} which acts as a peripheral, you may alternatively implement {@link IPeripheralTile}. + * If you have a {@link TileEntity} which acts as a peripheral, you may alternatively expose the {@link IPeripheral} + * capability. * * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ @@ -29,9 +30,9 @@ public interface IPeripheralProvider * @param world The world the block is in. * @param pos The position the block is at. * @param side The side to get the peripheral from. - * @return A peripheral, or {@code null} if there is not a peripheral here you'd like to handle. + * @return A peripheral, or {@link LazyOptional#empty()} if there is not a peripheral here you'd like to handle. * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ - @Nullable - IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); + @Nonnull + LazyOptional getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java deleted file mode 100644 index ce64116c2..000000000 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. - * For help using the API, and posting your mods, visit the forums at computercraft.info. - */ -package dan200.computercraft.api.peripheral; - -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * A {@link net.minecraft.tileentity.TileEntity} which may act as a peripheral. - * - * If you need more complex capabilities (such as handling TEs not belonging to your mod), you should use - * {@link IPeripheralProvider}. - */ -public interface IPeripheralTile -{ - /** - * Get the peripheral on the given {@code side}. - * - * @param side The side to get the peripheral from. - * @return A peripheral, or {@code null} if there is not a peripheral here. - * @see IPeripheralProvider#getPeripheral(World, BlockPos, Direction) - */ - @Nullable - IPeripheral getPeripheral( @Nonnull Direction side ); -} diff --git a/src/main/java/dan200/computercraft/shared/Capabilities.java b/src/main/java/dan200/computercraft/shared/Capabilities.java new file mode 100644 index 000000000..ba820e183 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/Capabilities.java @@ -0,0 +1,25 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared; + +import dan200.computercraft.api.network.wired.IWiredElement; +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityInject; + +public final class Capabilities +{ + @CapabilityInject( IPeripheral.class ) + public static Capability CAPABILITY_PERIPHERAL = null; + + @CapabilityInject( IWiredElement.class ) + public static Capability CAPABILITY_WIRED_ELEMENT = null; + + private Capabilities() + { + } +} diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 021884d71..aae2b9d6d 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -8,15 +8,22 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.shared.util.CapabilityUtil; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullConsumer; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collection; import java.util.LinkedHashSet; import java.util.Objects; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + public final class Peripherals { private static final Collection providers = new LinkedHashSet<>(); @@ -29,20 +36,29 @@ public final class Peripherals providers.add( provider ); } - public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side ) + @Nullable + public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side, NonNullConsumer> invalidate ) { - return World.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side ) : null; + return World.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side, invalidate ) : null; } - private static IPeripheral getPeripheralAt( World world, BlockPos pos, Direction side ) + @Nullable + private static IPeripheral getPeripheralAt( World world, BlockPos pos, Direction side, NonNullConsumer> invalidate ) { + TileEntity block = world.getTileEntity( pos ); + if( block != null ) + { + LazyOptional peripheral = block.getCapability( CAPABILITY_PERIPHERAL, side ); + if( peripheral.isPresent() ) return CapabilityUtil.unwrap( peripheral, invalidate ); + } + // Try the handlers in order: for( IPeripheralProvider peripheralProvider : providers ) { try { - IPeripheral peripheral = peripheralProvider.getPeripheral( world, pos, side ); - if( peripheral != null ) return peripheral; + LazyOptional peripheral = peripheralProvider.getPeripheral( world, pos, side ); + if( peripheral.isPresent() ) return CapabilityUtil.unwrap( peripheral, invalidate ); } catch( Exception e ) { diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index 81a4f45f5..b7cad192e 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -50,7 +50,7 @@ public abstract class BlockGeneric extends Block @Nonnull @Override @Deprecated - public final ActionResultType onBlockActivated( BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit ) + public final ActionResultType onBlockActivated( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull PlayerEntity player, @Nonnull Hand hand, @Nonnull BlockRayTraceResult hit ) { TileEntity tile = world.getTileEntity( pos ); return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : ActionResultType.PASS; @@ -58,7 +58,7 @@ public abstract class BlockGeneric extends Block @Override @Deprecated - public final void neighborChanged( BlockState state, World world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving ) + public final void neighborChanged( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, @Nonnull BlockPos neighbourPos, boolean isMoving ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourChange( neighbourPos ); @@ -73,7 +73,7 @@ public abstract class BlockGeneric extends Block @Override @Deprecated - public void tick( BlockState state, ServerWorld world, BlockPos pos, Random rand ) + public void tick( @Nonnull BlockState state, ServerWorld world, @Nonnull BlockPos pos, @Nonnull Random rand ) { TileEntity te = world.getTileEntity( pos ); if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick(); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java index 71b394256..15c3395b9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java @@ -67,7 +67,7 @@ public class ComputerPeripheral implements IPeripheral @Override public boolean equals( IPeripheral other ) { - return other != null && other.getClass() == getClass(); + return other instanceof ComputerPeripheral && computer == ((ComputerPeripheral) other).computer; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java index 810d72c57..205161aeb 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java @@ -8,12 +8,24 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.ServerComputer; +import java.util.function.Supplier; + /** * A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate. */ -public abstract class ComputerProxy +public final class ComputerProxy { - protected abstract TileComputerBase getTile(); + private final Supplier get; + + public ComputerProxy( Supplier get ) + { + this.get = get; + } + + protected TileComputerBase getTile() + { + return get.get(); + } public void turnOn() { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 1ac0c94ad..34a768af3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -6,11 +6,13 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; +import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -19,10 +21,14 @@ import net.minecraft.inventory.container.Container; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + public class TileComputer extends TileComputerBase { public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( @@ -35,7 +41,8 @@ public class TileComputer extends TileComputerBase f -> new TileComputer( ComputerFamily.ADVANCED, f ) ); - private ComputerProxy m_proxy; + private ComputerProxy proxy; + private LazyOptional peripheral; public TileComputer( ComputerFamily family, TileEntityType type ) { @@ -55,23 +62,6 @@ public class TileComputer extends TileComputerBase return computer; } - @Override - public ComputerProxy createProxy() - { - if( m_proxy == null ) - { - m_proxy = new ComputerProxy() - { - @Override - protected TileComputerBase getTile() - { - return TileComputer.this; - } - }; - } - return m_proxy; - } - public boolean isUsableByPlayer( PlayerEntity player ) { return isUsable( player, false ); @@ -109,4 +99,30 @@ public class TileComputer extends TileComputerBase { return new ContainerComputer( id, this ); } + + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) + { + if( cap == CAPABILITY_PERIPHERAL ) + { + if( peripheral == null ) + { + peripheral = LazyOptional.of( () -> { + if( proxy == null ) proxy = new ComputerProxy( () -> this ); + return new ComputerPeripheral( "computer", proxy ); + } ); + } + return peripheral.cast(); + } + + return super.getCapability( cap, side ); + } + + @Override + protected void invalidateCaps() + { + super.invalidateCaps(); + peripheral = CapabilityUtil.invalidate( peripheral ); + } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 652700e9a..9bf2df439 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.BundledRedstone; import dan200.computercraft.shared.Peripherals; @@ -45,7 +44,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; -public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickableTileEntity, IPeripheralTile, INameable, INamedContainerProvider +public abstract class TileComputerBase extends TileGeneric implements IComputerTile, ITickableTileEntity, INameable, INamedContainerProvider { private static final String NBT_ID = "ComputerId"; private static final String NBT_LABEL = "Label"; @@ -226,7 +225,8 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); if( !isPeripheralBlockedOnSide( localDir ) ) { - computer.setPeripheral( localDir, Peripherals.getPeripheral( getWorld(), offset, offsetSide ) ); + IPeripheral peripheral = Peripherals.getPeripheral( getWorld(), offset, offsetSide, o -> updateInput( dir ) ); + computer.setPeripheral( localDir, peripheral ); } } @@ -272,7 +272,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT ServerComputer computer = getServerComputer(); if( computer == null ) return; - BlockPos pos = computer.getPosition(); for( Direction dir : DirectionUtil.FACINGS ) { BlockPos offset = pos.offset( dir ); @@ -287,6 +286,16 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT updateInput(); } + private void updateInput( Direction dir ) + { + if( getWorld() == null || getWorld().isRemote ) return; + + ServerComputer computer = getServerComputer(); + if( computer == null ) return; + + updateSideInput( computer, dir, pos.offset( dir ) ); + } + public void updateOutput() { // Update redstone @@ -299,8 +308,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT protected abstract ServerComputer createComputer( int instanceID, int id ); - public abstract ComputerProxy createProxy(); - @Override public final int getComputerID() { @@ -404,13 +411,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT copy.m_instanceID = -1; } - @Nullable - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) - { - return new ComputerPeripheral( "computer", createProxy() ); - } - @Nonnull @Override public ITextComponent getName() diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index 383f65f62..1ba941959 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -5,15 +5,33 @@ */ package dan200.computercraft.shared.peripheral.commandblock; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.util.CapabilityUtil; import net.minecraft.tileentity.CommandBlockTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.event.AttachCapabilitiesEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; import javax.annotation.Nonnull; +import javax.annotation.Nullable; -public class CommandBlockPeripheral implements IPeripheral +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + +@Mod.EventBusSubscriber +public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider { + private static final ResourceLocation CAP_ID = new ResourceLocation( ComputerCraft.MOD_ID, "command_block" ); + private final CommandBlockTileEntity commandBlock; + private LazyOptional self; public CommandBlockPeripheral( CommandBlockTileEntity commandBlock ) { @@ -53,4 +71,33 @@ public class CommandBlockPeripheral implements IPeripheral { return other != null && other.getClass() == getClass(); } + + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) + { + if( cap == CAPABILITY_PERIPHERAL ) + { + if( self == null ) self = LazyOptional.of( () -> this ); + return self.cast(); + } + return LazyOptional.empty(); + } + + private void invalidate() + { + self = CapabilityUtil.invalidate( self ); + } + + @SubscribeEvent + public static void onCapability( AttachCapabilitiesEvent event ) + { + TileEntity tile = event.getObject(); + if( tile instanceof CommandBlockTileEntity ) + { + CommandBlockPeripheral peripheral = new CommandBlockPeripheral( (CommandBlockTileEntity) tile ); + event.addCapability( CAP_ID, peripheral ); + event.addListener( peripheral::invalidate ); + } + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index a6337d1dc..fbbfc4bef 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -11,13 +11,9 @@ import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.util.DefaultInventory; -import dan200.computercraft.shared.util.InventoryUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; -import dan200.computercraft.shared.util.RecordUtil; +import dan200.computercraft.shared.util.*; import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; @@ -45,9 +41,10 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; -public final class TileDiskDrive extends TileGeneric implements DefaultInventory, ITickableTileEntity, IPeripheralTile, INameable, INamedContainerProvider +public final class TileDiskDrive extends TileGeneric implements DefaultInventory, ITickableTileEntity, INameable, INamedContainerProvider { private static final String NBT_NAME = "CustomName"; private static final String NBT_ITEM = "Item"; @@ -69,6 +66,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull private ItemStack m_diskStack = ItemStack.EMPTY; private LazyOptional itemHandlerCap; + private LazyOptional peripheralCap; private IMount m_diskMount = null; private boolean m_recordQueued = false; @@ -92,11 +90,8 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory protected void invalidateCaps() { super.invalidateCaps(); - if( itemHandlerCap != null ) - { - itemHandlerCap.invalidate(); - itemHandlerCap = null; - } + itemHandlerCap = CapabilityUtil.invalidate( itemHandlerCap ); + peripheralCap = CapabilityUtil.invalidate( peripheralCap ); } @Nonnull @@ -313,12 +308,6 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory setInventorySlotContents( 0, ItemStack.EMPTY ); } - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) - { - return new DiskDrivePeripheral( this ); - } - @Nonnull ItemStack getDiskStack() { @@ -535,6 +524,13 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory if( itemHandlerCap == null ) itemHandlerCap = LazyOptional.of( () -> new InvWrapper( this ) ); return itemHandlerCap.cast(); } + + if( cap == CAPABILITY_PERIPHERAL ) + { + if( peripheralCap == null ) peripheralCap = LazyOptional.of( () -> new DiskDrivePeripheral( this ) ); + return peripheralCap.cast(); + } + return super.getCapability( cap, side ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index be3630a05..22d4b5ead 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -9,6 +9,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.IStringSerializable; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public enum CableModemVariant implements IStringSerializable { @@ -69,6 +70,7 @@ public enum CableModemVariant implements IStringSerializable return name; } + @Nullable public Direction getFacing() { return facing; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index bfe602ce0..8652b33f5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -11,14 +11,13 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; -import dan200.computercraft.shared.wired.CapabilityWiredElement; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -42,7 +41,10 @@ import javax.annotation.Nullable; import java.util.Collections; import java.util.Map; -public class TileCable extends TileGeneric implements IPeripheralTile +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT; + +public class TileCable extends TileGeneric { public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ), @@ -82,7 +84,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile } private boolean m_peripheralAccessAllowed; - private WiredModemLocalPeripheral m_peripheral = new WiredModemLocalPeripheral(); + private final WiredModemLocalPeripheral m_peripheral = new WiredModemLocalPeripheral( this::refreshPeripheral ); private boolean m_destroyed = false; @@ -113,6 +115,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } }; + private LazyOptional modemCap; private final NonNullConsumer> connectedNodeChanged = x -> connectionsChanged(); @@ -159,11 +162,8 @@ public class TileCable extends TileGeneric implements IPeripheralTile protected void invalidateCaps() { super.invalidateCaps(); - if( elementCap != null ) - { - elementCap.invalidate(); - elementCap = null; - } + elementCap = CapabilityUtil.invalidate( elementCap ); + modemCap = CapabilityUtil.invalidate( modemCap ); } @Override @@ -181,20 +181,26 @@ public class TileCable extends TileGeneric implements IPeripheralTile if( !world.isRemote ) world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 ); } - private void updateDirection() + private void refreshDirection() { - if( !hasModemDirection ) - { - hasModemDirection = true; - modemDirection = getDirection(); - } + if( hasModemDirection ) return; + + hasModemDirection = true; + modemDirection = getBlockState().get( BlockCable.MODEM ).getFacing(); } + @Nullable + private Direction getMaybeDirection() + { + refreshDirection(); + return modemDirection; + } + + @Nonnull private Direction getDirection() { - BlockState state = getBlockState(); - Direction facing = state.get( BlockCable.MODEM ).getFacing(); - return facing != null ? facing : Direction.NORTH; + refreshDirection(); + return modemDirection == null ? Direction.NORTH : modemDirection; } @Override @@ -232,10 +238,15 @@ public class TileCable extends TileGeneric implements IPeripheralTile if( !world.isRemote && m_peripheralAccessAllowed ) { Direction facing = getDirection(); - if( getPos().offset( facing ).equals( neighbour ) ) - { - if( m_peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals(); - } + if( getPos().offset( facing ).equals( neighbour ) ) refreshPeripheral(); + } + } + + private void refreshPeripheral() + { + if( world != null && !isRemoved() && m_peripheral.attach( world, getPos(), getDirection() ) ) + { + updateConnectedPeripherals(); } } @@ -303,7 +314,14 @@ public class TileCable extends TileGeneric implements IPeripheralTile { if( getWorld().isRemote ) return; - updateDirection(); + Direction oldDirection = modemDirection; + refreshDirection(); + if( modemDirection != oldDirection ) + { + // We invalidate both the modem and element if the modem's direction is different. + modemCap = CapabilityUtil.invalidate( modemCap ); + elementCap = CapabilityUtil.invalidate( elementCap ); + } if( m_modem.getModemState().pollChanged() ) updateBlockState(); @@ -353,11 +371,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile void modemChanged() { // Tell anyone who cares that the connection state has changed - if( elementCap != null ) - { - elementCap.invalidate(); - elementCap = null; - } + elementCap = CapabilityUtil.invalidate( elementCap ); if( getWorld().isRemote ) return; @@ -415,22 +429,24 @@ public class TileCable extends TileGeneric implements IPeripheralTile @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction side ) { - if( capability == CapabilityWiredElement.CAPABILITY ) + if( capability == CAPABILITY_WIRED_ELEMENT ) { - if( m_destroyed || !BlockCable.canConnectIn( getBlockState(), facing ) ) return LazyOptional.empty(); + if( m_destroyed || !BlockCable.canConnectIn( getBlockState(), side ) ) return LazyOptional.empty(); if( elementCap == null ) elementCap = LazyOptional.of( () -> m_cable ); return elementCap.cast(); } - return super.getCapability( capability, facing ); - } + if( capability == CAPABILITY_PERIPHERAL ) + { + refreshDirection(); + if( side != null && getMaybeDirection() != side ) return LazyOptional.empty(); + if( modemCap == null ) modemCap = LazyOptional.of( () -> m_modem ); + return modemCap.cast(); + } - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) - { - return !m_destroyed && hasModem() && side == getDirection() ? m_modem : null; + return super.getCapability( capability, side ); } boolean hasCable() diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 84aa21a32..97d38f76e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -11,14 +11,10 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; -import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; -import dan200.computercraft.shared.util.TickScheduler; -import dan200.computercraft.shared.wired.CapabilityWiredElement; +import dan200.computercraft.shared.util.*; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; @@ -40,10 +36,12 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT; import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.MODEM_ON; import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.PERIPHERAL_ON; -public class TileWiredModemFull extends TileGeneric implements IPeripheralTile +public class TileWiredModemFull extends TileGeneric { public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ), @@ -66,7 +64,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { for( int i = 0; i < 6; i++ ) { - WiredModemPeripheral modem = m_entity.m_modems[i]; + WiredModemPeripheral modem = m_entity.modems[i]; if( modem != null ) modem.attachPeripheral( name, peripheral ); } } @@ -76,7 +74,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { for( int i = 0; i < 6; i++ ) { - WiredModemPeripheral modem = m_entity.m_modems[i]; + WiredModemPeripheral modem = m_entity.modems[i]; if( modem != null ) modem.detachPeripheral( name ); } } @@ -97,10 +95,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile } } - private WiredModemPeripheral[] m_modems = new WiredModemPeripheral[6]; + private final WiredModemPeripheral[] modems = new WiredModemPeripheral[6]; + private final SidedCaps modemCaps = SidedCaps.ofNonNull( this::getPeripheral ); private boolean m_peripheralAccessAllowed = false; - private WiredModemLocalPeripheral[] m_peripherals = new WiredModemLocalPeripheral[6]; + private final WiredModemLocalPeripheral[] m_peripherals = new WiredModemLocalPeripheral[6]; private boolean m_destroyed = false; private boolean m_connectionsFormed = false; @@ -115,7 +114,11 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile public TileWiredModemFull() { super( FACTORY ); - for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i] = new WiredModemLocalPeripheral(); + for( int i = 0; i < m_peripherals.length; i++ ) + { + Direction facing = Direction.byIndex( i ); + m_peripherals[i] = new WiredModemLocalPeripheral( () -> refreshPeripheral( facing ) ); + } } private void doRemove() @@ -149,11 +152,8 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile protected void invalidateCaps() { super.invalidateCaps(); - if( elementCap != null ) - { - elementCap.invalidate(); - elementCap = null; - } + elementCap = CapabilityUtil.invalidate( elementCap ); + modemCaps.invalidate(); } @Override @@ -176,15 +176,20 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { for( Direction facing : DirectionUtil.FACINGS ) { - if( getPos().offset( facing ).equals( neighbour ) ) - { - WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()]; - if( peripheral.attach( world, getPos(), facing ) ) updateConnectedPeripherals(); - } + if( getPos().offset( facing ).equals( neighbour ) ) refreshPeripheral( facing ); } } } + private void refreshPeripheral( @Nonnull Direction facing ) + { + WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()]; + if( world != null && !isRemoved() && peripheral.attach( world, getPos(), facing ) ) + { + updateConnectedPeripherals(); + } + } + @Nonnull @Override public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit ) @@ -223,7 +228,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile } @Override - public void read( CompoundNBT nbt ) + public void read( @Nonnull CompoundNBT nbt ) { super.read( nbt ); m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); @@ -362,14 +367,17 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) + public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction side ) { - if( capability == CapabilityWiredElement.CAPABILITY ) + if( capability == CAPABILITY_WIRED_ELEMENT ) { if( elementCap == null ) elementCap = LazyOptional.of( () -> m_element ); return elementCap.cast(); } - return super.getCapability( capability, facing ); + + if( capability == CAPABILITY_PERIPHERAL ) return modemCaps.get( side ).cast(); + + return super.getCapability( capability, side ); } public IWiredElement getElement() @@ -377,35 +385,28 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile return m_element; } - // IPeripheralTile - - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) + private WiredModemPeripheral getPeripheral( @Nonnull Direction side ) { - if( m_destroyed ) return null; + WiredModemPeripheral peripheral = modems[side.ordinal()]; + if( peripheral != null ) return peripheral; - WiredModemPeripheral peripheral = m_modems[side.ordinal()]; - if( peripheral == null ) + WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()]; + return modems[side.ordinal()] = new WiredModemPeripheral( m_modemState, m_element ) { - WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()]; - peripheral = m_modems[side.ordinal()] = new WiredModemPeripheral( m_modemState, m_element ) + @Nonnull + @Override + protected WiredModemLocalPeripheral getLocalPeripheral() { - @Nonnull - @Override - protected WiredModemLocalPeripheral getLocalPeripheral() - { - return localPeripheral; - } + return localPeripheral; + } - @Nonnull - @Override - public Vec3d getPosition() - { - BlockPos pos = getPos().offset( side ); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); - } - }; - } - return peripheral; + @Nonnull + @Override + public Vec3d getPosition() + { + BlockPos pos = getPos().offset( side ); + return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + } + }; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index 9c776cf76..9314c4d74 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -15,6 +15,8 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullConsumer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -36,6 +38,12 @@ public final class WiredModemLocalPeripheral private String type; private IPeripheral peripheral; + private final NonNullConsumer> invalidate; + + public WiredModemLocalPeripheral( @Nonnull Runnable invalidate ) + { + this.invalidate = x -> invalidate.run(); + } /** * Attach a new peripheral from the world. @@ -130,14 +138,15 @@ public final class WiredModemLocalPeripheral ? tag.getString( NBT_PERIPHERAL_TYPE + suffix ) : null; } - private static IPeripheral getPeripheralFrom( World world, BlockPos pos, Direction direction ) + @Nullable + private IPeripheral getPeripheralFrom( World world, BlockPos pos, Direction direction ) { BlockPos offset = pos.offset( direction ); Block block = world.getBlockState( offset ).getBlock(); if( block == ComputerCraft.Blocks.wiredModemFull || block == ComputerCraft.Blocks.cable ) return null; - IPeripheral peripheral = Peripherals.getPeripheral( world, offset, direction.getOpposite() ); + IPeripheral peripheral = Peripherals.getPeripheral( world, offset, direction.getOpposite(), invalidate ); return peripheral instanceof WiredModemPeripheral ? null : peripheral; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 557aee0d4..33373e566 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -7,10 +7,10 @@ package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; +import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.block.BlockState; @@ -20,11 +20,15 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TileWirelessModem extends TileGeneric implements IPeripheralTile +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + +public class TileWirelessModem extends TileGeneric { public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ), @@ -74,6 +78,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile private Direction modemDirection = Direction.DOWN; private final ModemPeripheral modem; private boolean destroyed = false; + private LazyOptional modemCap; public TileWirelessModem( TileEntityType type, boolean advanced ) { @@ -99,20 +104,6 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile } } - @Override - public void markDirty() - { - super.markDirty(); - if( world != null ) - { - updateDirection(); - } - else - { - hasModemDirection = false; - } - } - @Override public void updateContainingBlockInfo() { @@ -124,12 +115,17 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile @Override public void blockTick() { - updateDirection(); + Direction currentDirection = modemDirection; + refreshDirection(); + // Invalidate the capability if the direction has changed. I'm not 100% happy with this implementation + // - ideally we'd do it within refreshDirection or updateContainingBlockInfo, but this seems the _safest_ + // place. + if( currentDirection != modemDirection ) modemCap = CapabilityUtil.invalidate( modemCap ); if( modem.getModemState().pollChanged() ) updateBlockState(); } - private void updateDirection() + private void refreshDirection() { if( hasModemDirection ) return; @@ -147,12 +143,18 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile } } - - @Nullable + @Nonnull @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) { - updateDirection(); - return side == modemDirection ? modem : null; + if( cap == CAPABILITY_PERIPHERAL ) + { + refreshDirection(); + if( side != null && modemDirection != side ) return LazyOptional.empty(); + if( modemCap == null ) modemCap = LazyOptional.of( () -> modem ); + return modemCap.cast(); + } + + return super.getCapability( cap, side ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index ff185fffc..e338d80fa 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -8,10 +8,10 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.entity.player.PlayerEntity; @@ -26,12 +26,17 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.HashSet; import java.util.Set; -public class TileMonitor extends TileGeneric implements IPeripheralTile +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + +public class TileMonitor extends TileGeneric { public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ), @@ -59,7 +64,8 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile private ServerMonitor m_serverMonitor; private ClientMonitor m_clientMonitor; - private MonitorPeripheral m_peripheral; + private MonitorPeripheral peripheral; + private LazyOptional peripheralCap; private final Set m_computers = new HashSet<>(); private boolean m_destroyed = false; @@ -174,14 +180,25 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile if( m_serverMonitor.pollTerminalChanged() ) updateBlock(); } - // IPeripheralTile implementation - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) + protected void invalidateCaps() { - createServerMonitor(); // Ensure the monitor is created before doing anything else. - if( m_peripheral == null ) m_peripheral = new MonitorPeripheral( this ); - return m_peripheral; + super.invalidateCaps(); + peripheralCap = CapabilityUtil.invalidate( peripheralCap ); + } + + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) + { + if( cap == CAPABILITY_PERIPHERAL ) + { + createServerMonitor(); // Ensure the monitor is created before doing anything else. + if( peripheral == null ) peripheral = new MonitorPeripheral( this ); + if( peripheralCap == null ) peripheralCap = LazyOptional.of( () -> peripheral ); + return peripheralCap.cast(); + } + return super.getCapability( cap, side ); } public ServerMonitor getCachedServerMonitor() @@ -409,7 +426,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile for( int y = 0; y < height; y++ ) { TileMonitor monitor = getNeighbour( x, y ); - if( monitor != null && monitor.m_peripheral != null ) + if( monitor != null && monitor.peripheral != null ) { needsTerminal = true; break terminalCheck; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 529ec7d23..65513f569 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -7,14 +7,10 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.util.ColourUtils; -import dan200.computercraft.shared.util.DefaultSidedInventory; -import dan200.computercraft.shared.util.NamedTileEntityType; -import dan200.computercraft.shared.util.WorldUtil; +import dan200.computercraft.shared.util.*; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; @@ -32,16 +28,17 @@ import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fml.network.NetworkHooks; -import net.minecraftforge.items.IItemHandlerModifiable; +import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.wrapper.InvWrapper; import net.minecraftforge.items.wrapper.SidedInvWrapper; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; -public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile, INameable, INamedContainerProvider +public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, INameable, INamedContainerProvider { public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ), @@ -61,7 +58,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent ITextComponent customName; private final NonNullList m_inventory = NonNullList.withSize( SLOTS, ItemStack.EMPTY ); - private LazyOptional[] itemHandlerCaps; + private final SidedCaps itemHandlerCaps = + SidedCaps.ofNullable( facing -> facing == null ? new InvWrapper( this ) : new SidedInvWrapper( this, facing ) ); + private LazyOptional peripheralCap; private final Terminal m_page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE ); private String m_pageTitle = ""; @@ -82,16 +81,8 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent protected void invalidateCaps() { super.invalidateCaps(); - - if( itemHandlerCaps != null ) - { - for( int i = 0; i < itemHandlerCaps.length; i++ ) - { - if( itemHandlerCaps[i] == null ) continue; - itemHandlerCaps[i].invalidate(); - itemHandlerCaps[i] = null; - } - } + itemHandlerCaps.invalidate(); + peripheralCap = CapabilityUtil.invalidate( peripheralCap ); } @Nonnull @@ -262,14 +253,6 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } } - // IPeripheralTile implementation - - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) - { - return new PrinterPeripheral( this ); - } - @Nullable Terminal getCurrentPage() { @@ -465,26 +448,15 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent getWorld().setBlockState( getPos(), state.with( BlockPrinter.TOP, top ).with( BlockPrinter.BOTTOM, bottom ) ); } - @SuppressWarnings( { "unchecked", "rawtypes" } ) @Nonnull @Override public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction facing ) { - if( capability == ITEM_HANDLER_CAPABILITY ) + if( capability == ITEM_HANDLER_CAPABILITY ) return itemHandlerCaps.get( facing ).cast(); + if( capability == CAPABILITY_PERIPHERAL ) { - LazyOptional[] handlers = itemHandlerCaps; - if( handlers == null ) handlers = itemHandlerCaps = new LazyOptional[7]; - - int index = facing == null ? 0 : 1 + facing.getIndex(); - LazyOptional handler = handlers[index]; - if( handler == null ) - { - handler = handlers[index] = facing == null - ? LazyOptional.of( () -> new InvWrapper( this ) ) - : LazyOptional.of( () -> new SidedInvWrapper( this, facing ) ); - } - - return handler.cast(); + if( peripheralCap == null ) peripheralCap = LazyOptional.of( () -> new PrinterPeripheral( this ) ); + return peripheralCap.cast(); } return super.getCapability( capability, facing ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 2ca05a11e..16fb6e5c2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -7,8 +7,8 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.util.Direction; @@ -16,11 +16,15 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TileSpeaker extends TileGeneric implements ITickableTileEntity, IPeripheralTile +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; + +public class TileSpeaker extends TileGeneric implements ITickableTileEntity { public static final int MIN_TICKS_BETWEEN_SOUNDS = 1; @@ -29,24 +33,39 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity, IPe TileSpeaker::new ); - private final SpeakerPeripheral m_peripheral; + private final SpeakerPeripheral peripheral; + private LazyOptional peripheralCap; public TileSpeaker() { super( FACTORY ); - m_peripheral = new Peripheral( this ); + peripheral = new Peripheral( this ); } @Override public void tick() { - m_peripheral.update(); + peripheral.update(); + } + + @Nonnull + @Override + public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) + { + if( cap == CAPABILITY_PERIPHERAL ) + { + if( peripheralCap == null ) peripheralCap = LazyOptional.of( () -> peripheral ); + return peripheralCap.cast(); + } + + return super.getCapability( cap, side ); } @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) + protected void invalidateCaps() { - return m_peripheral; + super.invalidateCaps(); + peripheralCap = CapabilityUtil.invalidate( peripheralCap ); } private static final class Peripheral extends SpeakerPeripheral diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index d22234ee9..d4b962cb3 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -8,7 +8,8 @@ package dan200.computercraft.shared.proxy; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.media.IMedia; -import dan200.computercraft.api.peripheral.IPeripheralTile; +import dan200.computercraft.api.network.wired.IWiredElement; +import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.shared.command.CommandComputerCraft; @@ -23,20 +24,18 @@ import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.network.NetworkHandler; -import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; -import dan200.computercraft.shared.wired.CapabilityWiredElement; +import dan200.computercraft.shared.util.NullStorage; import net.minecraft.inventory.container.Container; import net.minecraft.item.Item; import net.minecraft.item.MusicDiscItem; -import net.minecraft.tileentity.CommandBlockTileEntity; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.ConstantRange; import net.minecraft.world.storage.loot.LootPool; import net.minecraft.world.storage.loot.LootTables; import net.minecraft.world.storage.loot.TableLootEntry; import net.minecraft.world.storage.loot.conditions.LootConditionManager; +import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent; @@ -90,17 +89,6 @@ public final class ComputerCraftProxyCommon private static void registerProviders() { - // Register peripheral providers - ComputerCraftAPI.registerPeripheralProvider( ( world, pos, side ) -> { - TileEntity tile = world.getTileEntity( pos ); - return tile instanceof IPeripheralTile ? ((IPeripheralTile) tile).getPeripheral( side ) : null; - } ); - - ComputerCraftAPI.registerPeripheralProvider( ( world, pos, side ) -> { - TileEntity tile = world.getTileEntity( pos ); - return ComputerCraft.enableCommandBlock && tile instanceof CommandBlockTileEntity ? new CommandBlockPeripheral( (CommandBlockTileEntity) tile ) : null; - } ); - // Register bundled power providers ComputerCraftAPI.registerBundledRedstoneProvider( new DefaultBundledRedstoneProvider() ); @@ -112,8 +100,9 @@ public final class ComputerCraftProxyCommon return null; } ); - // Register network providers - CapabilityWiredElement.register(); + // Register capabilities + CapabilityManager.INSTANCE.register( IWiredElement.class, new NullStorage<>(), () -> null ); + CapabilityManager.INSTANCE.register( IPeripheral.class, new NullStorage<>(), () -> null ); } @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index f3a6d22e7..7954d83c2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -47,6 +47,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Collections; +import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY; public class TileTurtle extends TileComputerBase implements ITurtleTile, DefaultInventory @@ -79,6 +80,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default private boolean m_inventoryChanged = false; private TurtleBrain m_brain = new TurtleBrain( this ); private MoveState m_moveState = MoveState.NOT_MOVED; + private LazyOptional peripheral; public TileTurtle( TileEntityType type, ComputerFamily family ) { @@ -103,7 +105,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default return computer; } - @Override public ComputerProxy createProxy() { return m_brain.getProxy(); @@ -154,11 +155,8 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default protected void invalidateCaps() { super.invalidateCaps(); - if( itemHandlerCap != null ) - { - itemHandlerCap.invalidate(); - itemHandlerCap = null; - } + itemHandlerCap = CapabilityUtil.invalidate( itemHandlerCap ); + peripheral = CapabilityUtil.invalidate( peripheral ); } @Nonnull @@ -545,14 +543,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default m_inventoryChanged = copy.m_inventoryChanged; m_brain = copy.m_brain; m_brain.setOwner( this ); - copy.m_moveState = MoveState.MOVED; - } - @Nullable - @Override - public IPeripheral getPeripheral( @Nonnull Direction side ) - { - return hasMoved() ? null : new ComputerPeripheral( "turtle", createProxy() ); + // Mark the other turtle as having moved, and so its peripheral is dead. + copy.m_moveState = MoveState.MOVED; + copy.peripheral = CapabilityUtil.invalidate( copy.peripheral ); } public IItemHandlerModifiable getItemHandler() @@ -569,6 +563,17 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default if( itemHandlerCap == null ) itemHandlerCap = LazyOptional.of( () -> new InvWrapper( this ) ); return itemHandlerCap.cast(); } + + if( cap == CAPABILITY_PERIPHERAL ) + { + if( hasMoved() ) return LazyOptional.empty(); + if( peripheral == null ) + { + peripheral = LazyOptional.of( () -> new ComputerPeripheral( "turtle", createProxy() ) ); + } + return peripheral.cast(); + } + return super.getCapability( cap, side ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 28eaded9b..31b363aa3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -15,7 +15,6 @@ import dan200.computercraft.api.turtle.*; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.blocks.ComputerProxy; -import dan200.computercraft.shared.computer.blocks.TileComputerBase; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.turtle.blocks.TileTurtle; @@ -72,12 +71,12 @@ public class TurtleBrain implements ITurtleAccess private final IInventory m_inventory = (InventoryDelegate) () -> m_owner; private final IItemHandlerModifiable m_inventoryWrapper = new InvWrapper( m_inventory ); - private Queue m_commandQueue = new ArrayDeque<>(); + private final Queue m_commandQueue = new ArrayDeque<>(); private int m_commandsIssued = 0; - private Map m_upgrades = new EnumMap<>( TurtleSide.class ); - private Map peripherals = new EnumMap<>( TurtleSide.class ); - private Map m_upgradeNBTData = new EnumMap<>( TurtleSide.class ); + private final Map m_upgrades = new EnumMap<>( TurtleSide.class ); + private final Map peripherals = new EnumMap<>( TurtleSide.class ); + private final Map m_upgradeNBTData = new EnumMap<>( TurtleSide.class ); private int m_selectedSlot = 0; private int m_fuelLevel = 0; @@ -107,17 +106,7 @@ public class TurtleBrain implements ITurtleAccess public ComputerProxy getProxy() { - if( m_proxy == null ) - { - m_proxy = new ComputerProxy() - { - @Override - protected TileComputerBase getTile() - { - return m_owner; - } - }; - } + if( m_proxy == null ) m_proxy = new ComputerProxy( () -> m_owner ); return m_proxy; } diff --git a/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java b/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java new file mode 100644 index 000000000..7643eeb2c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java @@ -0,0 +1,47 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullConsumer; + +import javax.annotation.Nullable; + +public final class CapabilityUtil +{ + private CapabilityUtil() + { + } + + @Nullable + public static LazyOptional invalidate( @Nullable LazyOptional cap ) + { + if( cap != null ) cap.invalidate(); + return null; + } + + public static void invalidate( @Nullable LazyOptional[] caps ) + { + if( caps == null ) return; + + for( int i = 0; i < caps.length; i++ ) + { + LazyOptional cap = caps[i]; + if( cap != null ) cap.invalidate(); + caps[i] = null; + } + } + + @Nullable + public static T unwrap( LazyOptional p, NonNullConsumer> invalidate ) + { + if( !p.isPresent() ) return null; + + p.addListener( invalidate ); + return p.orElseThrow( NullPointerException::new ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/NullStorage.java b/src/main/java/dan200/computercraft/shared/util/NullStorage.java new file mode 100644 index 000000000..1c8ab93ae --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/NullStorage.java @@ -0,0 +1,25 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.nbt.INBT; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; + +public class NullStorage implements Capability.IStorage +{ + @Override + public INBT writeNBT( Capability capability, T instance, Direction side ) + { + return null; + } + + @Override + public void readNBT( Capability capability, T instance, Direction side, INBT base ) + { + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/SidedCaps.java b/src/main/java/dan200/computercraft/shared/util/SidedCaps.java new file mode 100644 index 000000000..7491416a7 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/SidedCaps.java @@ -0,0 +1,68 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import net.minecraft.util.Direction; +import net.minecraftforge.common.util.LazyOptional; + +import javax.annotation.Nullable; +import java.util.function.Function; + +/** + * Provides a constant (but invalidate-able) capability for each side. + * + * @param The type of the produced capability. + */ +public final class SidedCaps +{ + private final Function factory; + private final boolean allowNull; + private T[] values; + private LazyOptional[] caps; + + private SidedCaps( Function factory, boolean allowNull ) + { + this.factory = factory; + this.allowNull = allowNull; + } + + public static SidedCaps ofNonNull( Function factory ) + { + return new SidedCaps<>( factory, false ); + } + + public static SidedCaps ofNullable( Function factory ) + { + return new SidedCaps<>( factory, true ); + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + public LazyOptional get( @Nullable Direction direction ) + { + if( direction == null && !allowNull ) return LazyOptional.empty(); + int index = direction == null ? 6 : direction.ordinal(); + + LazyOptional[] caps = this.caps; + if( caps == null ) + { + caps = this.caps = new LazyOptional[allowNull ? 7 : 6]; + values = (T[]) new Object[caps.length]; + } + + LazyOptional cap = caps[index]; + return cap == null ? caps[index] = LazyOptional.of( () -> { + T[] values = this.values; + T value = values[index]; + return value == null ? values[index] = factory.apply( direction ) : value; + } ) : cap; + } + + public void invalidate() + { + if( caps != null ) CapabilityUtil.invalidate( caps ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java b/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java deleted file mode 100644 index 4681021a1..000000000 --- a/src/main/java/dan200/computercraft/shared/wired/CapabilityWiredElement.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.wired; - -import dan200.computercraft.api.network.wired.IWiredElement; -import dan200.computercraft.api.network.wired.IWiredNode; -import net.minecraft.nbt.INBT; -import net.minecraft.util.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityInject; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.util.LazyOptional; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public final class CapabilityWiredElement -{ - @CapabilityInject( IWiredElement.class ) - public static Capability CAPABILITY = null; - - private CapabilityWiredElement() {} - - public static void register() - { - CapabilityManager.INSTANCE.register( IWiredElement.class, new NullStorage(), NullElement::new ); - } - - private static class NullElement implements IWiredElement - { - @Nonnull - @Override - public IWiredNode getNode() - { - throw new IllegalStateException( "Should not use the default element implementation" ); - } - - @Nonnull - @Override - public World getWorld() - { - throw new IllegalStateException( "Should not use the default element implementation" ); - } - - @Nonnull - @Override - public Vec3d getPosition() - { - throw new IllegalStateException( "Should not use the default element implementation" ); - } - - @Nonnull - @Override - public String getSenderID() - { - throw new IllegalStateException( "Should not use the default element implementation" ); - } - } - - private static class NullStorage implements Capability.IStorage - { - @Override - public INBT writeNBT( Capability capability, IWiredElement instance, Direction side ) - { - return null; - } - - @Override - public void readNBT( Capability capability, IWiredElement instance, Direction side, INBT base ) - { - } - } - - private static final IWiredElement NULL_ELEMENT = new NullElement(); - - @Nullable - public static IWiredElement unwrap( LazyOptional capability ) - { - IWiredElement element = capability.orElse( NULL_ELEMENT ); - return element == NULL_ELEMENT ? null : element; - } -} From 4f8217d1ab4c87380b7c04897970c59f873d03c6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 17:34:00 +0100 Subject: [PATCH 235/711] Implement IPeripheral.getTarget on a few additional TEs Also make it nullable. Hopefully this will allow us to distinguish between non-default implementations more easily. --- .../dan200/computercraft/api/peripheral/IPeripheral.java | 4 ++-- .../peripheral/commandblock/CommandBlockPeripheral.java | 7 +++++++ .../shared/peripheral/modem/wired/TileCable.java | 7 +++++++ .../shared/peripheral/modem/wired/TileWiredModemFull.java | 7 +++++++ .../peripheral/modem/wireless/TileWirelessModem.java | 7 +++++++ .../shared/peripheral/monitor/MonitorPeripheral.java | 8 ++++++++ .../shared/turtle/upgrades/CraftingTablePeripheral.java | 7 +++++++ 7 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 04cfa6440..c5d897e8c 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -81,10 +81,10 @@ public interface IPeripheral * * @return The object this peripheral targets */ - @Nonnull + @Nullable default Object getTarget() { - return this; + return null; } /** diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index 1ba941959..a5d2a2041 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -72,6 +72,13 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider return other != null && other.getClass() == getClass(); } + @Nonnull + @Override + public Object getTarget() + { + return commandBlock; + } + @Nonnull @Override public LazyOptional getCapability( @Nonnull Capability cap, @Nullable Direction side ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 8652b33f5..1844bb405 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -114,6 +114,13 @@ public class TileCable extends TileGeneric BlockPos pos = getPos().offset( modemDirection ); return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } + + @Nonnull + @Override + public Object getTarget() + { + return TileCable.this; + } }; private LazyOptional modemCap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 97d38f76e..054da8aad 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -407,6 +407,13 @@ public class TileWiredModemFull extends TileGeneric BlockPos pos = getPos().offset( side ); return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } + + @Nonnull + @Override + public Object getTarget() + { + return TileWiredModemFull.this; + } }; } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 33373e566..620c86e5b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -70,6 +70,13 @@ public class TileWirelessModem extends TileGeneric { return this == other || (other instanceof Peripheral && entity == ((Peripheral) other).entity); } + + @Nonnull + @Override + public Object getTarget() + { + return entity; + } } private final boolean advanced; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java index 67c88dc40..9551a3773 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java @@ -14,6 +14,7 @@ import dan200.computercraft.core.apis.TermMethods; import dan200.computercraft.core.terminal.Terminal; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class MonitorPeripheral extends TermMethods implements IPeripheral { @@ -85,4 +86,11 @@ public class MonitorPeripheral extends TermMethods implements IPeripheral { return getMonitor().isColour(); } + + @Nullable + @Override + public Object getTarget() + { + return monitor; + } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index 9b5238f85..530937992 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -44,4 +44,11 @@ public class CraftingTablePeripheral implements IPeripheral { return other instanceof CraftingTablePeripheral; } + + @Nonnull + @Override + public Object getTarget() + { + return turtle; + } } From 7af63d052dcdcdf239ec35b19d4b4aa089bd118e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 22:44:46 +0100 Subject: [PATCH 236/711] Make many more http options domain-specific timetout, max_upload, max_download and max_websocket_message may now be configured on a domain-by-domain basis. This uses the same system that we use for the block/allow-list from before: Example: [[http.rules]] host = "*" action = "allow" max_upload = 4194304 max_download = 16777216 timeout = 30000 --- .../dan200/computercraft/ComputerCraft.java | 17 +-- .../computercraft/core/apis/HTTPAPI.java | 6 - .../core/apis/http/CheckUrl.java | 5 +- .../core/apis/http/NetworkUtils.java | 29 ++-- .../core/apis/http/options/Action.java | 23 +++ .../apis/http/{ => options}/AddressRule.java | 53 ++++--- .../apis/http/options/AddressRuleConfig.java | 132 ++++++++++++++++++ .../core/apis/http/options/Options.java | 31 ++++ .../apis/http/options/PartialOptions.java | 59 ++++++++ .../core/apis/http/request/HttpRequest.java | 23 ++- .../apis/http/request/HttpRequestHandler.java | 9 +- .../core/apis/http/websocket/Websocket.java | 12 +- .../apis/http/websocket/WebsocketHandle.java | 8 +- .../apis/http/websocket/WebsocketHandler.java | 7 +- .../core/computer/ComputerThread.java | 2 +- .../computercraft/core/lua/BasicFunction.java | 2 +- .../core/lua/CobaltLuaMachine.java | 4 +- .../core/lua/ResultInterpreterFunction.java | 4 +- .../dan200/computercraft/shared/Config.java | 72 ++-------- .../shared/computer/apis/CommandAPI.java | 2 +- .../core/ComputerTestDelegate.java | 2 +- .../core/computer/ComputerBootstrap.java | 2 +- 22 files changed, 372 insertions(+), 132 deletions(-) create mode 100644 src/main/java/dan200/computercraft/core/apis/http/options/Action.java rename src/main/java/dan200/computercraft/core/apis/http/{ => options}/AddressRule.java (76%) create mode 100644 src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java create mode 100644 src/main/java/dan200/computercraft/core/apis/http/options/Options.java create mode 100644 src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 681cc8363..067fa3bc4 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -6,7 +6,8 @@ package dan200.computercraft; import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.core.apis.http.AddressRule; +import dan200.computercraft.core.apis.http.options.Action; +import dan200.computercraft.core.apis.http.options.AddressRule; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.computer.blocks.BlockComputer; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; @@ -70,7 +71,7 @@ public final class ComputerCraft public static boolean disable_lua51_features = false; public static String default_computer_settings = ""; public static boolean debug_enable = true; - public static boolean logPeripheralErrors = true; + public static boolean logComputerErrors = true; public static boolean commandRequireCreative = true; public static int computer_threads = 1; @@ -80,16 +81,16 @@ public final class ComputerCraft public static boolean httpEnabled = true; public static boolean httpWebsocketEnabled = true; public static List httpRules = Collections.unmodifiableList( Stream.concat( - Stream.of( DEFAULT_HTTP_DENY ).map( x -> AddressRule.parse( x, AddressRule.Action.DENY ) ).filter( Objects::nonNull ), - Stream.of( DEFAULT_HTTP_ALLOW ).map( x -> AddressRule.parse( x, AddressRule.Action.ALLOW ) ).filter( Objects::nonNull ) + Stream.of( DEFAULT_HTTP_DENY ) + .map( x -> AddressRule.parse( x, Action.DENY.toPartial() ) ) + .filter( Objects::nonNull ), + Stream.of( DEFAULT_HTTP_ALLOW ) + .map( x -> AddressRule.parse( x, Action.ALLOW.toPartial() ) ) + .filter( Objects::nonNull ) ).collect( Collectors.toList() ) ); - public static int httpTimeout = 30000; public static int httpMaxRequests = 16; - public static long httpMaxDownload = 16 * 1024 * 1024; - public static long httpMaxUpload = 4 * 1024 * 1024; public static int httpMaxWebsockets = 4; - public static int httpMaxWebsocketMessage = 128 * 1024; public static boolean enableCommandBlock = false; public static int modem_range = 64; diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index eac31b9f8..fa0af20ea 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -119,12 +119,6 @@ public class HTTPAPI implements ILuaAPI URI uri = HttpRequest.checkUri( address ); HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect ); - long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers ); - if( ComputerCraft.httpMaxUpload != 0 && requestBody > ComputerCraft.httpMaxUpload ) - { - throw new HTTPRequestException( "Request body is too large" ); - } - // Make the request request.queue( r -> r.request( uri, httpMethod ) ); diff --git a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java index f92d5926e..2d902581c 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java +++ b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java @@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.http; import dan200.computercraft.core.apis.IAPIEnvironment; +import java.net.InetSocketAddress; import java.net.URI; import java.util.concurrent.Future; @@ -46,7 +47,9 @@ public class CheckUrl extends Resource try { - NetworkUtils.getAddress( host, 80, false ); + InetSocketAddress address = NetworkUtils.getAddress( host, 80, false ); + NetworkUtils.getOptions( host, address ); + if( tryClose() ) environment.queueEvent( EVENT, address, true ); } catch( HTTPRequestException e ) diff --git a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java index c2a3e6c59..aa2a9a6be 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -6,6 +6,9 @@ package dan200.computercraft.core.apis.http; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.apis.http.options.Action; +import dan200.computercraft.core.apis.http.options.AddressRule; +import dan200.computercraft.core.apis.http.options.Options; import dan200.computercraft.shared.util.ThreadUtils; import io.netty.buffer.ByteBuf; import io.netty.channel.EventLoopGroup; @@ -15,7 +18,6 @@ import io.netty.handler.ssl.SslContextBuilder; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.KeyStore; import java.util.concurrent.ExecutorService; @@ -106,24 +108,31 @@ public final class NetworkUtils * @param port The port, or -1 if not defined. * @param ssl Whether to connect with SSL. This is used to find the default port if not otherwise specified. * @return The resolved address. - * @throws HTTPRequestException If the host is not permitted. + * @throws HTTPRequestException If the host is not malformed. */ public static InetSocketAddress getAddress( String host, int port, boolean ssl ) throws HTTPRequestException { if( port < 0 ) port = ssl ? 443 : 80; - InetSocketAddress socketAddress = new InetSocketAddress( host, port ); if( socketAddress.isUnresolved() ) throw new HTTPRequestException( "Unknown host" ); - - InetAddress address = socketAddress.getAddress(); - if( AddressRule.apply( ComputerCraft.httpRules, host, address ) == AddressRule.Action.DENY ) - { - throw new HTTPRequestException( "Domain not permitted" ); - } - return socketAddress; } + /** + * Get options for a specific domain. + * + * @param host The host to resolve. + * @param address The address, resolved by {@link #getAddress(String, int, boolean)}. + * @return The options for this host. + * @throws HTTPRequestException If the host is not permitted + */ + public static Options getOptions( String host, InetSocketAddress address ) throws HTTPRequestException + { + Options options = AddressRule.apply( ComputerCraft.httpRules, host, address.getAddress() ); + if( options.action == Action.DENY ) throw new HTTPRequestException( "Domain not permitted" ); + return options; + } + /** * Read a {@link ByteBuf} into a byte array. * diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/Action.java b/src/main/java/dan200/computercraft/core/apis/http/options/Action.java new file mode 100644 index 000000000..ac23cc575 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/http/options/Action.java @@ -0,0 +1,23 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis.http.options; + +import javax.annotation.Nonnull; + +public enum Action +{ + ALLOW, + DENY; + + private final PartialOptions partial = new PartialOptions( this, null, null, null, null ); + + @Nonnull + public PartialOptions toPartial() + { + return partial; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/http/AddressRule.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java similarity index 76% rename from src/main/java/dan200/computercraft/core/apis/http/AddressRule.java rename to src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java index 19ab61f36..03bf372ba 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/AddressRule.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java @@ -3,11 +3,12 @@ * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.core.apis.http; +package dan200.computercraft.core.apis.http.options; import com.google.common.net.InetAddresses; import dan200.computercraft.ComputerCraft; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.net.Inet6Address; import java.net.InetAddress; @@ -18,6 +19,11 @@ import java.util.regex.Pattern; */ public final class AddressRule { + public static final long MAX_DOWNLOAD = 16 * 1024 * 1024; + public static final long MAX_UPLOAD = 4 * 1024 * 1024; + public static final int TIMEOUT = 30_000; + public static final int WEBSOCKET_MESSAGE = 128 * 1024; + private static final class HostRange { private final byte[] min; @@ -44,25 +50,19 @@ public final class AddressRule } } - public enum Action - { - ALLOW, - DENY, - } - private final HostRange ip; private final Pattern domainPattern; - private final Action action; + private final PartialOptions partial; - private AddressRule( HostRange ip, Pattern domainPattern, Action action ) + private AddressRule( @Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial ) { this.ip = ip; this.domainPattern = domainPattern; - this.action = action; + this.partial = partial; } @Nullable - public static AddressRule parse( String filter, Action action ) + public static AddressRule parse( String filter, @Nonnull PartialOptions partial ) { int cidr = filter.indexOf( '/' ); if( cidr >= 0 ) @@ -117,12 +117,12 @@ public final class AddressRule size -= 8; } - return new AddressRule( new HostRange( minBytes, maxBytes ), null, action ); + return new AddressRule( new HostRange( minBytes, maxBytes ), null, partial ); } else { Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ); - return new AddressRule( null, pattern, action ); + return new AddressRule( null, pattern, partial ); } } @@ -133,7 +133,7 @@ public final class AddressRule * @param address The address to check. * @return Whether it matches any of these patterns. */ - public boolean matches( String domain, InetAddress address ) + private boolean matches( String domain, InetAddress address ) { if( domainPattern != null ) { @@ -155,13 +155,32 @@ public final class AddressRule return ip != null && ip.contains( address ); } - public static Action apply( Iterable rules, String domain, InetAddress address ) + public static Options apply( Iterable rules, String domain, InetAddress address ) { + PartialOptions options = null; + boolean hasMany = false; + for( AddressRule rule : rules ) { - if( rule.matches( domain, address ) ) return rule.action; + if( !rule.matches( domain, address ) ) continue; + + if( options == null ) + { + options = rule.partial; + } + else + { + + if( !hasMany ) + { + options = options.copy(); + hasMany = true; + } + + options.merge( rule.partial ); + } } - return Action.DENY; + return (options == null ? PartialOptions.DEFAULT : options).toOptions(); } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java new file mode 100644 index 000000000..4f0bc5647 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java @@ -0,0 +1,132 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis.http.options; + +import com.electronwill.nightconfig.core.CommentedConfig; +import com.electronwill.nightconfig.core.Config; +import com.electronwill.nightconfig.core.InMemoryCommentedFormat; +import com.electronwill.nightconfig.core.UnmodifiableConfig; +import dan200.computercraft.ComputerCraft; + +import javax.annotation.Nullable; +import java.util.Locale; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Parses, checks and generates {@link Config}s for {@link AddressRule}. + */ +public class AddressRuleConfig +{ + public static UnmodifiableConfig makeRule( String host, Action action ) + { + CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new ); + config.add( "host", host ); + config.add( "action", action.name().toLowerCase( Locale.ROOT ) ); + + if( host.equals( "*" ) && action == Action.ALLOW ) + { + config.setComment( "timeout", "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ); + config.add( "timeout", AddressRule.TIMEOUT ); + + config.setComment( "max_download", "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." ); + config.set( "max_download", AddressRule.MAX_DOWNLOAD ); + + config.setComment( "max_upload", "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." ); + config.set( "max_upload", AddressRule.MAX_UPLOAD ); + + config.setComment( "max_websocket_message", "The maximum size (in bytes) that a computer can send or receive in one websocket packet." ); + config.set( "max_websocket_message", AddressRule.WEBSOCKET_MESSAGE ); + } + + return config; + } + + public static boolean checkRule( UnmodifiableConfig builder ) + { + String hostObj = get( builder, "host", String.class ).orElse( null ); + return hostObj != null && checkEnum( builder, "action", Action.class ) + && check( builder, "timeout", Number.class ) + && check( builder, "max_upload", Number.class ) + && check( builder, "max_download", Number.class ) + && check( builder, "websocket_message", Number.class ) + && AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null; + } + + @Nullable + public static AddressRule parseRule( UnmodifiableConfig builder ) + { + String hostObj = get( builder, "host", String.class ).orElse( null ); + if( hostObj == null ) return null; + + Action action = getEnum( builder, "action", Action.class ).orElse( null ); + Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null ); + Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null ); + Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null ); + Integer websocketMessage = get( builder, "websocket_message", Number.class ).map( Number::intValue ).orElse( null ); + + PartialOptions options = new PartialOptions( + action, + maxUpload, + maxDownload, + timeout, + websocketMessage + ); + + return AddressRule.parse( hostObj, options ); + } + + private static boolean check( UnmodifiableConfig config, String field, Class klass ) + { + Object value = config.get( field ); + if( value == null || klass.isInstance( value ) ) return true; + + ComputerCraft.log.warn( "HTTP rule's {} is not a {}.", field, klass.getSimpleName() ); + return false; + } + + private static > boolean checkEnum( UnmodifiableConfig config, String field, Class klass ) + { + Object value = config.get( field ); + if( value == null ) return true; + + if( !(value instanceof String) ) + { + ComputerCraft.log.warn( "HTTP rule's {} is not a string", field ); + return false; + } + + if( parseEnum( klass, (String) value ) == null ) + { + ComputerCraft.log.warn( "HTTP rule's {} is not a known option", field ); + return false; + } + + return true; + } + + private static Optional get( UnmodifiableConfig config, String field, Class klass ) + { + Object value = config.get( field ); + return klass.isInstance( value ) ? Optional.of( klass.cast( value ) ) : Optional.empty(); + } + + private static > Optional getEnum( UnmodifiableConfig config, String field, Class klass ) + { + return get( config, field, String.class ).map( x -> parseEnum( klass, x ) ); + } + + @Nullable + private static > T parseEnum( Class klass, String x ) + { + for( T value : klass.getEnumConstants() ) + { + if( value.name().equalsIgnoreCase( x ) ) return value; + } + return null; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/Options.java b/src/main/java/dan200/computercraft/core/apis/http/options/Options.java new file mode 100644 index 000000000..5dd0e78d1 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/http/options/Options.java @@ -0,0 +1,31 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis.http.options; + +import javax.annotation.Nonnull; + +/** + * Options about a specific domain. + */ +public final class Options +{ + @Nonnull + public final Action action; + public final long maxUpload; + public final long maxDownload; + public final int timeout; + public final int websocketMessage; + + Options( @Nonnull Action action, long maxUpload, long maxDownload, int timeout, int websocketMessage ) + { + this.action = action; + this.maxUpload = maxUpload; + this.maxDownload = maxDownload; + this.timeout = timeout; + this.websocketMessage = websocketMessage; + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java b/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java new file mode 100644 index 000000000..fb7150dd5 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java @@ -0,0 +1,59 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis.http.options; + +import javax.annotation.Nonnull; + +public final class PartialOptions +{ + static final PartialOptions DEFAULT = new PartialOptions( null, null, null, null, null ); + + Action action; + Long maxUpload; + Long maxDownload; + Integer timeout; + Integer websocketMessage; + + Options options; + + PartialOptions( Action action, Long maxUpload, Long maxDownload, Integer timeout, Integer websocketMessage ) + { + this.action = action; + this.maxUpload = maxUpload; + this.maxDownload = maxDownload; + this.timeout = timeout; + this.websocketMessage = websocketMessage; + } + + @Nonnull + Options toOptions() + { + if( options != null ) return options; + + return options = new Options( + action == null ? Action.DENY : action, + maxUpload == null ? AddressRule.MAX_UPLOAD : maxUpload, + maxDownload == null ? AddressRule.MAX_DOWNLOAD : maxDownload, + timeout == null ? AddressRule.TIMEOUT : timeout, + websocketMessage == null ? AddressRule.WEBSOCKET_MESSAGE : websocketMessage + ); + } + + void merge( @Nonnull PartialOptions other ) + { + if( action == null && other.action != null ) action = other.action; + if( maxUpload == null && other.maxUpload != null ) maxUpload = other.maxUpload; + if( maxDownload == null && other.maxDownload != null ) maxDownload = other.maxDownload; + if( timeout == null && other.timeout != null ) timeout = other.timeout; + if( websocketMessage == null && other.websocketMessage != null ) websocketMessage = other.websocketMessage; + } + + PartialOptions copy() + { + return new PartialOptions( action, maxUpload, maxDownload, timeout, websocketMessage ); + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index 3af3bacc3..ebd21a655 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -11,6 +11,7 @@ import dan200.computercraft.core.apis.http.HTTPRequestException; import dan200.computercraft.core.apis.http.NetworkUtils; import dan200.computercraft.core.apis.http.Resource; import dan200.computercraft.core.apis.http.ResourceGroup; +import dan200.computercraft.core.apis.http.options.Options; import dan200.computercraft.core.tracking.TrackingField; import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; @@ -136,16 +137,24 @@ public class HttpRequest extends Resource { boolean ssl = uri.getScheme().equalsIgnoreCase( "https" ); InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl ); + Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress ); SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; // getAddress may have a slight delay, so let's perform another cancellation check. if( isClosed() ) return; + long requestBody = getHeaderSize( headers ) + postBuffer.capacity(); + if( options.maxUpload != 0 && requestBody > options.maxUpload ) + { + failure( "Request body is too large" ); + return; + } + // Add request size to the tracker before opening the connection environment.addTrackingChange( TrackingField.HTTP_REQUESTS, 1 ); - environment.addTrackingChange( TrackingField.HTTP_UPLOAD, getHeaderSize( headers ) + postBuffer.capacity() ); + environment.addTrackingChange( TrackingField.HTTP_UPLOAD, requestBody ); - HttpRequestHandler handler = currentRequest = new HttpRequestHandler( this, uri, method ); + HttpRequestHandler handler = currentRequest = new HttpRequestHandler( this, uri, method, options ); connectFuture = new Bootstrap() .group( NetworkUtils.LOOP_GROUP ) .channelFactory( NioSocketChannel::new ) @@ -155,9 +164,9 @@ public class HttpRequest extends Resource protected void initChannel( SocketChannel ch ) { - if( ComputerCraft.httpTimeout > 0 ) + if( options.timeout > 0 ) { - ch.config().setConnectTimeoutMillis( ComputerCraft.httpTimeout ); + ch.config().setConnectTimeoutMillis( options.timeout ); } ChannelPipeline p = ch.pipeline(); @@ -166,9 +175,9 @@ public class HttpRequest extends Resource p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) ); } - if( ComputerCraft.httpTimeout > 0 ) + if( options.timeout > 0 ) { - p.addLast( new ReadTimeoutHandler( ComputerCraft.httpTimeout, TimeUnit.MILLISECONDS ) ); + p.addLast( new ReadTimeoutHandler( options.timeout, TimeUnit.MILLISECONDS ) ); } p.addLast( @@ -194,7 +203,7 @@ public class HttpRequest extends Resource catch( Exception e ) { failure( "Could not connect" ); - if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error in HTTP request", e ); + if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error in HTTP request", e ); } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index d742ec538..0f164d4f0 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -12,6 +12,7 @@ import dan200.computercraft.core.apis.handles.EncodedReadableHandle; import dan200.computercraft.core.apis.handles.HandleGeneric; import dan200.computercraft.core.apis.http.HTTPRequestException; import dan200.computercraft.core.apis.http.NetworkUtils; +import dan200.computercraft.core.apis.http.options.Options; import dan200.computercraft.core.tracking.TrackingField; import io.netty.buffer.ByteBuf; import io.netty.buffer.CompositeByteBuf; @@ -45,18 +46,20 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler ComputerCraft.httpMaxDownload ) + if( options.maxDownload != 0 && responseBody.readableBytes() + partial.readableBytes() > options.maxDownload ) { closed = true; ctx.close(); @@ -185,7 +188,7 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler boolean ssl = uri.getScheme().equalsIgnoreCase( "wss" ); InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl ); + Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress ); SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; // getAddress may have a slight delay, so let's perform another cancellation check. @@ -151,14 +153,14 @@ public class Websocket extends Resource WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker( uri, WebSocketVersion.V13, null, true, headers, - ComputerCraft.httpMaxWebsocketMessage == 0 ? MAX_MESSAGE_SIZE : ComputerCraft.httpMaxWebsocketMessage + options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage ); p.addLast( new HttpClientCodec(), new HttpObjectAggregator( 8192 ), WebSocketClientCompressionHandler.INSTANCE, - new WebsocketHandler( Websocket.this, handshaker ) + new WebsocketHandler( Websocket.this, handshaker, options ) ); } } ) @@ -178,15 +180,15 @@ public class Websocket extends Resource catch( Exception e ) { failure( "Could not connect" ); - if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error in websocket", e ); + if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error in websocket", e ); } } - void success( Channel channel ) + void success( Channel channel, Options options ) { if( isClosed() ) return; - WebsocketHandle handle = new WebsocketHandle( this, channel ); + WebsocketHandle handle = new WebsocketHandle( this, options, channel ); environment().queueEvent( SUCCESS_EVENT, address, handle ); websocketHandle = createOwnerReference( handle ); diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index 78bb17bdf..a6436a785 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -6,8 +6,8 @@ package dan200.computercraft.core.apis.http.websocket; import com.google.common.base.Objects; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.*; +import dan200.computercraft.core.apis.http.options.Options; import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.util.StringUtil; import io.netty.buffer.Unpooled; @@ -28,13 +28,15 @@ import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EV public class WebsocketHandle implements Closeable { private final Websocket websocket; + private final Options options; private boolean closed = false; private Channel channel; - public WebsocketHandle( Websocket websocket, Channel channel ) + public WebsocketHandle( Websocket websocket, Options options, Channel channel ) { this.websocket = websocket; + this.options = options; this.channel = channel; } @@ -55,7 +57,7 @@ public class WebsocketHandle implements Closeable checkOpen(); String text = StringUtil.toString( args.get( 0 ) ); - if( ComputerCraft.httpMaxWebsocketMessage != 0 && text.length() > ComputerCraft.httpMaxWebsocketMessage ) + if( options.websocketMessage != 0 && text.length() > options.websocketMessage ) { throw new LuaException( "Message is too large" ); } diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java index c3e69d7b9..52c27b97c 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java @@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.http.websocket; import dan200.computercraft.core.apis.http.HTTPRequestException; import dan200.computercraft.core.apis.http.NetworkUtils; +import dan200.computercraft.core.apis.http.options.Options; import dan200.computercraft.core.tracking.TrackingField; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ConnectTimeoutException; @@ -23,11 +24,13 @@ public class WebsocketHandler extends SimpleChannelInboundHandler { private final Websocket websocket; private final WebSocketClientHandshaker handshaker; + private final Options options; - public WebsocketHandler( Websocket websocket, WebSocketClientHandshaker handshaker ) + public WebsocketHandler( Websocket websocket, WebSocketClientHandshaker handshaker, Options options ) { this.handshaker = handshaker; this.websocket = websocket; + this.options = options; } @Override @@ -52,7 +55,7 @@ public class WebsocketHandler extends SimpleChannelInboundHandler if( !handshaker.isHandshakeComplete() ) { handshaker.finishHandshake( ctx.channel(), (FullHttpResponse) msg ); - websocket.success( ctx.channel() ); + websocket.success( ctx.channel(), options ); return; } diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java index 91ac8161e..6c7d6ca9b 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java @@ -518,7 +518,7 @@ public final class ComputerThread private static void timeoutTask( ComputerExecutor executor, Thread thread, long time ) { - if( !ComputerCraft.logPeripheralErrors ) return; + if( !ComputerCraft.logComputerErrors ) return; StringBuilder builder = new StringBuilder() .append( "Terminating computer #" ).append( executor.getComputer().getID() ) diff --git a/src/main/java/dan200/computercraft/core/lua/BasicFunction.java b/src/main/java/dan200/computercraft/core/lua/BasicFunction.java index 3c988f025..6f4b25652 100644 --- a/src/main/java/dan200/computercraft/core/lua/BasicFunction.java +++ b/src/main/java/dan200/computercraft/core/lua/BasicFunction.java @@ -54,7 +54,7 @@ class BasicFunction extends VarArgFunction } catch( Throwable t ) { - if( ComputerCraft.logPeripheralErrors ) + if( ComputerCraft.logComputerErrors ) { ComputerCraft.log.error( "Error calling " + name + " on " + instance, t ); } diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index dc8291b21..58b284a1e 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -323,7 +323,7 @@ public class CobaltLuaMachine implements ILuaMachine return wrapped; } - if( ComputerCraft.logPeripheralErrors ) + if( ComputerCraft.logComputerErrors ) { ComputerCraft.log.warn( "Received unknown type '{}', returning nil.", object.getClass().getName() ); } @@ -532,7 +532,7 @@ public class CobaltLuaMachine implements ILuaMachine } catch( Throwable t ) { - if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running task", t ); + if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error running task", t ); m_computer.queueEvent( "task_complete", new Object[] { taskID, false, "Java Exception Thrown: " + t, } ); diff --git a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java index 09e6ecd0b..58c630c28 100644 --- a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java +++ b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java @@ -64,7 +64,7 @@ class ResultInterpreterFunction extends ResumableVarArgFunction httpWebsocketEnabled; private static final ConfigValue> httpRules; - private static final ConfigValue httpTimeout; private static final ConfigValue httpMaxRequests; - private static final ConfigValue httpMaxDownload; - private static final ConfigValue httpMaxUpload; private static final ConfigValue httpMaxWebsockets; - private static final ConfigValue httpMaxWebsocketMessage; private static final ConfigValue commandBlockEnabled; private static final ConfigValue modemRange; @@ -121,7 +116,7 @@ public final class Config logComputerErrors = builder .comment( "Log exceptions thrown by peripherals and other Lua objects.\n" + "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ) - .define( "log_computer_errors", ComputerCraft.logPeripheralErrors ); + .define( "log_computer_errors", ComputerCraft.logComputerErrors ); } { @@ -164,42 +159,25 @@ public final class Config .define( "websocket_enabled", ComputerCraft.httpWebsocketEnabled ); httpRules = builder - .comment( "A list of rules which control which domains or IPs are allowed through the \"http\" API on computers.\n" + - "Each rule is an item with a 'host' to match against, and an action. " + + .comment( "A list of rules which control behaviour of the \"http\" API for specific domains or IPs.\n" + + "Each rule is an item with a 'host' to match against, and a series of properties. " + "The host may be a domain name (\"pastebin.com\"),\n" + - "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). 'action' maybe 'allow' or 'block'. If no rules" + - "match, the domain will be blocked." ) + "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). If no rules, the domain is blocked." ) .defineList( "rules", Stream.concat( - Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> makeRule( x, "deny" ) ), - Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> makeRule( x, "allow" ) ) + Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> AddressRuleConfig.makeRule( x, Action.DENY ) ), + Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> AddressRuleConfig.makeRule( x, Action.ALLOW ) ) ).collect( Collectors.toList() ), - x -> x instanceof UnmodifiableConfig && parseRule( (UnmodifiableConfig) x ) != null ); - - httpTimeout = builder - .comment( "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." ) - .defineInRange( "timeout", ComputerCraft.httpTimeout, 0, Integer.MAX_VALUE ); + x -> x instanceof UnmodifiableConfig && AddressRuleConfig.checkRule( (UnmodifiableConfig) x ) ); httpMaxRequests = builder .comment( "The number of http requests a computer can make at one time. Additional requests will be queued, and sent when the running requests have finished. Set to 0 for unlimited." ) .defineInRange( "max_requests", ComputerCraft.httpMaxRequests, 0, Integer.MAX_VALUE ); - httpMaxDownload = builder - .comment( "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." ) - .defineInRange( "max_download", (int) ComputerCraft.httpMaxDownload, 0, Integer.MAX_VALUE ); - - httpMaxUpload = builder - .comment( "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." ) - .defineInRange( "max_upload", (int) ComputerCraft.httpMaxUpload, 0, Integer.MAX_VALUE ); - httpMaxWebsockets = builder .comment( "The number of websockets a computer can have open at one time. Set to 0 for unlimited." ) .defineInRange( "max_websockets", ComputerCraft.httpMaxWebsockets, 1, Integer.MAX_VALUE ); - httpMaxWebsocketMessage = builder - .comment( "The maximum size (in bytes) that a computer can send or receive in one websocket packet." ) - .defineInRange( "max_websocket_message", ComputerCraft.httpMaxWebsocketMessage, 0, Websocket.MAX_MESSAGE_SIZE ); - builder.pop(); } @@ -291,7 +269,7 @@ public final class Config ComputerCraft.default_computer_settings = defaultComputerSettings.get(); ComputerCraft.debug_enable = debugEnabled.get(); ComputerCraft.computer_threads = computerThreads.get(); - ComputerCraft.logPeripheralErrors = logComputerErrors.get(); + ComputerCraft.logComputerErrors = logComputerErrors.get(); // Execution ComputerCraft.computer_threads = computerThreads.get(); @@ -302,14 +280,10 @@ public final class Config ComputerCraft.httpEnabled = httpEnabled.get(); ComputerCraft.httpWebsocketEnabled = httpWebsocketEnabled.get(); ComputerCraft.httpRules = Collections.unmodifiableList( httpRules.get().stream() - .map( Config::parseRule ).filter( Objects::nonNull ).collect( Collectors.toList() ) ); + .map( AddressRuleConfig::parseRule ).filter( Objects::nonNull ).collect( Collectors.toList() ) ); - ComputerCraft.httpTimeout = httpTimeout.get(); ComputerCraft.httpMaxRequests = httpMaxRequests.get(); - ComputerCraft.httpMaxDownload = httpMaxDownload.get(); - ComputerCraft.httpMaxUpload = httpMaxUpload.get(); ComputerCraft.httpMaxWebsockets = httpMaxWebsockets.get(); - ComputerCraft.httpMaxWebsocketMessage = httpMaxWebsocketMessage.get(); // Peripheral ComputerCraft.enableCommandBlock = commandBlockEnabled.get(); @@ -362,28 +336,4 @@ public final class Config return null; } } - - private static UnmodifiableConfig makeRule( String host, String action ) - { - com.electronwill.nightconfig.core.Config config = com.electronwill.nightconfig.core.Config.inMemory(); - config.add( "host", host ); - config.add( "action", action ); - return config; - } - - @Nullable - private static AddressRule parseRule( UnmodifiableConfig builder ) - { - Object hostObj = builder.get( "host" ); - Object actionObj = builder.get( "action" ); - if( !(hostObj instanceof String) || !(actionObj instanceof String) ) return null; - - String host = (String) hostObj, action = (String) actionObj; - for( AddressRule.Action candiate : AddressRule.Action.values() ) - { - if( candiate.name().equalsIgnoreCase( action ) ) return AddressRule.parse( host, candiate ); - } - - return null; - } } diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index c7ef8986a..7354853ef 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -64,7 +64,7 @@ public class CommandAPI implements ILuaAPI } catch( Throwable t ) { - if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running command.", t ); + if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error running command.", t ); return new Object[] { false, createOutput( "Java Exception Thrown: " + t ) }; } } diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 91fdc4cad..2807f189b 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -85,7 +85,7 @@ public class ComputerTestDelegate @BeforeEach public void before() throws IOException { - ComputerCraft.logPeripheralErrors = true; + ComputerCraft.logComputerErrors = true; if( REPORT_PATH.delete() ) ComputerCraft.log.info( "Deleted previous coverage report." ); diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index e2deba3cb..21b55613b 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -42,7 +42,7 @@ public class ComputerBootstrap public static void run( IWritableMount mount, Consumer setup, int maxTicks ) { - ComputerCraft.logPeripheralErrors = true; + ComputerCraft.logComputerErrors = true; ComputerCraft.maxMainComputerTime = ComputerCraft.maxMainGlobalTime = Integer.MAX_VALUE; Terminal term = new Terminal( ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); From 5a816917d562df440df0fd006f9165664a65f48f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 22:49:12 +0100 Subject: [PATCH 237/711] Normalise config names --- .../dan200/computercraft/ComputerCraft.java | 16 ++++----- .../core/computer/ComputerThread.java | 2 +- .../core/lua/CobaltLuaMachine.java | 6 ++-- .../dan200/computercraft/shared/Config.java | 34 +++++++++---------- .../wireless/WirelessModemPeripheral.java | 8 ++--- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 067fa3bc4..35f93e0fc 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -68,13 +68,13 @@ public final class ComputerCraft public static int computerSpaceLimit = 1000 * 1000; public static int floppySpaceLimit = 125 * 1000; public static int maximumFilesOpen = 128; - public static boolean disable_lua51_features = false; - public static String default_computer_settings = ""; - public static boolean debug_enable = true; + public static boolean disableLua51Features = false; + public static String defaultComputerSettings = ""; + public static boolean debugEnable = true; public static boolean logComputerErrors = true; public static boolean commandRequireCreative = true; - public static int computer_threads = 1; + public static int computerThreads = 1; public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( 10 ); public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( 5 ); @@ -93,10 +93,10 @@ public final class ComputerCraft public static int httpMaxWebsockets = 4; public static boolean enableCommandBlock = false; - public static int modem_range = 64; - public static int modem_highAltitudeRange = 384; - public static int modem_rangeDuringStorm = 64; - public static int modem_highAltitudeRangeDuringStorm = 384; + public static int modemRange = 64; + public static int modemHighAltitudeRange = 384; + public static int modemRangeDuringStorm = 64; + public static int modemHighAltitudeRangeDuringStorm = 384; public static int maxNotesPerTick = 8; public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java index 6c7d6ca9b..ed6a903cb 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java @@ -136,7 +136,7 @@ public final class ComputerThread if( runners == null ) { // TODO: Change the runners length on config reloads - runners = new TaskRunner[ComputerCraft.computer_threads]; + runners = new TaskRunner[ComputerCraft.computerThreads]; // latency and minPeriod are scaled by 1 + floor(log2(threads)). We can afford to execute tasks for // longer when executing on more than one thread. diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 58b284a1e..40bf39c23 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -95,7 +95,7 @@ public class CobaltLuaMachine implements ILuaMachine m_globals.load( state, new CoroutineLib() ); m_globals.load( state, new Bit32Lib() ); m_globals.load( state, new Utf8Lib() ); - if( ComputerCraft.debug_enable ) m_globals.load( state, new DebugLib() ); + if( ComputerCraft.debugEnable ) m_globals.load( state, new DebugLib() ); // Remove globals we don't want to expose m_globals.rawset( "collectgarbage", Constants.NIL ); @@ -106,8 +106,8 @@ public class CobaltLuaMachine implements ILuaMachine // Add version globals m_globals.rawset( "_VERSION", valueOf( "Lua 5.1" ) ); m_globals.rawset( "_HOST", valueOf( computer.getAPIEnvironment().getComputerEnvironment().getHostString() ) ); - m_globals.rawset( "_CC_DEFAULT_SETTINGS", valueOf( ComputerCraft.default_computer_settings ) ); - if( ComputerCraft.disable_lua51_features ) + m_globals.rawset( "_CC_DEFAULT_SETTINGS", valueOf( ComputerCraft.defaultComputerSettings ) ); + if( ComputerCraft.disableLua51Features ) { m_globals.rawset( "_CC_DISABLE_LUA51_FEATURES", Constants.TRUE ); } diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 49afec510..a7dbfe32f 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -101,17 +101,17 @@ public final class Config disableLua51Features = builder .comment( "Set this to true to disable Lua 5.1 functions that will be removed in a future update. " + "Useful for ensuring forward compatibility of your programs now." ) - .define( "disable_lua51_features", ComputerCraft.disable_lua51_features ); + .define( "disable_lua51_features", ComputerCraft.disableLua51Features ); defaultComputerSettings = builder .comment( "A comma separated list of default system settings to set on new computers. Example: " + "\"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" will disable all " + "autocompletion" ) - .define( "default_computer_settings", ComputerCraft.default_computer_settings ); + .define( "default_computer_settings", ComputerCraft.defaultComputerSettings ); debugEnabled = builder .comment( "Enable Lua's debug library. This is sandboxed to each computer, so is generally safe to be used by players." ) - .define( "debug_enabled", ComputerCraft.debug_enable ); + .define( "debug_enabled", ComputerCraft.debugEnable ); logComputerErrors = builder .comment( "Log exceptions thrown by peripherals and other Lua objects.\n" + @@ -129,7 +129,7 @@ public final class Config "at once, but may induce lag.\n" + "Please note that some mods may not work with a thread count higher than 1. Use with caution." ) .worldRestart() - .defineInRange( "computer_threads", ComputerCraft.computer_threads, 1, Integer.MAX_VALUE ); + .defineInRange( "computer_threads", ComputerCraft.computerThreads, 1, Integer.MAX_VALUE ); maxMainGlobalTime = builder .comment( "The maximum time that can be spent executing tasks in a single tick, in milliseconds.\n" + @@ -191,19 +191,19 @@ public final class Config modemRange = builder .comment( "The range of Wireless Modems at low altitude in clear weather, in meters" ) - .defineInRange( "modem_range", ComputerCraft.modem_range, 0, MODEM_MAX_RANGE ); + .defineInRange( "modem_range", ComputerCraft.modemRange, 0, MODEM_MAX_RANGE ); modemHighAltitudeRange = builder .comment( "The range of Wireless Modems at maximum altitude in clear weather, in meters" ) - .defineInRange( "modem_high_altitude_range", ComputerCraft.modem_highAltitudeRange, 0, MODEM_MAX_RANGE ); + .defineInRange( "modem_high_altitude_range", ComputerCraft.modemHighAltitudeRange, 0, MODEM_MAX_RANGE ); modemRangeDuringStorm = builder .comment( "The range of Wireless Modems at low altitude in stormy weather, in meters" ) - .defineInRange( "modem_range_during_storm", ComputerCraft.modem_rangeDuringStorm, 0, MODEM_MAX_RANGE ); + .defineInRange( "modem_range_during_storm", ComputerCraft.modemRangeDuringStorm, 0, MODEM_MAX_RANGE ); modemHighAltitudeRangeDuringStorm = builder .comment( "The range of Wireless Modems at maximum altitude in stormy weather, in meters" ) - .defineInRange( "modem_high_altitude_range_during_storm", ComputerCraft.modem_highAltitudeRangeDuringStorm, 0, MODEM_MAX_RANGE ); + .defineInRange( "modem_high_altitude_range_during_storm", ComputerCraft.modemHighAltitudeRangeDuringStorm, 0, MODEM_MAX_RANGE ); maxNotesPerTick = builder .comment( "Maximum amount of notes a speaker can play at once" ) @@ -265,14 +265,14 @@ public final class Config ComputerCraft.computerSpaceLimit = computerSpaceLimit.get(); ComputerCraft.floppySpaceLimit = floppySpaceLimit.get(); ComputerCraft.maximumFilesOpen = maximumFilesOpen.get(); - ComputerCraft.disable_lua51_features = disableLua51Features.get(); - ComputerCraft.default_computer_settings = defaultComputerSettings.get(); - ComputerCraft.debug_enable = debugEnabled.get(); - ComputerCraft.computer_threads = computerThreads.get(); + ComputerCraft.disableLua51Features = disableLua51Features.get(); + ComputerCraft.defaultComputerSettings = defaultComputerSettings.get(); + ComputerCraft.debugEnable = debugEnabled.get(); + ComputerCraft.computerThreads = computerThreads.get(); ComputerCraft.logComputerErrors = logComputerErrors.get(); // Execution - ComputerCraft.computer_threads = computerThreads.get(); + ComputerCraft.computerThreads = computerThreads.get(); ComputerCraft.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos( maxMainGlobalTime.get() ); ComputerCraft.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos( maxMainComputerTime.get() ); @@ -288,10 +288,10 @@ public final class Config // Peripheral ComputerCraft.enableCommandBlock = commandBlockEnabled.get(); ComputerCraft.maxNotesPerTick = maxNotesPerTick.get(); - ComputerCraft.modem_range = modemRange.get(); - ComputerCraft.modem_highAltitudeRange = modemHighAltitudeRange.get(); - ComputerCraft.modem_rangeDuringStorm = modemRangeDuringStorm.get(); - ComputerCraft.modem_highAltitudeRangeDuringStorm = modemHighAltitudeRangeDuringStorm.get(); + ComputerCraft.modemRange = modemRange.get(); + ComputerCraft.modemHighAltitudeRange = modemHighAltitudeRange.get(); + ComputerCraft.modemRangeDuringStorm = modemRangeDuringStorm.get(); + ComputerCraft.modemHighAltitudeRangeDuringStorm = modemHighAltitudeRangeDuringStorm.get(); // Turtles ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.get(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index 1bd677a8c..68d77d366 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -41,12 +41,12 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral if( world != null ) { Vec3d position = getPosition(); - double minRange = ComputerCraft.modem_range; - double maxRange = ComputerCraft.modem_highAltitudeRange; + double minRange = ComputerCraft.modemRange; + double maxRange = ComputerCraft.modemHighAltitudeRange; if( world.isRaining() && world.isThundering() ) { - minRange = ComputerCraft.modem_rangeDuringStorm; - maxRange = ComputerCraft.modem_highAltitudeRangeDuringStorm; + minRange = ComputerCraft.modemRangeDuringStorm; + maxRange = ComputerCraft.modemHighAltitudeRangeDuringStorm; } if( position.y > 96.0 && maxRange > minRange ) { From f36f532c633b3d59679de983bfc6ab31d6cba0df Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 15 May 2020 23:05:14 +0100 Subject: [PATCH 238/711] Migrate config to the server (rather than common) --- src/main/java/dan200/computercraft/shared/Config.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index a7dbfe32f..2517133bd 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -73,7 +73,7 @@ public final class Config private static final ConfigValue monitorRenderer; - private static final ForgeConfigSpec commonSpec; + private static final ForgeConfigSpec serverSpec; private static final ForgeConfigSpec clientSpec; private Config() {} @@ -243,7 +243,7 @@ public final class Config builder.pop(); } - commonSpec = builder.build(); + serverSpec = builder.build(); Builder clientBuilder = new Builder(); monitorRenderer = clientBuilder @@ -255,7 +255,7 @@ public final class Config public static void load() { - ModLoadingContext.get().registerConfig( ModConfig.Type.COMMON, commonSpec ); + ModLoadingContext.get().registerConfig( ModConfig.Type.SERVER, serverSpec ); ModLoadingContext.get().registerConfig( ModConfig.Type.CLIENT, clientSpec ); } From e02ccdcb1a0c817acb677ead61f290210645af13 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 16 May 2020 10:19:25 +0100 Subject: [PATCH 239/711] Fix incorrect shadowing --- .../java/dan200/computercraft/core/apis/http/CheckUrl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java index 2d902581c..a2b9f896d 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java +++ b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java @@ -47,8 +47,8 @@ public class CheckUrl extends Resource try { - InetSocketAddress address = NetworkUtils.getAddress( host, 80, false ); - NetworkUtils.getOptions( host, address ); + InetSocketAddress netAddress = NetworkUtils.getAddress( host, 80, false ); + NetworkUtils.getOptions( host, netAddress ); if( tryClose() ) environment.queueEvent( EVENT, address, true ); } From 87aa839b603aabc5b6ce6bf6e8cea7eb00ae520a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 16 May 2020 10:20:16 +0100 Subject: [PATCH 240/711] Upgrade the release to beta It should be release quality in all honesty[^1], but let's leave it a few days to see if any issues trickle in. [^1]: Well, aside from upsidedown turtles! --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5e75050db..6813fdfa6 100644 --- a/build.gradle +++ b/build.gradle @@ -384,7 +384,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'alpha' + releaseType = 'beta' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { From 53477fd3a185ea9243fccae8af6e724a25d3e1a5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 17 May 2020 16:58:19 +0100 Subject: [PATCH 241/711] Fix several AIOB exceptions Closes #450 --- .../computercraft/core/asm/IntCache.java | 4 +-- .../computercraft/core/asm/IntCacheTest.java | 27 +++++++++++++++ .../computercraft/core/asm/MethodTest.java | 34 +++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/test/java/dan200/computercraft/core/asm/IntCacheTest.java diff --git a/src/main/java/dan200/computercraft/core/asm/IntCache.java b/src/main/java/dan200/computercraft/core/asm/IntCache.java index d50f54b2a..3652a530d 100644 --- a/src/main/java/dan200/computercraft/core/asm/IntCache.java +++ b/src/main/java/dan200/computercraft/core/asm/IntCache.java @@ -24,7 +24,7 @@ public final class IntCache { if( index < 0 ) throw new IllegalArgumentException( "index < 0" ); - if( index <= cache.length ) + if( index < cache.length ) { T current = (T) cache[index]; if( current != null ) return current; @@ -32,7 +32,7 @@ public final class IntCache synchronized( this ) { - if( index > cache.length ) cache = Arrays.copyOf( cache, Math.max( cache.length * 2, index ) ); + if( index >= cache.length ) cache = Arrays.copyOf( cache, Math.max( cache.length * 2, index + 1 ) ); T current = (T) cache[index]; if( current == null ) cache[index] = current = factory.apply( index ); return current; diff --git a/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java b/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java new file mode 100644 index 000000000..94f17da65 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java @@ -0,0 +1,27 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IntCacheTest +{ + @Test + public void testCache() + { + IntCache c = new IntCache<>( i -> new Object() ); + assertEquals( c.get( 0 ), c.get( 0 ) ); + } + + @Test + public void testMassive() + { + assertEquals( 40, new IntCache<>( i -> i ).get( 40 ) ); + } +} diff --git a/src/test/java/dan200/computercraft/core/asm/MethodTest.java b/src/test/java/dan200/computercraft/core/asm/MethodTest.java index 58be91ecd..cd2e780a4 100644 --- a/src/test/java/dan200/computercraft/core/asm/MethodTest.java +++ b/src/test/java/dan200/computercraft/core/asm/MethodTest.java @@ -78,6 +78,15 @@ public class MethodTest ); } + @Test + public void testMany() + { + ComputerBootstrap.run( + "assert(many.method_0)\n" + + "assert(many.method_39)", + x -> x.addApi( new ManyMethods() ), 50 ); + } + public static class MainThread implements ILuaAPI, IPeripheral { public final String thread = Thread.currentThread().getName(); @@ -205,4 +214,29 @@ public class MethodTest return this == other; } } + + public static class ManyMethods implements IDynamicLuaObject, ILuaAPI + { + @Nonnull + @Override + public String[] getMethodNames() + { + String[] methods = new String[40]; + for( int i = 0; i < methods.length; i++ ) methods[i] = "method_" + i; + return methods; + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) throws LuaException + { + return MethodResult.of(); + } + + @Override + public String[] getNames() + { + return new String[] { "many" }; + } + } } From c493d668c8b1a0a6940b0bb97f20eb784b0c9749 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 17 May 2020 17:02:17 +0100 Subject: [PATCH 242/711] Bump version --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 4 ++++ .../computercraft/lua/rom/help/whatsnew.txt | 18 ++---------------- 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/gradle.properties b/gradle.properties index 79b9114e3..a42181268 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.88.0 +mod_version=1.88.1 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 1ce64df8a..82edfe40c 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.88.1 + +* Fix error on objects with too many methods. + # New features in CC: Tweaked 1.88.0 * Computers and turtles now preserve their ID when broken. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index eb087af78..e3563cb08 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,19 +1,5 @@ -New features in CC: Tweaked 1.88.0 +New features in CC: Tweaked 1.88.1 -* Computers and turtles now preserve their ID when broken. -* Add `peripheral.getName` - returns the name of a wrapped peripheral. -* Reduce network overhead of monitors and terminals. -* Add a TBO backend for monitors, with a significant performance boost. -* The Lua REPL warns when declaring locals (lupus590, exerro) -* Add config to allow using command computers in survival. -* Add fs.isDriveRoot - checks if a path is the root of a drive. -* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default. -* Move the shell's `require`/`package` implementation to a separate `cc.require` module. -* Move treasure programs into a separate external data pack. - -And several bug fixes: -* Fix io.lines not accepting arguments. -* Fix settings.load using an unknown global (MCJack123). -* Prevent computers scanning peripherals twice. +* Fix error on objects with too many methods. Type "help changelog" to see the full version history. From d50a08a5491cdede71cf8e83c33dd8f39c31612f Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 20 May 2020 08:44:44 +0100 Subject: [PATCH 243/711] Rewrite monitor networking (#453) This moves monitor networking into its own packet, rather than serialising using NBT. This allows us to be more flexible with how monitors are serialised. We now compress terminal data using gzip. This reduces the packet size of a max-sized-monitor from ~25kb to as little as 100b. On my test set of images (what I would consider to be the extreme end of the "reasonable" case), we have packets from 1.4kb bytes up to 12kb, with a mean of 6kb. Even in the worst case, this is a 2x reduction in packet size. While this is a fantastic win for the common case, it is not abuse-proof. One can create a terminal with high entropy (and so uncompressible). This will still be close to the original packet size. In order to prevent any other abuse, we also limit the amount of monitor data a client can possibly receive to 1MB (configurable). --- .../dan200/computercraft/ComputerCraft.java | 3 +- .../core/apis/handles/HandleGeneric.java | 8 +- .../core/apis/http/Resource.java | 2 +- .../core/apis/http/websocket/Websocket.java | 2 +- .../core/filesystem/FileSystem.java | 3 +- .../dan200/computercraft/shared/Config.java | 15 +- .../shared/common/ClientTerminal.java | 15 +- .../shared/common/ServerTerminal.java | 33 +--- .../shared/computer/core/ServerComputer.java | 4 +- .../shared/network/NetworkHandler.java | 6 + .../client/ComputerTerminalClientMessage.java | 14 +- .../network/client/MonitorClientMessage.java | 60 ++++++ .../shared/network/client/TerminalState.java | 183 ++++++++++++++++++ .../peripheral/monitor/MonitorWatcher.java | 102 ++++++++++ .../peripheral/monitor/TileMonitor.java | 29 ++- .../computercraft/shared/util/IoUtil.java | 5 +- .../assets/computercraft/lang/en_us.lang | 1 + .../network/client/TerminalStateTest.java | 94 +++++++++ 18 files changed, 507 insertions(+), 72 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java create mode 100644 src/main/java/dan200/computercraft/shared/network/client/TerminalState.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java create mode 100644 src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index f2ae2b16e..5f5d0e428 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -138,6 +138,7 @@ public class ComputerCraft public static int modem_highAltitudeRangeDuringStorm = 384; public static int maxNotesPerTick = 8; public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; + public static long monitorBandwidth = 1_000_000; public static boolean turtlesNeedFuel = true; public static int turtleFuelLimit = 20000; @@ -537,7 +538,7 @@ public class ComputerCraft } catch( IOException e ) { - if( zipFile != null ) IoUtil.closeQuietly( zipFile ); + IoUtil.closeQuietly( zipFile ); } } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index 2ebad4202..a26cd7364 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -37,12 +37,8 @@ public abstract class HandleGeneric implements ILuaObject { m_open = false; - Closeable closeable = m_closable; - if( closeable != null ) - { - IoUtil.closeQuietly( closeable ); - m_closable = null; - } + IoUtil.closeQuietly( m_closable ); + m_closable = null; } /** diff --git a/src/main/java/dan200/computercraft/core/apis/http/Resource.java b/src/main/java/dan200/computercraft/core/apis/http/Resource.java index 6587fb19d..469a57511 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/Resource.java +++ b/src/main/java/dan200/computercraft/core/apis/http/Resource.java @@ -106,7 +106,7 @@ public abstract class Resource> implements Closeable protected static T closeCloseable( T closeable ) { - if( closeable != null ) IoUtil.closeQuietly( closeable ); + IoUtil.closeQuietly( closeable ); return null; } diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index c1d91a078..75dd42e04 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -221,7 +221,7 @@ public class Websocket extends Resource WeakReference websocketHandleRef = websocketHandle; WebsocketHandle websocketHandle = websocketHandleRef == null ? null : websocketHandleRef.get(); - if( websocketHandle != null ) IoUtil.closeQuietly( websocketHandle ); + IoUtil.closeQuietly( websocketHandle ); this.websocketHandle = null; } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 0403f98ac..644515e1c 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -366,8 +366,7 @@ public class FileSystem Reference ref; while( (ref = m_openFileQueue.poll()) != null ) { - Closeable file = m_openFiles.remove( ref ); - if( file != null ) IoUtil.closeQuietly( file ); + IoUtil.closeQuietly( m_openFiles.remove( ref ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index ceb42e27b..bc39cc616 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -72,6 +72,7 @@ public final class Config private static Property modemHighAltitudeRangeDuringStorm; private static Property maxNotesPerTick; private static Property monitorRenderer; + private static Property monitorBandwidth; private static Property turtlesNeedFuel; private static Property turtleFuelLimit; @@ -276,10 +277,21 @@ public final class Config "monitors have performance issues, you may wish to experiment with alternative renderers." ); monitorRenderer.setValidValues( MonitorRenderer.NAMES ); + monitorBandwidth = config.get( CATEGORY_PERIPHERAL, "monitor_bandwidth", (int) ComputerCraft.monitorBandwidth ); + monitorBandwidth.setComment( "The limit to how much monitor data can be sent *per tick*. Note:\n" + + " - Bandwidth is measured before compression, so the data sent to the client is smaller.\n" + + " - This ignores the number of players a packet is sent to. Updating a monitor for one player consumes " + + "the same bandwidth limit as sending to 20.\n" + + " - A full sized monitor sends ~25kb of data. So the default (1MB) allows for ~40 monitors to be updated " + + "in a single tick. \n" + + "Set to 0 to disable." ); + monitorBandwidth.setValidValues( MonitorRenderer.NAMES ); + monitorBandwidth.setMinValue( 0 ); + setOrder( CATEGORY_PERIPHERAL, commandBlockEnabled, modemRange, modemHighAltitudeRange, modemRangeDuringStorm, modemHighAltitudeRangeDuringStorm, maxNotesPerTick, - monitorRenderer + monitorRenderer, monitorBandwidth ); } @@ -474,6 +486,7 @@ public final class Config ComputerCraft.modem_rangeDuringStorm = Math.min( modemRangeDuringStorm.getInt(), MODEM_MAX_RANGE ); ComputerCraft.modem_highAltitudeRangeDuringStorm = Math.min( modemHighAltitudeRangeDuringStorm.getInt(), MODEM_MAX_RANGE ); ComputerCraft.monitorRenderer = MonitorRenderer.ofString( monitorRenderer.getString() ); + ComputerCraft.monitorBandwidth = Math.max( 0, monitorBandwidth.getLong() ); // Turtles ComputerCraft.turtlesNeedFuel = turtlesNeedFuel.getBoolean(); diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 5df44befa..08fb599fe 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -6,9 +6,7 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; -import io.netty.buffer.Unpooled; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; +import dan200.computercraft.shared.network.client.TerminalState; public class ClientTerminal implements ITerminal { @@ -48,14 +46,13 @@ public class ClientTerminal implements ITerminal return m_colour; } - public void readDescription( NBTTagCompound nbt ) + public void read( TerminalState state ) { - m_colour = nbt.getBoolean( "colour" ); - if( nbt.hasKey( "terminal" ) ) + m_colour = state.colour; + if( state.hasTerminal() ) { - NBTTagCompound terminal = nbt.getCompoundTag( "terminal" ); - resizeTerminal( terminal.getInteger( "term_width" ), terminal.getInteger( "term_height" ) ); - m_terminal.read( new PacketBuffer( Unpooled.wrappedBuffer( terminal.getByteArray( "term_contents" ) ) ) ); + resizeTerminal( state.width, state.height ); + state.apply( m_terminal ); } else { diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index d4c89dba5..a2385b684 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -5,12 +5,8 @@ */ package dan200.computercraft.shared.common; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.terminal.Terminal; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.network.PacketBuffer; +import dan200.computercraft.shared.network.client.TerminalState; import java.util.concurrent.atomic.AtomicBoolean; @@ -73,8 +69,6 @@ public class ServerTerminal implements ITerminal return m_terminalChangedLastFrame; } - // ITerminal implementation - @Override public Terminal getTerminal() { @@ -87,29 +81,8 @@ public class ServerTerminal implements ITerminal return m_colour; } - public void writeDescription( NBTTagCompound nbt ) + public TerminalState write() { - nbt.setBoolean( "colour", m_colour ); - if( m_terminal != null ) - { - // We have a 10 byte header (2 integer positions, then blinking and current colours), followed by the - // contents and palette. - // Yes, this serialisation code is terrible, but we need to serialise to NBT in order to work with monitors - // (or rather tile entity serialisation). - final int length = 10 + (2 * m_terminal.getWidth() * m_terminal.getHeight()) + (16 * 3); - ByteBuf buffer = Unpooled.buffer( length ); - m_terminal.write( new PacketBuffer( buffer ) ); - - if( buffer.writableBytes() != 0 ) - { - ComputerCraft.log.warn( "Should have written {} bytes, but have {} ({} remaining).", length, buffer.writerIndex(), buffer.writableBytes() ); - } - - NBTTagCompound terminal = new NBTTagCompound(); - terminal.setInteger( "term_width", m_terminal.getWidth() ); - terminal.setInteger( "term_height", m_terminal.getHeight() ); - terminal.setByteArray( "term_contents", buffer.array() ); - nbt.setTag( "terminal", terminal ); - } + return new TerminalState( m_colour, m_terminal ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index f5938d62c..db02db719 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -155,9 +155,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput protected IMessage createTerminalPacket() { - NBTTagCompound tagCompound = new NBTTagCompound(); - writeDescription( tagCompound ); - return new ComputerTerminalClientMessage( getInstanceID(), tagCompound ); + return new ComputerTerminalClientMessage( getInstanceID(), write() ); } public void broadcastState( boolean force ) diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index b83aa81ca..ef9f35a88 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -45,6 +45,7 @@ public final class NetworkHandler registerMainThread( 12, Side.CLIENT, ComputerDeletedClientMessage::new ); registerMainThread( 13, Side.CLIENT, ComputerTerminalClientMessage::new ); registerMainThread( 14, Side.CLIENT, PlayRecordClientMessage::new ); + registerMainThread( 15, Side.CLIENT, MonitorClientMessage::new ); } public static void sendToPlayer( EntityPlayer player, IMessage packet ) @@ -67,6 +68,11 @@ public final class NetworkHandler network.sendToAllAround( packet, point ); } + public static void sendToAllTracking( IMessage packet, NetworkRegistry.TargetPoint point ) + { + network.sendToAllTracking( packet, point ); + } + /** * /** * Register packet, and a thread-unsafe handler for it. diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index 7c82c4dec..446545d6e 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -5,8 +5,6 @@ */ package dan200.computercraft.shared.network.client; -import dan200.computercraft.shared.util.NBTUtil; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; @@ -14,12 +12,12 @@ import javax.annotation.Nonnull; public class ComputerTerminalClientMessage extends ComputerClientMessage { - private NBTTagCompound tag; + private TerminalState state; - public ComputerTerminalClientMessage( int instanceId, NBTTagCompound tag ) + public ComputerTerminalClientMessage( int instanceId, TerminalState state ) { super( instanceId ); - this.tag = tag; + this.state = state; } public ComputerTerminalClientMessage() @@ -30,19 +28,19 @@ public class ComputerTerminalClientMessage extends ComputerClientMessage public void toBytes( @Nonnull PacketBuffer buf ) { super.toBytes( buf ); - buf.writeCompoundTag( tag ); // TODO: Do we need to compress this? + state.write( buf ); } @Override public void fromBytes( @Nonnull PacketBuffer buf ) { super.fromBytes( buf ); - tag = NBTUtil.readCompoundTag( buf ); + state = new TerminalState( buf ); } @Override public void handle( MessageContext context ) { - getComputer().readDescription( tag ); + getComputer().read( state ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java new file mode 100644 index 000000000..309b9fd1a --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java @@ -0,0 +1,60 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.client; + +import dan200.computercraft.shared.network.NetworkMessage; +import dan200.computercraft.shared.peripheral.monitor.TileMonitor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; + +import javax.annotation.Nonnull; + +public class MonitorClientMessage implements NetworkMessage +{ + private BlockPos pos; + private TerminalState state; + + public MonitorClientMessage( BlockPos pos, TerminalState state ) + { + this.pos = pos; + this.state = state; + } + + public MonitorClientMessage() + { + } + + @Override + public void toBytes( @Nonnull PacketBuffer buf ) + { + buf.writeBlockPos( pos ); + state.write( buf ); + } + + @Override + public void fromBytes( @Nonnull PacketBuffer buf ) + { + pos = buf.readBlockPos(); + state = new TerminalState( buf ); + } + + @Override + public void handle( MessageContext context ) + { + EntityPlayerSP player = Minecraft.getMinecraft().player; + if( player == null || player.world == null ) return; + + TileEntity te = player.world.getTileEntity( pos ); + if( !(te instanceof TileMonitor) ) return; + + ((TileMonitor) te).read( state ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java new file mode 100644 index 000000000..a720bc818 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java @@ -0,0 +1,183 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.client; + +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.util.IoUtil; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.buffer.Unpooled; +import net.minecraft.network.PacketBuffer; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + * A snapshot of a terminal's state. + * + * This is somewhat memory inefficient (we build a buffer, only to write it elsewhere), however it means we get a + * complete and accurate description of a terminal, which avoids a lot of complexities with resizing terminals, dirty + * states, etc... + */ +public class TerminalState +{ + public final boolean colour; + + public final int width; + public final int height; + + private final boolean compress; + + @Nullable + private final ByteBuf buffer; + + private ByteBuf compressed; + + public TerminalState( boolean colour, @Nullable Terminal terminal ) + { + this( colour, terminal, true ); + } + + public TerminalState( boolean colour, @Nullable Terminal terminal, boolean compress ) + { + this.colour = colour; + this.compress = compress; + + if( terminal == null ) + { + this.width = this.height = 0; + this.buffer = null; + } + else + { + this.width = terminal.getWidth(); + this.height = terminal.getHeight(); + + ByteBuf buf = this.buffer = Unpooled.buffer(); + terminal.write( new PacketBuffer( buf ) ); + } + } + + public TerminalState( PacketBuffer buf ) + { + this.colour = buf.readBoolean(); + this.compress = buf.readBoolean(); + + if( buf.readBoolean() ) + { + this.width = buf.readVarInt(); + this.height = buf.readVarInt(); + + int length = buf.readVarInt(); + this.buffer = readCompressed( buf, length, compress ); + } + else + { + this.width = this.height = 0; + this.buffer = null; + } + } + + public void write( PacketBuffer buf ) + { + buf.writeBoolean( colour ); + buf.writeBoolean( compress ); + + buf.writeBoolean( buffer != null ); + if( buffer != null ) + { + buf.writeVarInt( width ); + buf.writeVarInt( height ); + + ByteBuf sendBuffer = getCompressed(); + buf.writeVarInt( sendBuffer.readableBytes() ); + buf.writeBytes( sendBuffer, sendBuffer.readerIndex(), sendBuffer.readableBytes() ); + } + } + + public boolean hasTerminal() + { + return buffer != null; + } + + public int size() + { + return buffer == null ? 0 : buffer.readableBytes(); + } + + public void apply( Terminal terminal ) + { + if( buffer == null ) throw new NullPointerException( "buffer" ); + terminal.read( new PacketBuffer( buffer ) ); + } + + private ByteBuf getCompressed() + { + if( buffer == null ) throw new NullPointerException( "buffer" ); + if( !compress ) return buffer; + if( compressed != null ) return compressed; + + ByteBuf compressed = Unpooled.directBuffer(); + OutputStream stream = null; + try + { + stream = new GZIPOutputStream( new ByteBufOutputStream( compressed ) ); + stream.write( buffer.array(), buffer.arrayOffset(), buffer.readableBytes() ); + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + finally + { + IoUtil.closeQuietly( stream ); + } + + return this.compressed = compressed; + } + + private static ByteBuf readCompressed( ByteBuf buf, int length, boolean compress ) + { + if( compress ) + { + ByteBuf buffer = Unpooled.buffer(); + InputStream stream = null; + try + { + stream = new GZIPInputStream( new ByteBufInputStream( buf, length ) ); + byte[] swap = new byte[8192]; + while( true ) + { + int bytes = stream.read( swap ); + if( bytes == -1 ) break; + buffer.writeBytes( swap, 0, bytes ); + } + } + catch( IOException e ) + { + throw new UncheckedIOException( e ); + } + finally + { + IoUtil.closeQuietly( stream ); + } + return buffer; + } + else + { + ByteBuf buffer = Unpooled.buffer( length ); + buf.readBytes( buffer, length ); + return buffer; + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java new file mode 100644 index 000000000..1f9f0081b --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java @@ -0,0 +1,102 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.monitor; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.network.client.MonitorClientMessage; +import dan200.computercraft.shared.network.client.TerminalState; +import net.minecraft.server.management.PlayerChunkMapEntry; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.common.DimensionManager; +import net.minecraftforge.event.world.ChunkWatchEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; +import net.minecraftforge.fml.common.network.NetworkRegistry; + +import java.util.ArrayDeque; +import java.util.Queue; + +@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID ) +public final class MonitorWatcher +{ + private static final Queue watching = new ArrayDeque<>(); + + private MonitorWatcher() + { + } + + static void enqueue( TileMonitor monitor ) + { + if( monitor.enqueued ) return; + + monitor.enqueued = true; + monitor.cached = null; + watching.add( monitor ); + } + + @SubscribeEvent + public static void onWatch( ChunkWatchEvent.Watch event ) + { + Chunk chunk = event.getChunkInstance(); + if( chunk == null ) return; + + for( TileEntity te : chunk.getTileEntityMap().values() ) + { + // Find all origin monitors who are not already on the queue. + if( !(te instanceof TileMonitor) ) continue; + + TileMonitor monitor = (TileMonitor) te; + ServerMonitor serverMonitor = getMonitor( monitor ); + if( serverMonitor == null || monitor.enqueued ) continue; + + // We use the cached terminal state if available - this is guaranteed to + TerminalState state = monitor.cached; + if( state == null ) state = monitor.cached = serverMonitor.write(); + NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getPos(), state ) ); + } + } + + @SubscribeEvent + public static void onTick( TickEvent.ServerTickEvent event ) + { + if( event.phase != TickEvent.Phase.END ) return; + + long limit = ComputerCraft.monitorBandwidth; + boolean obeyLimit = limit > 0; + + TileMonitor tile; + while( (!obeyLimit || limit > 0) && (tile = watching.poll()) != null ) + { + tile.enqueued = false; + ServerMonitor monitor = getMonitor( tile ); + if( monitor == null ) continue; + + BlockPos pos = tile.getPos(); + World world = tile.getWorld(); + WorldServer serverWorld = world instanceof WorldServer ? (WorldServer) world : DimensionManager.getWorld( world.provider.getDimension() ); + PlayerChunkMapEntry entry = serverWorld.getPlayerChunkMap().getEntry( pos.getX() >> 4, pos.getZ() >> 4 ); + if( entry == null || entry.getWatchingPlayers().isEmpty() ) continue; + + NetworkRegistry.TargetPoint point = new NetworkRegistry.TargetPoint( world.provider.getDimension(), pos.getX(), pos.getY(), pos.getZ(), 0 ); + TerminalState state = tile.cached = monitor.write(); + NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), point ); + + limit -= state.size(); + } + } + + private static ServerMonitor getMonitor( TileMonitor monitor ) + { + return !monitor.isInvalid() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 46e6999a2..e5db1eaff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -5,12 +5,14 @@ */ package dan200.computercraft.shared.peripheral.monitor; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; +import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.peripheral.PeripheralType; import dan200.computercraft.shared.peripheral.common.BlockPeripheral; import dan200.computercraft.shared.peripheral.common.ITilePeripheral; @@ -46,6 +48,10 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph private boolean m_destroyed = false; private boolean visiting = false; + // MonitorWatcher state. + boolean enqueued; + TerminalState cached; + private int m_width = 1; private int m_height = 1; private int m_xIndex = 0; @@ -148,7 +154,7 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph } } - if( m_serverMonitor.pollTerminalChanged() ) updateBlock(); + if( m_serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this ); } // IPeripheralTile implementation @@ -239,11 +245,6 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph nbt.setInteger( "width", m_width ); nbt.setInteger( "height", m_height ); nbt.setInteger( "monitorDir", m_dir ); - - if( m_xIndex == 0 && m_yIndex == 0 && m_serverMonitor != null ) - { - m_serverMonitor.writeDescription( nbt ); - } } @Override @@ -273,9 +274,8 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph if( m_xIndex == 0 && m_yIndex == 0 ) { - // If we're the origin terminal then read the description + // If we're the origin terminal then create it. if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( m_advanced, this ); - m_clientMonitor.readDescription( nbt ); } if( oldXIndex != m_xIndex || oldYIndex != m_yIndex || @@ -286,6 +286,19 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph updateBlock(); } } + + public final void read( TerminalState state ) + { + if( m_xIndex != 0 || m_yIndex != 0 ) + { + ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getPos() ); + return; + } + + if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( m_advanced, this ); + m_clientMonitor.read( state ); + } + // Sizing and placement stuff public EnumFacing getDirection() diff --git a/src/main/java/dan200/computercraft/shared/util/IoUtil.java b/src/main/java/dan200/computercraft/shared/util/IoUtil.java index a2afde286..910a716e2 100644 --- a/src/main/java/dan200/computercraft/shared/util/IoUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/IoUtil.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.util; +import javax.annotation.Nullable; import java.io.Closeable; import java.io.IOException; @@ -12,11 +13,11 @@ public final class IoUtil { private IoUtil() {} - public static void closeQuietly( Closeable closeable ) + public static void closeQuietly( @Nullable Closeable closeable ) { try { - closeable.close(); + if( closeable != null ) closeable.close(); } catch( IOException ignored ) { diff --git a/src/main/resources/assets/computercraft/lang/en_us.lang b/src/main/resources/assets/computercraft/lang/en_us.lang index 503e4aaef..c0afe492c 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.lang +++ b/src/main/resources/assets/computercraft/lang/en_us.lang @@ -191,6 +191,7 @@ gui.computercraft:config.peripheral.monitor_renderer.best=Best gui.computercraft:config.peripheral.monitor_renderer.tbo=Texture Buffers gui.computercraft:config.peripheral.monitor_renderer.vbo=Vertex Buffers gui.computercraft:config.peripheral.monitor_renderer.display_list=Display Lists +gui.computercraft:config.peripheral.monitor_bandwidth=Monitor bandwidth gui.computercraft:config.turtle=Turtles gui.computercraft:config.turtle.need_fuel=Enable fuel diff --git a/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java b/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java new file mode 100644 index 000000000..23cfbede8 --- /dev/null +++ b/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java @@ -0,0 +1,94 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.network.client; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.terminal.TextBuffer; +import io.netty.buffer.Unpooled; +import net.minecraft.network.PacketBuffer; +import org.apache.logging.log4j.LogManager; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.RepeatedTest; + +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests {@link TerminalState} round tripping works as expected. + */ +public class TerminalStateTest +{ + @BeforeAll + public static void before() + { + ComputerCraft.log = LogManager.getLogger( ComputerCraft.MOD_ID ); + } + + @RepeatedTest( 5 ) + public void testCompressed() + { + Terminal terminal = randomTerminal(); + + PacketBuffer buffer = new PacketBuffer( Unpooled.directBuffer() ); + new TerminalState( true, terminal, true ).write( buffer ); + + checkEqual( terminal, read( buffer ) ); + assertEquals( 0, buffer.readableBytes() ); + } + + @RepeatedTest( 5 ) + public void testUncompressed() + { + Terminal terminal = randomTerminal(); + + PacketBuffer buffer = new PacketBuffer( Unpooled.directBuffer() ); + new TerminalState( true, terminal, false ).write( buffer ); + + checkEqual( terminal, read( buffer ) ); + assertEquals( 0, buffer.readableBytes() ); + } + + private static Terminal randomTerminal() + { + Random random = new Random(); + Terminal terminal = new Terminal( 10, 5 ); + for( int y = 0; y < terminal.getHeight(); y++ ) + { + TextBuffer buffer = terminal.getLine( y ); + for( int x = 0; x < buffer.length(); x++ ) buffer.setChar( x, (char) (random.nextInt( 26 ) + 65) ); + } + + return terminal; + } + + private static void checkEqual( Terminal expected, Terminal actual ) + { + assertNotNull( expected, "Expected cannot be null" ); + assertNotNull( actual, "Actual cannot be null" ); + assertEquals( expected.getHeight(), actual.getHeight(), "Heights must match" ); + assertEquals( expected.getWidth(), actual.getWidth(), "Widths must match" ); + + for( int y = 0; y < expected.getHeight(); y++ ) + { + assertEquals( expected.getLine( y ).toString(), actual.getLine( y ).toString() ); + } + } + + private static Terminal read( PacketBuffer buffer ) + { + TerminalState state = new TerminalState( buffer ); + assertTrue( state.colour ); + + if( !state.hasTerminal() ) return null; + + Terminal other = new Terminal( state.width, state.height ); + state.apply( other ); + return other; + } +} From d929c02d2a506dc8fb548d8a2f4eddb3f2cb5e9c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 24 May 2020 12:16:51 +0100 Subject: [PATCH 244/711] Fix settings loading failing for defined settings Yes, this was the only piece of code which wasn't tested :/. Fixes #457. --- .../computercraft/lua/rom/apis/settings.lua | 2 +- .../test-rom/spec/apis/settings_spec.lua | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua index 92d211a24..f86044128 100644 --- a/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua +++ b/src/main/resources/assets/computercraft/lua/rom/apis/settings.lua @@ -205,7 +205,7 @@ function load(sPath) end for k, v in pairs(tFile) do - local ty_v = type(k) + local ty_v = type(v) if type(k) == "string" and (ty_v == "string" or ty_v == "number" or ty_v == "boolean" or ty_v == "table") then local opt = details[k] if not opt or not opt.type or ty_v == opt.type then diff --git a/src/test/resources/test-rom/spec/apis/settings_spec.lua b/src/test/resources/test-rom/spec/apis/settings_spec.lua index 40af033d1..1551a822a 100644 --- a/src/test/resources/test-rom/spec/apis/settings_spec.lua +++ b/src/test/resources/test-rom/spec/apis/settings_spec.lua @@ -153,11 +153,50 @@ describe("The settings library", function() expect.error(settings.load, 1):eq("bad argument #1 (expected string, got number)") end) + local function setup_with(contents) + settings.clear() + local h = fs.open("/test-files/.settings", "w") + h.write(contents) + h.close() + + return settings.load("/test-files/.settings") + end + + local function setup(contents) + return setup_with(textutils.serialize(contents)) + end + it("defaults to .settings", function() local s = stub(fs, "open") settings.load() expect(s):called_with(".settings", "r") end) + + it("loads undefined settings", function() + expect(setup { ["test"] = 1 }):eq(true) + expect(settings.get("test")):eq(1) + end) + + it("loads defined settings", function() + settings.define("test.defined", { type = "number" }) + expect(setup { ["test.defined"] = 1 }):eq(true) + expect(settings.get("test.defined")):eq(1) + end) + + it("skips defined settings with incorrect types", function() + settings.define("test.defined", { type = "number" }) + expect(setup { ["test.defined"] = "abc" }):eq(true) + expect(settings.get("test.defined")):eq(nil) + end) + + it("skips unserializable values", function() + expect(setup_with "{ test = function() end }"):eq(true) + expect(settings.get("test")):eq(nil) + end) + + it("skips non-table files", function() + expect(setup "not a table"):eq(false) + end) end) describe("settings.save", function() From 4ff33f165d60ac73c37b26bfc3b33987cdd60e63 Mon Sep 17 00:00:00 2001 From: Lignum Date: Mon, 25 May 2020 12:19:03 +0200 Subject: [PATCH 245/711] Fetch MVP matrix in monitor shader instead (#454) --- .../render/MonitorTextureBufferShader.java | 18 ------------------ .../assets/computercraft/shaders/monitor.vert | 5 +---- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index 5d4a43043..7991ed907 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -13,7 +13,6 @@ import dan200.computercraft.shared.util.Palette; import net.minecraft.client.renderer.OpenGlHelper; import org.apache.commons.io.IOUtils; import org.lwjgl.BufferUtils; -import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; @@ -27,12 +26,8 @@ class MonitorTextureBufferShader { static final int TEXTURE_INDEX = GL13.GL_TEXTURE3; - private static final FloatBuffer MATRIX_BUFFER = BufferUtils.createFloatBuffer( 16 ); private static final FloatBuffer PALETTE_BUFFER = BufferUtils.createFloatBuffer( 16 * 3 ); - private static int uniformMv; - private static int uniformP; - private static int uniformFont; private static int uniformWidth; private static int uniformHeight; @@ -45,16 +40,6 @@ class MonitorTextureBufferShader static void setupUniform( int width, int height, Palette palette, boolean greyscale ) { - MATRIX_BUFFER.rewind(); - GL11.glGetFloat( GL11.GL_MODELVIEW_MATRIX, MATRIX_BUFFER ); - MATRIX_BUFFER.rewind(); - OpenGlHelper.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER ); - - MATRIX_BUFFER.rewind(); - GL11.glGetFloat( GL11.GL_PROJECTION_MATRIX, MATRIX_BUFFER ); - MATRIX_BUFFER.rewind(); - OpenGlHelper.glUniformMatrix4( uniformP, false, MATRIX_BUFFER ); - OpenGlHelper.glUniform1i( uniformWidth, width ); OpenGlHelper.glUniform1i( uniformHeight, height ); @@ -123,9 +108,6 @@ class MonitorTextureBufferShader if( !ok ) return false; - uniformMv = getUniformLocation( program, "u_mv" ); - uniformP = getUniformLocation( program, "u_p" ); - uniformFont = getUniformLocation( program, "u_font" ); uniformWidth = getUniformLocation( program, "u_width" ); uniformHeight = getUniformLocation( program, "u_height" ); diff --git a/src/main/resources/assets/computercraft/shaders/monitor.vert b/src/main/resources/assets/computercraft/shaders/monitor.vert index 564f063e2..99f56f4ea 100644 --- a/src/main/resources/assets/computercraft/shaders/monitor.vert +++ b/src/main/resources/assets/computercraft/shaders/monitor.vert @@ -1,13 +1,10 @@ #version 140 -uniform mat4 u_mv; -uniform mat4 u_p; - in vec3 v_pos; out vec2 f_pos; void main() { - gl_Position = u_p * u_mv * vec4(v_pos.x, v_pos.y, 0, 1); + gl_Position = gl_ModelViewProjectionMatrix * vec4(v_pos.x, v_pos.y, 0, 1); f_pos = v_pos.xy; } From 085ae2e74a4c6840632c06cfa6b9b5529abc83b2 Mon Sep 17 00:00:00 2001 From: Lignum Date: Thu, 28 May 2020 12:06:14 +0200 Subject: [PATCH 246/711] Use an older version of GLSL (#459) This ensures that the MVP matrix is available within the monitor fragment shader, without requiring the ARB_compatibility extension. --- src/main/resources/assets/computercraft/shaders/monitor.vert | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/shaders/monitor.vert b/src/main/resources/assets/computercraft/shaders/monitor.vert index 99f56f4ea..b758cce8d 100644 --- a/src/main/resources/assets/computercraft/shaders/monitor.vert +++ b/src/main/resources/assets/computercraft/shaders/monitor.vert @@ -1,4 +1,4 @@ -#version 140 +#version 130 in vec3 v_pos; From 014bf55cd462fed2c6bcfcf7a076e54cfe7d6bb4 Mon Sep 17 00:00:00 2001 From: Lignum Date: Sun, 31 May 2020 17:23:49 +0100 Subject: [PATCH 247/711] Cherry pick several improvements from #455 - Use texture over texture2D - the latter was deprecated in GLSL 1.30. - Cache the tbo buffer - this saves an allocation when monitors update. Closes #455. While the rest of the PR has some nice changes, it performs signlificantly worse on my system. --- .../client/render/TileEntityMonitorRenderer.java | 10 +++++++++- .../assets/computercraft/shaders/monitor.frag | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 405a36a29..7dd003152 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -35,6 +35,7 @@ import static dan200.computercraft.shared.peripheral.monitor.TileMonitor.RENDER_ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer { private static final float MARGIN = (float) (TileMonitor.RENDER_MARGIN * 1.1); + private static ByteBuffer tboContents; @Override public void render( @Nonnull TileMonitor tileEntity, double posX, double posY, double posZ, float f, int i, float f2 ) @@ -162,7 +163,14 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer Date: Mon, 1 Jun 2020 11:14:36 +0100 Subject: [PATCH 248/711] Expose tags for turtle.{inspect,getItemDetail} This is simply exposed as a table from tag -> true. While this is less natural than an array, it allows for easy esting of whether a tag is present. Closes #461 --- .../computercraft/shared/turtle/apis/TurtleAPI.java | 9 +++++++-- .../shared/turtle/core/TurtleInspectCommand.java | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index bb43c34e1..21e84199c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -19,6 +19,7 @@ import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.shared.turtle.core.*; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.registries.ForgeRegistries; @@ -31,8 +32,8 @@ import static dan200.computercraft.api.lua.ArgumentHelper.*; public class TurtleAPI implements ILuaAPI { - private IAPIEnvironment m_environment; - private ITurtleAccess m_turtle; + private final IAPIEnvironment m_environment; + private final ITurtleAccess m_turtle; public TurtleAPI( IAPIEnvironment environment, ITurtleAccess turtle ) { @@ -351,6 +352,10 @@ public class TurtleAPI implements ILuaAPI table.put( "name", name ); table.put( "count", count ); + Map tags = new HashMap<>(); + for( ResourceLocation location : item.getTags() ) tags.put( location.toString(), true ); + table.put( "tags", tags ); + TurtleActionEvent event = new TurtleInspectItemEvent( m_turtle, stack, table ); if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() }; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index e45d9ba58..baa1ea966 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -14,6 +14,7 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.state.IProperty; import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; @@ -64,6 +65,10 @@ public class TurtleInspectCommand implements ITurtleCommand } table.put( "state", stateTable ); + Map tags = new HashMap<>(); + for( ResourceLocation location : block.getTags() ) tags.put( location.toString(), true ); + table.put( "tags", tags ); + // Fire the event, exiting if it is cancelled TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); TurtleBlockEvent.Inspect event = new TurtleBlockEvent.Inspect( turtle, turtlePlayer, world, newPosition, state, table ); From b9ff9b7f90b3254482c60d66b62546a49c015229 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 3 Jun 2020 21:44:08 +0100 Subject: [PATCH 249/711] Allow returning lua functions Not sure how this will play with persistence when it happens (badly, most likely), but it's not a bad idea to support it. Closes #466 --- .../computercraft/api/lua/ILuaFunction.java | 29 +++++++++++++++++++ .../computercraft/api/lua/MethodResult.java | 2 +- .../core/lua/CobaltLuaMachine.java | 7 +++++ .../computercraft/core/asm/MethodTest.java | 23 +++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/main/java/dan200/computercraft/api/lua/ILuaFunction.java diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java new file mode 100644 index 000000000..cd75848e1 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java @@ -0,0 +1,29 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ +package dan200.computercraft.api.lua; + +import javax.annotation.Nonnull; + +/** + * A function, which can be called from Lua. If you need to return a table of functions, it is recommended to use + * an object with {@link LuaFunction} methods, or implement {@link IDynamicLuaObject}. + * + * @see MethodResult#of(Object) + */ +@FunctionalInterface +public interface ILuaFunction +{ + /** + * Call this function with a series of arguments. Note, this will always be called on the computer thread, + * and so its implementation must be thread-safe. + * + * @param arguments The arguments for this function + * @return The result of calling this function. + * @throws LuaException Upon Lua errors. + */ + @Nonnull + MethodResult call( @Nonnull IArguments arguments ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/MethodResult.java b/src/main/java/dan200/computercraft/api/lua/MethodResult.java index 2a7f80155..fce9f970f 100644 --- a/src/main/java/dan200/computercraft/api/lua/MethodResult.java +++ b/src/main/java/dan200/computercraft/api/lua/MethodResult.java @@ -58,7 +58,7 @@ public final class MethodResult * * Integers, doubles, floats, strings, booleans, {@link Map}, {@link Collection}s, arrays and {@code null} will be * converted to their corresponding Lua type. {@code byte[]} and {@link ByteBuffer} will be treated as binary - * strings. + * strings. {@link ILuaFunction} will be treated as a function. * * In order to provide a custom object with methods, one may return a {@link IDynamicLuaObject}, or an arbitrary * class with {@link LuaFunction} annotations. Anything else will be converted to {@code nil}. diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 40bf39c23..e678667e1 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -48,6 +48,8 @@ public class CobaltLuaMachine implements ILuaMachine ThreadUtils.factory( "Coroutine" ) ); + private static final LuaMethod FUNCTION_METHOD = ( target, context, args ) -> ((ILuaFunction) target).call( args ); + private final Computer m_computer; private final TimeoutState timeout; private final TimeoutDebugHandler debug; @@ -275,6 +277,11 @@ public class CobaltLuaMachine implements ILuaMachine LuaValue result = values.get( object ); if( result != null ) return result; + if( object instanceof ILuaFunction ) + { + return new ResultInterpreterFunction( this, FUNCTION_METHOD, object, context, object.toString() ); + } + if( object instanceof IDynamicLuaObject ) { LuaValue wrapped = wrapLuaObject( object ); diff --git a/src/test/java/dan200/computercraft/core/asm/MethodTest.java b/src/test/java/dan200/computercraft/core/asm/MethodTest.java index cd2e780a4..cfbbe6b9b 100644 --- a/src/test/java/dan200/computercraft/core/asm/MethodTest.java +++ b/src/test/java/dan200/computercraft/core/asm/MethodTest.java @@ -87,6 +87,14 @@ public class MethodTest x -> x.addApi( new ManyMethods() ), 50 ); } + @Test + public void testFunction() + { + ComputerBootstrap.run( + "assert(func.call()(123) == 123)", + x -> x.addApi( new ReturnFunction() ), 50 ); + } + public static class MainThread implements ILuaAPI, IPeripheral { public final String thread = Thread.currentThread().getName(); @@ -239,4 +247,19 @@ public class MethodTest return new String[] { "many" }; } } + + public static class ReturnFunction implements ILuaAPI + { + @LuaFunction + public final ILuaFunction call() + { + return args -> MethodResult.of( args.getAll() ); + } + + @Override + public String[] getNames() + { + return new String[] { "func" }; + } + } } From 190ed4fd20313e2577bd2ce8393f435a14760561 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 11 Jun 2020 21:19:14 +0100 Subject: [PATCH 250/711] Fix incorrect disk drive method name The previous comment was wrong, and I never double checked. Closes #472. --- .../shared/peripheral/diskdrive/DiskDrivePeripheral.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 1a56cd236..ee0001a38 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -104,7 +104,7 @@ public class DiskDrivePeripheral implements IPeripheral } @LuaFunction - public final void eject() + public final void ejectDisk() { diskDrive.ejectDisk(); } From c0f3ca81fb05f5f883c4743eab76ad6cbac33d36 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 15 Jun 2020 21:37:08 +0100 Subject: [PATCH 251/711] Bump to 1.89.0 --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 9 +++++++++ .../computercraft/lua/rom/help/whatsnew.txt | 17 +++++------------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6a0e98d27..3fe94fba4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.88.0 +mod_version=1.89.0 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 6e6804037..7c9eac4ce 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,12 @@ +# New features in CC: Tweaked 1.89.0 + +* Compress monitor data, reducing network traffic by a significant amount. +* Allow limiting the bandwidth monitor updates use. +* Several optimisations to monitor rendering (@Lignum) + +And several bug fixes: +* Fix settings.load failing on defined settings. + # New features in CC: Tweaked 1.88.0 * Computers and turtles now preserve their ID when broken. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index 772f17738..d715a80f5 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,17 +1,10 @@ -New features in CC: Tweaked 1.88.0 +New features in CC: Tweaked 1.89.0 -* Computers and turtles now preserve their ID when broken. -* Add `peripheral.getName` - returns the name of a wrapped peripheral. -* Reduce network overhead of monitors and terminals. -* Add a TBO backend for monitors, with a significant performance boost. -* The Lua REPL warns when declaring locals (lupus590, exerro) -* Add config to allow using command computers in survival. -* Add fs.isDriveRoot - checks if a path is the root of a drive. -* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default. -* Move the shell's `require`/`package` implementation to a separate `cc.require` module. +* Compress monitor data, reducing network traffic by a significant amount. +* Allow limiting the bandwidth monitor updates use. +* Several optimisations to monitor rendering (@Lignum) And several bug fixes: -* Fix io.lines not accepting arguments. -* Fix settings.load using an unknown global (MCJack123). +* Fix settings.load failing on defined settings. Type "help changelog" to see the full version history. From 7b2d4823879a6db77bb99fc2e8605e9e54a0d361 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 16 Jun 2020 09:45:42 +0100 Subject: [PATCH 252/711] Make the CF release stable --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6813fdfa6..4b6864ec8 100644 --- a/build.gradle +++ b/build.gradle @@ -384,7 +384,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'beta' + releaseType = 'release' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { @@ -462,7 +462,7 @@ githubRelease { .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() } - prerelease true + prerelease false } def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] From a35dcb28ef09574a6843c059b48a4c8b3d617b82 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 18 Jun 2020 13:10:51 +0100 Subject: [PATCH 253/711] Import translations and clean up - Strip any gui._.config options. These haven't been used since 1.12 and while they may return, it doesn't seem worth it right now. - Fix a couple of typos in the English translations. - Import from https://i18n.tweaked.cc. There's definitely some problems with the import - empty translations are still included, so we write a script to strip them. --- .../assets/computercraft/lang/da_dk.json | 12 -- .../assets/computercraft/lang/de_de.json | 79 +----------- .../assets/computercraft/lang/en_us.json | 83 +------------ .../assets/computercraft/lang/es_es.json | 37 +----- .../assets/computercraft/lang/fr_fr.json | 37 +----- .../assets/computercraft/lang/it_it.json | 112 ++++++++++-------- .../assets/computercraft/lang/ko_kr.json | 79 +----------- .../assets/computercraft/lang/nl_nl.json | 54 +++++++++ .../assets/computercraft/lang/pl_pl.json | 43 +++++++ .../assets/computercraft/lang/pt_br.json | 53 +-------- .../assets/computercraft/lang/sv_se.json | 53 +-------- .../assets/computercraft/lang/zh_cn.json | 80 +------------ tools/language.py | 42 +++++++ 13 files changed, 210 insertions(+), 554 deletions(-) create mode 100644 src/main/resources/assets/computercraft/lang/nl_nl.json create mode 100644 src/main/resources/assets/computercraft/lang/pl_pl.json create mode 100644 tools/language.py diff --git a/src/main/resources/assets/computercraft/lang/da_dk.json b/src/main/resources/assets/computercraft/lang/da_dk.json index fa2465308..1b72f4622 100644 --- a/src/main/resources/assets/computercraft/lang/da_dk.json +++ b/src/main/resources/assets/computercraft/lang/da_dk.json @@ -1,41 +1,31 @@ { - "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Avanceret Computer", "block.computercraft.computer_command": "Kommandocomputer", - "block.computercraft.disk_drive": "Diskdrev", "block.computercraft.printer": "Printer", "block.computercraft.speaker": "Højttaler", - "block.computercraft.monitor_normal": "Skærm", "block.computercraft.monitor_advanced": "Avanceret Skærm", - "block.computercraft.wireless_modem_normal": "TrÃ¥dløst Modem", "block.computercraft.wireless_modem_advanced": "Endermodem", - "block.computercraft.wired_modem": "Kablet Modem", "block.computercraft.cable": "Netværkskabel", - "block.computercraft.turtle_normal": "Turtle", "block.computercraft.turtle_normal.upgraded": "%s Turtle", "block.computercraft.turtle_normal.upgraded_twice": "%s %s Turtle", - "block.computercraft.turtle_advanced": "Avanceret Turtle", "block.computercraft.turtle_advanced.upgraded": "Avanceret %s Turtle", "block.computercraft.turtle_advanced.upgraded_twice": "Avanceret %s %s Turtle", - "item.computercraft.disk": "Floppydisk", "item.computercraft.treasure_disk": "Floppydisk", "item.computercraft.printed_page": "Printet Side", "item.computercraft.printed_pages": "Printede Sider", "item.computercraft.printed_book": "Printet Bog", - "item.computercraft.pocket_computer_normal": "Lommecomputer", "item.computercraft.pocket_computer_normal.upgraded": "%s Lommecomputer", "item.computercraft.pocket_computer_advanced": "Avanceret Lommecomputer", "item.computercraft.pocket_computer_advanced.upgraded": "Avanceret %s Lommecomputer", - "upgrade.minecraft.diamond_sword.adjective": "Kæmpende", "upgrade.minecraft.diamond_shovel.adjective": "Gravende", "upgrade.minecraft.diamond_pickaxe.adjective": "Brydende", @@ -45,10 +35,8 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "TrÃ¥dløs", "upgrade.computercraft.wireless_modem_advanced.adjective": "EndertrÃ¥dløs", "upgrade.computercraft.speaker.adjective": "Larmende", - "chat.computercraft.wired_modem.peripheral_connected": "Perifer enhed \"%s\" koblet til netværk", "chat.computercraft.wired_modem.peripheral_disconnected": "Perifer enhed \"%s\" koblet fra netværk", - "gui.computercraft.tooltip.copy": "Kopier til udklipsholder", "gui.computercraft.tooltip.computer_id": "Computer-ID: %s", "gui.computercraft.tooltip.disk_id": "Disk-ID: %s" diff --git a/src/main/resources/assets/computercraft/lang/de_de.json b/src/main/resources/assets/computercraft/lang/de_de.json index 596438a14..255a1d794 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.json +++ b/src/main/resources/assets/computercraft/lang/de_de.json @@ -1,43 +1,33 @@ { "itemGroup.computercraft": "CC: Tweaked", - "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Erweiterter Computer", "block.computercraft.computer_command": "Befehlscomputer", - "block.computercraft.disk_drive": "Diskettenlaufwerk", "block.computercraft.printer": "Drucker", "block.computercraft.speaker": "Lautsprecher", - "block.computercraft.monitor_normal": "Monitor", "block.computercraft.monitor_advanced": "Erweiterter Monitor", - "block.computercraft.wireless_modem_normal": "Kabelloses Modem", "block.computercraft.wireless_modem_advanced": "Endermodem", - "block.computercraft.wired_modem": "Kabelmodem", "block.computercraft.cable": "Netzwerkkabel", "block.computercraft.wired_modem_full": "Kabelmodem", - "block.computercraft.turtle_normal": "Turtle", "block.computercraft.turtle_normal.upgraded": "Turtle (%s)", "block.computercraft.turtle_normal.upgraded_twice": "Turtle (%s, %s)", - "block.computercraft.turtle_advanced": "Erweiterte Turtle", "block.computercraft.turtle_advanced.upgraded": "Erweiterte Turtle (%s)", "block.computercraft.turtle_advanced.upgraded_twice": "Erweiterte Turtle (%s, %s)", - "item.computercraft.disk": "Diskette", "item.computercraft.treasure_disk": "Diskette", "item.computercraft.printed_page": "Gedruckte Seite", "item.computercraft.printed_pages": "Gedruckte Seiten", "item.computercraft.printed_book": "Gedrucktes Buch", - "item.computercraft.pocket_computer_normal": "Taschencomputer", "item.computercraft.pocket_computer_normal.upgraded": "Taschencomputer (%s)", "item.computercraft.pocket_computer_advanced": "Erweiterter Taschencomputer", "item.computercraft.pocket_computer_advanced.upgraded": "Erweiterter Taschencomputer (%s)", - "upgrade.minecraft.diamond_sword.adjective": "Nahkampf", "upgrade.minecraft.diamond_shovel.adjective": "Graben", "upgrade.minecraft.diamond_pickaxe.adjective": "Bergbau", @@ -47,142 +37,75 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "Ender", "upgrade.computercraft.wireless_modem_advanced.adjective": "Kabellos", "upgrade.computercraft.speaker.adjective": "Laut", - "chat.computercraft.wired_modem.peripheral_connected": "Peripheriegerät \"%s\" mit dem Netzwerk verbunden", "chat.computercraft.wired_modem.peripheral_disconnected": "Peripheriegerät \"%s\" vom Netzwerk getrennt", - "commands.computercraft.synopsis": "Verschiedene Befehle um Computer zu kontrollieren.", "commands.computercraft.desc": "Der /computercraft Befehl enthält verschiedene Werkzeuge um Computer zu debuggen, kontrollieren oder mit ihnen zu interagieren.", - "commands.computercraft.help.synopsis": "Zeigt die Hilfe für den angegebenen Befehl", - "commands.computercraft.help.desc": "", "commands.computercraft.help.no_children": "%s hat keine Unterbefehle", "commands.computercraft.help.no_command": "Unbekannter Befehl '%s'", - "commands.computercraft.dump.synopsis": "Zeigt den Status eines Computers.", "commands.computercraft.dump.desc": "Zeigt den Status aller Computer oder genauere Informationen über einen angegebenen Computer. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", "commands.computercraft.dump.action": "Zeigt mehr Informationen über einen Computer", - "commands.computercraft.shutdown.synopsis": "Fährt den Computer aus der Ferne herunter.", "commands.computercraft.shutdown.desc": "Fährt die angegebenen Computer herunter. Falls keine Computer angegeben sind, werden alle heruntergefahren. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", "commands.computercraft.shutdown.done": "Fährt die Computer %s/%s herunter", - "commands.computercraft.turn_on.synopsis": "Fährt einen Computer aus der Ferne hoch.", "commands.computercraft.turn_on.desc": "Fährt die angegebenen Computer hoch. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", "commands.computercraft.turn_on.done": "Fährt die Computer %s/%s hoch", - "commands.computercraft.tp.synopsis": "Teleportiert dich zum angegebenen Computer.", "commands.computercraft.tp.desc": "Teleportiert dich zum Standort eines Computers. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", "commands.computercraft.tp.action": "Teleportiert dich zum Computer", "commands.computercraft.tp.not_player": "Konnte Terminal für Nicht-Spieler nicht öffnen", "commands.computercraft.tp.not_there": "Konnte Computer in der Welt nicht finden", - "commands.computercraft.view.synopsis": "Zeigt das Terminal eines Computers.", "commands.computercraft.view.desc": "Zeigt das Terminal eines Computers. Dies ermöglicht, den Computer aus der Ferne zu steuern. Ein Zugriff auf das Inventar eines Turtles ist dadurch allerdings nicht möglich. Der Computer kann entweder über seine Instanz ID (z.B. 123), seine Computer ID (z.B. #123) oder seinen Namen (z.B. \"@Mein Computer\") angegeben werden.", "commands.computercraft.view.action": "Zeigt den Computer", "commands.computercraft.view.not_player": "Konnte Terminal für Nicht-Spieler nicht öffnen", - "commands.computercraft.track.synopsis": "Zeichnet die Laufzeiten von Computern auf.", "commands.computercraft.track.desc": "Zeichnet die Laufzeiten von Computern und wie viele Events ausgelöst werden auf. Die Ausgabe der Informationen ist ähnlich zu /forge track, was beim aufspüren von Lags sehr hilfreich sein kann.", - "commands.computercraft.track.start.synopsis": "Startet die Aufzeichnung von Computern", "commands.computercraft.track.start.desc": "Startet die Aufzeichnung der Laufzeiten und Anzahl der Events aller Computer. Dadurch werden die Ergebnisse der letzten Male verworfen.", "commands.computercraft.track.start.stop": "Führe %s aus um die Aufzeichnung zu stoppen und die Ergebnisse anzusehen", - "commands.computercraft.track.stop.synopsis": "Stoppt die Aufzeichnung aller Computer", "commands.computercraft.track.stop.desc": "Stopt die Aufzeichnung aller Computer Events und Laufzeiten", "commands.computercraft.track.stop.action": "Klicke um die Aufzeichnung zu stoppen", "commands.computercraft.track.stop.not_enabled": "Momentan werden keine Computer aufgezeichnet", - "commands.computercraft.track.dump.synopsis": "Gibt die aktuellen Ergebnisse der Aufzeichnung aus", "commands.computercraft.track.dump.desc": "Gibt die aktuellen Ergebnisse der Aufzeichnung aus.", "commands.computercraft.track.dump.no_timings": "Keine Zeitangaben verfügbar", "commands.computercraft.track.dump.computer": "Computer", - "commands.computercraft.reload.synopsis": "Liest die Konfigurationsdatei von ComputerCraft neu ein", "commands.computercraft.reload.desc": "Liest die Konfigurationsdatei von ComputerCraft neu ein", "commands.computercraft.reload.done": "Die Konfigurationsdatei wurde erfolgreich neu eingelesen", - "commands.computercraft.queue.synopsis": "Sendet ein computer_command Event an einen Befehlscomputer", "commands.computercraft.queue.desc": "Sendet ein computer_command Event zusammen mit optionalen Argumenten an einen Befehlscomputer. Dieser Befehl wurde als eine Computerfreundliche Version von /trigger für Mapdesigner designed. Jeder Spieler kann diesen Befehl ausführen, weshalb er sich perfekt für ein Klickevent von z.B. Schildern oder Büchern eignet.", - "commands.computercraft.generic.no_position": "", "commands.computercraft.generic.position": "%s, %s, %s", "commands.computercraft.generic.yes": "J", "commands.computercraft.generic.no": "N", "commands.computercraft.generic.exception": "Unbehandelte Ausnahme (%s)", "commands.computercraft.generic.additional_rows": "%d zusätzliche Zeilen…", - "argument.computercraft.computer.no_matching": "Kein Computer passt auf '%s'", "argument.computercraft.computer.many_matching": "Mehrere Computer passen auf '%s' (Instanzen %s)", - "argument.computercraft.tracking_field.no_field": "Unbekanntes Feld '%s'", - "tracking_field.computercraft.tasks.name": "Aufgaben", "tracking_field.computercraft.total.name": "Gesamtzeit", "tracking_field.computercraft.average.name": "Durchschnittliche Zeit", "tracking_field.computercraft.max.name": "Maximale Zeit", - "tracking_field.computercraft.server_count.name": "Anzahl der Server-Tasks", "tracking_field.computercraft.server_time.name": "Server-Task-Zeit", - "tracking_field.computercraft.peripheral.name": "Peripheriegeräte Aufrufe", "tracking_field.computercraft.fs.name": "Dateisystem Operationen", "tracking_field.computercraft.turtle.name": "Turtle Operationen", - "tracking_field.computercraft.http.name": "HTTP-Requests", "tracking_field.computercraft.http_upload.name": "HTTP Upload", "tracking_field.computercraft.http_download.name": "HTTT Download", - "tracking_field.computercraft.websocket_incoming.name": "Websocket eingehend", "tracking_field.computercraft.websocket_outgoing.name": "Websocket ausgehend", - "tracking_field.computercraft.coroutines_created.name": "Koroutinen erstellt", "tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht", - "gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren", "gui.computercraft.tooltip.computer_id": "Computer ID: %s", - "gui.computercraft.tooltip.disk_id": "Disketten ID: %s", - - "gui.computercraft.config.computer_space_limit": "Speicherplatz von Computern (bytes)", - "gui.computercraft.config.floppy_space_limit": "Speicherplatz von Disketten (bytes)", - "gui.computercraft.config.maximum_open_files": "Maximalanzahl an gleichzeitig offenen Dateien je Computer", - "gui.computercraft.config.disable_lua51_features": "Lua 5.1-Funktionen deaktivieren", - "gui.computercraft.config.default_computer_settings": "Computer-Standardeinstellungen", - "gui.computercraft.config.debug_enabled": "Debug-Library aktivieren", - "gui.computercraft.config.log_computer_errors": "Peripheriefehler loggen", - - "gui.computercraft.config.execution": "Ausführung", - "gui.computercraft.config.execution.computer_threads": "Computer Threads", - "gui.computercraft.config.execution.max_main_global_time": "Globales Servertick Zeitlimit", - "gui.computercraft.config.execution.max_main_computer_time": "Computer Servertick Zeitlimit", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "HTTP-API aktivieren", - "gui.computercraft.config.http.websocket_enabled": "HTTP-Websockets aktivieren", - "gui.computercraft.config.http.whitelist": "HTTP-Whitelist", - "gui.computercraft.config.http.blacklist": "HTTP-Blacklist", - - "gui.computercraft.config.http.timeout": "Zeitüberschreitung", - "gui.computercraft.config.http.max_requests": "Maximale Anzahl gleichzeitiger Anfragen", - "gui.computercraft.config.http.max_download": "Maximale Antwortgröße", - "gui.computercraft.config.http.max_upload": "Maximale Anfragegröße", - "gui.computercraft.config.http.max_websockets": "Maximale Anzahl gleichzeitiger Websockets", - "gui.computercraft.config.http.max_websocket_message": "Maximale Größe der Websocket-Nachricht", - - "gui.computercraft.config.peripheral": "Peripheriegeräte", - "gui.computercraft.config.peripheral.command_block_enabled": "Befehlsblöcke als Peripheriegerät erlauben", - "gui.computercraft.config.peripheral.modem_range": "Modemreichweite (normal)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Modemreichweite (in großer Höhe)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Modemreichweite (bei schlechtem Wetter)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Modemreichweite (in großer Höhe bei schlechtem Wetter)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Maximalanzahl an Noten, die ein Computer gleichzeitig spielen kann", - - "gui.computercraft.config.turtle": "Turtles", - "gui.computercraft.config.turtle.need_fuel": "Treibstoffverbrauch aktivieren", - "gui.computercraft.config.turtle.normal_fuel_limit": "Treibstofflimit von Turtles", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Treibstofflimit von Erweiterten Turtles", - "gui.computercraft.config.turtle.obey_block_protection": "Turtles unterliegen Blockschutzrichtlinien", - "gui.computercraft.config.turtle.can_push": "Turtles können Entities bewegen", - "gui.computercraft.config.turtle.disabled_actions": "Deaktivierte Turtle-Aktionen" + "gui.computercraft.tooltip.disk_id": "Disketten ID: %s" } diff --git a/src/main/resources/assets/computercraft/lang/en_us.json b/src/main/resources/assets/computercraft/lang/en_us.json index 53514aa93..0de1b7c4b 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.json +++ b/src/main/resources/assets/computercraft/lang/en_us.json @@ -1,43 +1,33 @@ { "itemGroup.computercraft": "ComputerCraft", - "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Advanced Computer", "block.computercraft.computer_command": "Command Computer", - "block.computercraft.disk_drive": "Disk Drive", "block.computercraft.printer": "Printer", "block.computercraft.speaker": "Speaker", - "block.computercraft.monitor_normal": "Monitor", "block.computercraft.monitor_advanced": "Advanced Monitor", - "block.computercraft.wireless_modem_normal": "Wireless Modem", "block.computercraft.wireless_modem_advanced": "Ender Modem", - "block.computercraft.wired_modem": "Wired Modem", "block.computercraft.cable": "Networking Cable", "block.computercraft.wired_modem_full": "Wired Modem", - "block.computercraft.turtle_normal": "Turtle", "block.computercraft.turtle_normal.upgraded": "%s Turtle", "block.computercraft.turtle_normal.upgraded_twice": "%s %s Turtle", - "block.computercraft.turtle_advanced": "Advanced Turtle", "block.computercraft.turtle_advanced.upgraded": "Advanced %s Turtle", "block.computercraft.turtle_advanced.upgraded_twice": "Advanced %s %s Turtle", - "item.computercraft.disk": "Floppy Disk", "item.computercraft.treasure_disk": "Floppy Disk", "item.computercraft.printed_page": "Printed Page", "item.computercraft.printed_pages": "Printed Pages", "item.computercraft.printed_book": "Printed Book", - "item.computercraft.pocket_computer_normal": "Pocket Computer", "item.computercraft.pocket_computer_normal.upgraded": "%s Pocket Computer", "item.computercraft.pocket_computer_advanced": "Advanced Pocket Computer", "item.computercraft.pocket_computer_advanced.upgraded": "Advanced %s Pocket Computer", - "upgrade.minecraft.diamond_sword.adjective": "Melee", "upgrade.minecraft.diamond_shovel.adjective": "Digging", "upgrade.minecraft.diamond_pickaxe.adjective": "Mining", @@ -47,144 +37,77 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "Wireless", "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", "upgrade.computercraft.speaker.adjective": "Noisy", - "chat.computercraft.wired_modem.peripheral_connected": "Peripheral \"%s\" connected to network", "chat.computercraft.wired_modem.peripheral_disconnected": "Peripheral \"%s\" disconnected from network", - "commands.computercraft.synopsis": "Various commands for controlling computers.", "commands.computercraft.desc": "The /computercraft command provides various debugging and administrator tools for controlling and interacting with computers.", - "commands.computercraft.help.synopsis": "Provide help for a specific command", - "commands.computercraft.help.desc": "", + "commands.computercraft.help.desc": "Displays this help message", "commands.computercraft.help.no_children": "%s has no sub-commands", "commands.computercraft.help.no_command": "No such command '%s'", - "commands.computercraft.dump.synopsis": "Display the status of computers.", "commands.computercraft.dump.desc": "Display the status of all computers or specific information about one computer. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").", "commands.computercraft.dump.action": "View more info about this computer", - "commands.computercraft.shutdown.synopsis": "Shutdown computers remotely.", "commands.computercraft.shutdown.desc": "Shutdown the listed computers or all if none are specified. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").", "commands.computercraft.shutdown.done": "Shutdown %s/%s computers", - "commands.computercraft.turn_on.synopsis": "Turn computers on remotely.", "commands.computercraft.turn_on.desc": "Turn on the listed computers. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").", "commands.computercraft.turn_on.done": "Turned on %s/%s computers", - "commands.computercraft.tp.synopsis": "Teleport to a specific computer.", "commands.computercraft.tp.desc": "Teleport to the location of a computer. You can either specify the computer's instance id (e.g. 123) or computer id (e.g #123).", "commands.computercraft.tp.action": "Teleport to this computer", "commands.computercraft.tp.not_player": "Cannot open terminal for non-player", "commands.computercraft.tp.not_there": "Cannot locate computer in the world", - "commands.computercraft.view.synopsis": "View the terminal of a computer.", "commands.computercraft.view.desc": "Open the terminal of a computer, allowing remote control of a computer. This does not provide access to turtle's inventories. You can either specify the computer's instance id (e.g. 123) or computer id (e.g #123).", "commands.computercraft.view.action": "View this computer", "commands.computercraft.view.not_player": "Cannot open terminal for non-player", - "commands.computercraft.track.synopsis": "Track execution times for computers.", "commands.computercraft.track.desc": "Track how long computers execute for, as well as how many events they handle. This presents information in a similar way to /forge track and can be useful for diagnosing lag.", - "commands.computercraft.track.start.synopsis": "Start tracking all computers", "commands.computercraft.track.start.desc": "Start tracking all computers' execution times and event counts. This will discard the results of previous runs.", "commands.computercraft.track.start.stop": "Run %s to stop tracking and view the results", - "commands.computercraft.track.stop.synopsis": "Stop tracking all computers", "commands.computercraft.track.stop.desc": "Stop tracking all computers' events and execution times", "commands.computercraft.track.stop.action": "Click to stop tracking", "commands.computercraft.track.stop.not_enabled": "Not currently tracking computers", - "commands.computercraft.track.dump.synopsis": "Dump the latest track results", "commands.computercraft.track.dump.desc": "Dump the latest results of computer tracking.", "commands.computercraft.track.dump.no_timings": "No timings available", "commands.computercraft.track.dump.computer": "Computer", - "commands.computercraft.reload.synopsis": "Reload the ComputerCraft config file", "commands.computercraft.reload.desc": "Reload the ComputerCraft config file", "commands.computercraft.reload.done": "Reloaded config", - "commands.computercraft.queue.synopsis": "Send a computer_command event to a command computer", "commands.computercraft.queue.desc": "Send a computer_command event to a command computer, passing through the additional arguments. This is mostly designed for map makers, acting as a more computer-friendly version of /trigger. Any player can run the command, which would most likely be done through a text component's click event.", - "commands.computercraft.generic.no_position": "", "commands.computercraft.generic.position": "%s, %s, %s", "commands.computercraft.generic.yes": "Y", "commands.computercraft.generic.no": "N", "commands.computercraft.generic.exception": "Unhandled exception (%s)", "commands.computercraft.generic.additional_rows": "%d additional rows…", - "argument.computercraft.computer.no_matching": "No computers matching '%s'", "argument.computercraft.computer.many_matching": "Multiple computers matching '%s' (instances %s)", - "argument.computercraft.tracking_field.no_field": "Unknown field '%s'", - "argument.computercraft.argument_expected": "Argument expected", - "tracking_field.computercraft.tasks.name": "Tasks", "tracking_field.computercraft.total.name": "Total time", "tracking_field.computercraft.average.name": "Average time", "tracking_field.computercraft.max.name": "Max time", - "tracking_field.computercraft.server_count.name": "Server task count", "tracking_field.computercraft.server_time.name": "Server task time", - "tracking_field.computercraft.peripheral.name": "Peripheral calls", "tracking_field.computercraft.fs.name": "Filesystem operations", "tracking_field.computercraft.turtle.name": "Turtle operations", - "tracking_field.computercraft.http.name": "HTTP requests", "tracking_field.computercraft.http_upload.name": "HTTP upload", - "tracking_field.computercraft.http_download.name": "HTTT download", - + "tracking_field.computercraft.http_download.name": "HTTP download", "tracking_field.computercraft.websocket_incoming.name": "Websocket incoming", "tracking_field.computercraft.websocket_outgoing.name": "Websocket outgoing", - "tracking_field.computercraft.coroutines_created.name": "Coroutines created", "tracking_field.computercraft.coroutines_dead.name": "Coroutines disposed", - "gui.computercraft.tooltip.copy": "Copy to clipboard", "gui.computercraft.tooltip.computer_id": "Computer ID: %s", - "gui.computercraft.tooltip.disk_id": "Disk ID: %s", - - "gui.computercraft.config.computer_space_limit": "Computer space limit (bytes)", - "gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)", - "gui.computercraft.config.maximum_open_files": "Maximum files open per computer", - "gui.computercraft.config.disable_lua51_features": "Disable Lua 5.1 features", - "gui.computercraft.config.default_computer_settings": "Default Computer settings", - "gui.computercraft.config.debug_enabled": "Enable debug library", - "gui.computercraft.config.log_computer_errors": "Log computer errors", - - "gui.computercraft.config.execution": "Execution", - "gui.computercraft.config.execution.computer_threads": "Computer threads", - "gui.computercraft.config.execution.max_main_global_time": "Server tick global time limit", - "gui.computercraft.config.execution.max_main_computer_time": "Server tick computer time limit", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "Enable the HTTP API", - "gui.computercraft.config.http.websocket_enabled": "Enable websockets", - "gui.computercraft.config.http.whitelist": "HTTP whitelist", - "gui.computercraft.config.http.blacklist": "HTTP blacklist", - - "gui.computercraft.config.http.timeout": "Timeout", - "gui.computercraft.config.http.max_requests": "Maximum concurrent requests", - "gui.computercraft.config.http.max_download": "Maximum response size", - "gui.computercraft.config.http.max_upload": "Maximum request size", - "gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets", - "gui.computercraft.config.http.max_websocket_message": "Maximum websocket message size", - - "gui.computercraft.config.peripheral": "Peripherals", - "gui.computercraft.config.peripheral.command_block_enabled": "Enable command block peripheral", - "gui.computercraft.config.peripheral.modem_range": "Modem range (default)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Modem range (high-altitude)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Modem range (bad weather)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Modem range (high-altitude, bad weather)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Maximum notes that a computer can play at once", - - "gui.computercraft.config.turtle": "Turtles", - "gui.computercraft.config.turtle.need_fuel": "Enable fuel", - "gui.computercraft.config.turtle.normal_fuel_limit": "Turtle fuel limit", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Advanced Turtle fuel limit", - "gui.computercraft.config.turtle.obey_block_protection": "Turtles obey block protection", - "gui.computercraft.config.turtle.can_push": "Turtles can push entities", - "gui.computercraft.config.turtle.disabled_actions": "Disabled turtle actions" + "gui.computercraft.tooltip.disk_id": "Disk ID: %s" } diff --git a/src/main/resources/assets/computercraft/lang/es_es.json b/src/main/resources/assets/computercraft/lang/es_es.json index afec3f007..7788dcecb 100644 --- a/src/main/resources/assets/computercraft/lang/es_es.json +++ b/src/main/resources/assets/computercraft/lang/es_es.json @@ -1,41 +1,31 @@ { - "block.computercraft.computer_normal": "Ordenador", "block.computercraft.computer_advanced": "Ordenador avanzado", "block.computercraft.computer_command": "Ordenador de Comandos", - "block.computercraft.disk_drive": "Disco duro", "block.computercraft.printer": "Impresora", "block.computercraft.speaker": "Altavoz", - "block.computercraft.monitor_normal": "Monitor", "block.computercraft.monitor_advanced": "Monitor avanzado", - "block.computercraft.wireless_modem_normal": "Módem sin cables", "block.computercraft.wireless_modem_advanced": "Módem de Ender", - "block.computercraft.wired_modem": "Módem cableado", "block.computercraft.cable": "Cable de red", - "block.computercraft.turtle_normal": "Tortuga", "block.computercraft.turtle_normal.upgraded": "Tortuga %s", "block.computercraft.turtle_normal.upgraded_twice": "Tortuga %s %s", - "block.computercraft.turtle_advanced": "Tortuga avanzada", "block.computercraft.turtle_advanced.upgraded": "Tortuga %s avanzada", "block.computercraft.turtle_advanced.upgraded_twice": "Tortuga %s %s avanzada", - "item.computercraft.disk": "Disquete", "item.computercraft.treasure_disk": "Disquete (Tesoro)", "item.computercraft.printed_page": "Página impresa", "item.computercraft.printed_pages": "Páginas impresas", "item.computercraft.printed_book": "Libro impreso", - "item.computercraft.pocket_computer_normal": "Ordenador de bolsillo", "item.computercraft.pocket_computer_normal.upgraded": "Ordenador de bolsillo %s", "item.computercraft.pocket_computer_advanced": "Ordenador de bolsillo avanzado", "item.computercraft.pocket_computer_advanced.upgraded": "Ordenador de bolsillo %s avanzado", - "upgrade.minecraft.diamond_sword.adjective": "guerrera", "upgrade.minecraft.diamond_shovel.adjective": "excavadora", "upgrade.minecraft.diamond_pickaxe.adjective": "minera", @@ -45,31 +35,6 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "sin cables", "upgrade.computercraft.wireless_modem_advanced.adjective": "ender", "upgrade.computercraft.speaker.adjective": "ruidosa", - "chat.computercraft.wired_modem.peripheral_connected": "El periférico \"%s\" se conectó a la red", - "chat.computercraft.wired_modem.peripheral_disconnected": "El periférico \"%s\" se desconectó de la red", - - "gui.computercraft.config.computer_space_limit": "Límite de memoria de ordenadores (en bytes)", - "gui.computercraft.config.floppy_space_limit": "Límite de memoria de disquetes (en bytes)", - "gui.computercraft.config.maximum_open_files": "Archivos abiertos máximos por cada ordenador", - "gui.computercraft.config.disable_lua51_features": "Deshabilitar funciones de Lua 5.1", - "gui.computercraft.config.default_computer_settings": "Configuración de Ordenador por defecto", - "gui.computercraft.config.log_computer_errors": "Grabar errores periféricos", - - "gui.computercraft.config.http.enabled": "Habilitar API de HTTP", - "gui.computercraft.config.http.whitelist": "Lista blanca de HTTP", - "gui.computercraft.config.http.blacklist": "Lista negra de HTTP", - - "gui.computercraft.config.peripheral.command_block_enabled": "Habilitar bloque de comandos periférico", - "gui.computercraft.config.peripheral.modem_range": "Rango del módem (Por defecto)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Rango del módem (en altitud)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Rango del módem (mal tiempo)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Rango del módem (en altitud con mal tiempo)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Notas máximas que un ordenador puede tocar a la vez", - - "gui.computercraft.config.turtle.need_fuel": "Habilitar combustible", - "gui.computercraft.config.turtle.normal_fuel_limit": "Límite de combustible de las tortugas", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Límite de combustible de las tortugas avanzadas", - "gui.computercraft.config.turtle.obey_block_protection": "Las tortugas obedecen protección de bloques", - "gui.computercraft.config.turtle.can_push": "Las tortugas pueden empujar entidades" + "chat.computercraft.wired_modem.peripheral_disconnected": "El periférico \"%s\" se desconectó de la red" } diff --git a/src/main/resources/assets/computercraft/lang/fr_fr.json b/src/main/resources/assets/computercraft/lang/fr_fr.json index 958fcbde6..e1e05ff7c 100644 --- a/src/main/resources/assets/computercraft/lang/fr_fr.json +++ b/src/main/resources/assets/computercraft/lang/fr_fr.json @@ -1,42 +1,32 @@ { - "block.computercraft.computer_normal": "Ordinateur", "block.computercraft.computer_advanced": "Ordinateur avancé", "block.computercraft.computer_command": "Ordinateur de commande", - "block.computercraft.disk_drive": "Lecteur disque", "block.computercraft.printer": "Imprimante", "block.computercraft.speaker": "Haut-parleur", - "block.computercraft.monitor_normal": "Moniteur", "block.computercraft.monitor_advanced": "Moniteur avancé", - "block.computercraft.wireless_modem_normal": "Modem sans fil", "block.computercraft.wireless_modem_advanced": "Modem de l'Ender", - "block.computercraft.wired_modem": "Modem filaire", "block.computercraft.cable": "Câble réseau", "block.computercraft.wired_modem_full": "Modem filaire", - "block.computercraft.turtle_normal": "Tortue", "block.computercraft.turtle_normal.upgraded": "Tortue %s", "block.computercraft.turtle_normal.upgraded_twice": "Tortue %s %s", - "block.computercraft.turtle_advanced": "Tortue avancée", "block.computercraft.turtle_advanced.upgraded": "Tortue %s avancée", "block.computercraft.turtle_advanced.upgraded_twice": "Tortue %s %s avancée", - "item.computercraft.disk": "Disquette", "item.computercraft.treasure_disk": "Disquette", "item.computercraft.printed_page": "Imprimé", "item.computercraft.printed_pages": "Imprimés", "item.computercraft.printed_book": "Livre imprimé", - "item.computercraft.pocket_computer_normal": "Ordinateur de poche", "item.computercraft.pocket_computer_normal.upgraded": "Ordinateur de poche %s", "item.computercraft.pocket_computer_advanced": "Ordinateur de poche avancé", "item.computercraft.pocket_computer_advanced.upgraded": "Ordinateur de poche %s avancé", - "upgrade.minecraft.diamond_sword.adjective": "combattante", "upgrade.minecraft.diamond_shovel.adjective": "excavatrice", "upgrade.minecraft.diamond_pickaxe.adjective": "minière", @@ -46,31 +36,6 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "sans fil", "upgrade.computercraft.wireless_modem_advanced.adjective": "de l'Ender", "upgrade.computercraft.speaker.adjective": "parlante", - "chat.computercraft.wired_modem.peripheral_connected": "Le periphérique \"%s\" est connecté au réseau", - "chat.computercraft.wired_modem.peripheral_disconnected": "Le periphérique \"%s\" est déconnecté du réseau", - - "gui.computercraft.config.computer_space_limit": "Espace disque d'un Ordinateur (octets)", - "gui.computercraft.config.floppy_space_limit": "Espace disque d'une Disquette (octets)", - "gui.computercraft.config.maximum_open_files": "Maximum de fichier ouvert par Ordinateur", - "gui.computercraft.config.disable_lua51_features": "Désactiver les particularités de Lua 5.1", - "gui.computercraft.config.default_computer_settings": "Configuration d'Ordinateur par défaut", - "gui.computercraft.config.log_computer_errors": "Journal d'erreur périphériques", - - "gui.computercraft.config.http.enabled": "Permettre l'API HTTP", - "gui.computercraft.config.http.whitelist": "HTTP liste blanche", - "gui.computercraft.config.http.blacklist": "HTTP liste noire", - - "gui.computercraft.config.peripheral.command_block_enabled": "Permettre l'accès d'un Bloc de Commande par périphérique", - "gui.computercraft.config.peripheral.modem_range": "Portée d'un Modem (par défaut)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Portée d'un Modem (en haute altitude)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Portée d'un Modem (par mauvais temps)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Portée d'un Modem (en haute altitude, par mauvais temps)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Maximum de notes simultanées jouées par Ordinateur", - - "gui.computercraft.config.turtle.need_fuel": "Activer la nécessité de carburant au mouvement des Tortues", - "gui.computercraft.config.turtle.normal_fuel_limit": "Limite de carburant par Tortue", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Limite de carburant par Tortue avancée", - "gui.computercraft.config.turtle.obey_block_protection": "Les Tortues respectent les protections de blocs", - "gui.computercraft.config.turtle.can_push": "Les Tortues peuvent pousser les entitées" + "chat.computercraft.wired_modem.peripheral_disconnected": "Le periphérique \"%s\" est déconnecté du réseau" } diff --git a/src/main/resources/assets/computercraft/lang/it_it.json b/src/main/resources/assets/computercraft/lang/it_it.json index 620c8b515..ef5c67d68 100644 --- a/src/main/resources/assets/computercraft/lang/it_it.json +++ b/src/main/resources/assets/computercraft/lang/it_it.json @@ -1,41 +1,33 @@ { - + "itemGroup.computercraft": "ComputerCraft", "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Computer Avanzato", "block.computercraft.computer_command": "Computer Commando", - "block.computercraft.disk_drive": "Lettore disco", "block.computercraft.printer": "Stampante", "block.computercraft.speaker": "Altoparlante", - "block.computercraft.monitor_normal": "Monitor", "block.computercraft.monitor_advanced": "Monitor Avanzato", - "block.computercraft.wireless_modem_normal": "Modem Wireless", "block.computercraft.wireless_modem_advanced": "Modem di Ender", - "block.computercraft.wired_modem": "Modem Cablato", "block.computercraft.cable": "Cavo Di Rete", - + "block.computercraft.wired_modem_full": "Modem cablato", "block.computercraft.turtle_normal": "Tartaruga", "block.computercraft.turtle_normal.upgraded": "Tartaruga %s", "block.computercraft.turtle_normal.upgraded_twice": "Tartaruga %s %s", - "block.computercraft.turtle_advanced": "Tartaruga Avanzata", "block.computercraft.turtle_advanced.upgraded": "Tartaruga %s Avanzata", "block.computercraft.turtle_advanced.upgraded_twice": "Tartaruga %s %s Avanzata", - "item.computercraft.disk": "Disco Floppy", "item.computercraft.treasure_disk": "Disco Floppy", "item.computercraft.printed_page": "Pagina Stampata", "item.computercraft.printed_pages": "Pagine Stampate", "item.computercraft.printed_book": "Libro Stampato", - "item.computercraft.pocket_computer_normal": "Computer Tascabile", "item.computercraft.pocket_computer_normal.upgraded": "Computer Tascabile %s", "item.computercraft.pocket_computer_advanced": "Computer Tascabile Avanzato", "item.computercraft.pocket_computer_advanced.upgraded": "Computer Tascabile %s Avanzato", - "upgrade.minecraft.diamond_sword.adjective": "Da Combattimento", "upgrade.minecraft.diamond_shovel.adjective": "Scavatrice", "upgrade.minecraft.diamond_pickaxe.adjective": "Minatrice", @@ -45,48 +37,66 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "Wireless", "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", "upgrade.computercraft.speaker.adjective": "Rumoroso", - "chat.computercraft.wired_modem.peripheral_connected": "Periferica \"%s\" connessa alla rete", "chat.computercraft.wired_modem.peripheral_disconnected": "Periferica \"%s\" disconessa dalla rete", - + "commands.computercraft.synopsis": "Vari comandi per controllare i computer.", + "commands.computercraft.desc": "Il comando /computercraft dà accesso a vari strumenti di debug e amministrazione per controllare e interagire con i computer.", + "commands.computercraft.help.synopsis": "Dà aiuto su un determinato comando", + "commands.computercraft.help.desc": "Mostra questo messaggio d'aiuto", + "commands.computercraft.help.no_children": "%s non ha sottocomandi", + "commands.computercraft.help.no_command": "Non esiste il comando '%s'", + "commands.computercraft.dump.synopsis": "Mostra lo stato dei computer.", + "commands.computercraft.dump.desc": "Mostra lo stato di tutti i computer o informazioni specifiche su un computer. Puoi specificare l'instance id di un computer (e.g. 123), l'id di un computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", + "commands.computercraft.dump.action": "Mostra più informazioni su questo computer", + "commands.computercraft.shutdown.synopsis": "Spegne i computer da remoto.", + "commands.computercraft.shutdown.desc": "Spegne i computer specificati o tutti se non specificati. Puoi specificare l'instance id del computer (e.g. 123), l'id del computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", + "commands.computercraft.shutdown.done": "Spenti %s/%s computer", + "commands.computercraft.turn_on.synopsis": "Accende i computer da remoto.", + "commands.computercraft.turn_on.desc": "Accende i computer specificati. Puoi specificare l'instance id del computer (e.g. 123), l'id del computer (e.g. #123) o l'etichetta (e.g. \"@Il mio Computer\").", + "commands.computercraft.turn_on.done": "Accesi %s/%s computer", + "commands.computercraft.tp.synopsis": "Teletrasporta al computer specificato.", + "commands.computercraft.tp.desc": "Teletrasporta alla posizione di un computer. Puoi specificare il computer con l'instance id (e.g. 123) o con l'id (e.g. #123).", + "commands.computercraft.tp.action": "Teletrasporta a questo computer", + "commands.computercraft.tp.not_player": "Puoi aprire un terminale solo per un giocatore", + "commands.computercraft.tp.not_there": "Impossibile trovare il computer nel mondo", + "commands.computercraft.view.synopsis": "Mostra il terminale di un computer.", + "commands.computercraft.view.desc": "Apre il terminale di un computer, in modo da poterlo controllare da remoto. Non permette l'accesso all'inventario di una tartaruga. Puoi specificare l'instance id del computer (e.g. 123) o l'id (e.g. #123).", + "commands.computercraft.view.action": "Mostra questo computer", + "commands.computercraft.view.not_player": "Il terminale può essere aperto solo da un giocatore", + "commands.computercraft.track.synopsis": "Registra il tempo di esecuzione di tutti i computer.", + "commands.computercraft.track.desc": "Registra per quanto tempo i computer vengono eseguiti e quanti eventi ricevono. Questo comando fornisce le informazioni in modo simile a /forge track e può essere utile per monitorare il lag.", + "commands.computercraft.track.start.synopsis": "Inizia a monitorare tutti i computer", + "commands.computercraft.track.start.desc": "Inizia a monitorare tutti i tempi di esecuzione e il numero di eventi dei computer. Questo comando cancellerà i risultati precedenti.", + "commands.computercraft.track.start.stop": "Esegui %s per smettere di monitorare e mostrare i risultati", + "commands.computercraft.track.stop.synopsis": "Smetti di monitorare tutti i computer", + "commands.computercraft.track.stop.desc": "Smetti di monitorare tutti gli eventi e i tempi di esecuzione dei computer", + "commands.computercraft.track.stop.action": "Premi per smettere di monitorare", + "commands.computercraft.track.stop.not_enabled": "Non stanno venendo monitorati computer", + "commands.computercraft.track.dump.synopsis": "Cancella gli ultimi risultati monitorati", + "commands.computercraft.track.dump.desc": "Cancella gli ultimi risultati del monitoraggio dei computer.", + "commands.computercraft.track.dump.no_timings": "No tempi disponibili", + "commands.computercraft.track.dump.computer": "Computer", + "commands.computercraft.reload.synopsis": "Ricarica il file di configurazione della ComputerCraft", + "commands.computercraft.reload.desc": "Ricarica il file di configurazione della ComputerCraft", + "commands.computercraft.reload.done": "File di configurazione ricaricato", + "commands.computercraft.queue.synopsis": "Invia un evento computer_command ad un computer dei comandi", + "commands.computercraft.queue.desc": "Invia un evento computer_command ad un computer dei comandi, passando gli argomenti aggiuntivi. Questo comando è pensato per i map makers, è un versione più amichevole verso i computer di /trigger. Qualsiasi giocatore può eseguire il comando, è più probabile che venga fatto attraverso un evento click di un componente di testo.", + "commands.computercraft.generic.no_position": "", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.yes": "S", + "commands.computercraft.generic.no": "N", + "commands.computercraft.generic.additional_rows": "%d colonne aggiuntive…", + "argument.computercraft.computer.no_matching": "Nessun computer che combacia con '%s'", + "tracking_field.computercraft.average.name": "Tempo medio", + "tracking_field.computercraft.max.name": "Tempo massimo", + "tracking_field.computercraft.peripheral.name": "Chiamate alle periferiche", + "tracking_field.computercraft.fs.name": "Operazioni filesystem", + "tracking_field.computercraft.turtle.name": "Operazioni tartarughe", + "tracking_field.computercraft.http.name": "Richieste HTTP", + "tracking_field.computercraft.http_upload.name": "Upload HTTP", + "tracking_field.computercraft.http_download.name": "Download HTTP", + "tracking_field.computercraft.coroutines_created.name": "Coroutine create", "gui.computercraft.tooltip.copy": "Copia negli appunti", - - "gui.computercraft.config.computer_space_limit": "Limite spazio Computer (bytes)", - "gui.computercraft.config.floppy_space_limit": "Limite spazio Disco Floppy (bytes)", - "gui.computercraft.config.maximum_open_files": "Massimo file aperti per computer", - "gui.computercraft.config.disable_lua51_features": "Disattiva features Lua 5.1", - "gui.computercraft.config.default_computer_settings": "Impostazioni Computer predefinite", - "gui.computercraft.config.debug_enabled": "Attiva libreria di debug", - "gui.computercraft.config.log_computer_errors": "Salva errori computer", - - "gui.computercraft.config.execution.computer_threads": "Threads computer", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "Attiva l'API HTTP", - "gui.computercraft.config.http.websocket_enabled": "Attiva websocket", - "gui.computercraft.config.http.whitelist": "Lista bianca HTTP", - "gui.computercraft.config.http.blacklist": "Lista nera HTTP", - - "gui.computercraft.config.http.timeout": "Tempo di scadenza", - "gui.computercraft.config.http.max_requests": "Richieste correnti massime", - "gui.computercraft.config.http.max_download": "Massimo grandezza risposte", - "gui.computercraft.config.http.max_upload": "Massimo grandezza richieste", - "gui.computercraft.config.http.max_websockets": "Connessioni websocket massime", - "gui.computercraft.config.http.max_websocket_message": "Massimo grandezza messaggi websocket", - - "gui.computercraft.config.peripheral": "Periferiche", - "gui.computercraft.config.peripheral.command_block_enabled": "Attiva periferica blocco comandi", - "gui.computercraft.config.peripheral.modem_range": "Raggio Modem (default)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Raggio Modem (alta quota)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Raggio Modem (brutto tempo)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Raggio Modem (alta quota, brutto tempo)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Note massime alla volta", - - "gui.computercraft.config.turtle": "Tartarughe", - "gui.computercraft.config.turtle.need_fuel": "Attiva carburante", - "gui.computercraft.config.turtle.normal_fuel_limit": "Limite carburante tartarughe", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Limite carburante tartarughe avanzate", - "gui.computercraft.config.turtle.obey_block_protection": "Tartarughe rispettano le protezioni", - "gui.computercraft.config.turtle.can_push": "Le tartarughe possono spingere le entità", - "gui.computercraft.config.turtle.disabled_actions": "Disattiva azioni tartarughe" + "gui.computercraft.tooltip.computer_id": "ID Computer: %s", + "gui.computercraft.tooltip.disk_id": "ID Disco: %s" } diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.json b/src/main/resources/assets/computercraft/lang/ko_kr.json index c3056c726..7b5d65208 100644 --- a/src/main/resources/assets/computercraft/lang/ko_kr.json +++ b/src/main/resources/assets/computercraft/lang/ko_kr.json @@ -1,42 +1,32 @@ { "itemGroup.computercraft": "컴퓨터í¬ëž˜í”„트", - "block.computercraft.computer_normal": "컴퓨터", "block.computercraft.computer_advanced": "고급 컴퓨터", "block.computercraft.computer_command": "명령 컴퓨터", - "block.computercraft.disk_drive": "ë””ìŠ¤í¬ ë“œë¼ì´ë¸Œ", "block.computercraft.printer": "프린터", "block.computercraft.speaker": "스피커", - "block.computercraft.monitor_normal": "모니터", "block.computercraft.monitor_advanced": "고급 모니터", - "block.computercraft.wireless_modem_normal": "무선 모뎀", "block.computercraft.wireless_modem_advanced": "ì—”ë” ëª¨ëŽ€", - "block.computercraft.wired_modem": "유선 모뎀", "block.computercraft.cable": "ë„¤íŠ¸ì›Œí¬ ì¼€ì´ë¸”", - "block.computercraft.turtle_normal": "í„°í‹€", "block.computercraft.turtle_normal.upgraded": "%s í„°í‹€", "block.computercraft.turtle_normal.upgraded_twice": "%s %s í„°í‹€", - "block.computercraft.turtle_advanced": "고급 í„°í‹€", "block.computercraft.turtle_advanced.upgraded": "고급 %s í„°í‹€", "block.computercraft.turtle_advanced.upgraded_twice": "고급 %s %s í„°í‹€", - "item.computercraft.disk": "플로피 디스í¬", "item.computercraft.treasure_disk": "플로피 디스í¬", "item.computercraft.printed_page": "ì¸ì‡„ëœ íŽ˜ì´ì§€", "item.computercraft.printed_pages": "ì¸ì‡„ëœ íŽ˜ì´ì§€ 모ìŒ", "item.computercraft.printed_book": "ì¸ì‡„ëœ ì±…", - "item.computercraft.pocket_computer_normal": "í¬ì¼“ 컴퓨터", "item.computercraft.pocket_computer_normal.upgraded": "%s í¬ì¼“ 컴퓨터", "item.computercraft.pocket_computer_advanced": "고급 í¬ì¼“ 컴퓨터", "item.computercraft.pocket_computer_advanced.upgraded": "고급 %s í¬ì¼“ 컴퓨터", - "upgrade.minecraft.diamond_sword.adjective": "난투", "upgrade.minecraft.diamond_shovel.adjective": "êµ´ì°©", "upgrade.minecraft.diamond_pickaxe.adjective": "채굴", @@ -46,140 +36,73 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "무선", "upgrade.computercraft.wireless_modem_advanced.adjective": "ì—”ë”", "upgrade.computercraft.speaker.adjective": "소ìŒ", - "chat.computercraft.wired_modem.peripheral_connected": "주변 \"%s\"ì´ ë„¤íŠ¸ì›Œí¬ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤.", "chat.computercraft.wired_modem.peripheral_disconnected": "주변 \"%s\"ì´ ë„¤íŠ¸ì›Œí¬ë¡œë¶€í„° 분리ë˜ì—ˆìŠµë‹ˆë‹¤.", - "commands.computercraft.synopsis": "컴퓨터를 제어하기 위한 다양한 명령어", "commands.computercraft.desc": "/computercraft 명령어는 컴퓨터를 제어하고 ìƒí˜¸ìž‘용하기 위한 다양한 디버깅 ë° ê´€ë¦¬ìž ë„구를 제공합니다.", - "commands.computercraft.help.synopsis": "특정 ëª…ë ¹ì–´ì— ëŒ€í•œ ë„움ë§ì„ 제공하기", - "commands.computercraft.help.desc": "", "commands.computercraft.help.no_children": "%sì—는 하위 명령어가 없습니다.", "commands.computercraft.help.no_command": "'%s'ë¼ëŠ” 명령어가 없습니다.", - "commands.computercraft.dump.synopsis": "ì»´í“¨í„°ì˜ ìƒíƒœë¥¼ 보여주기", "commands.computercraft.dump.desc": "모든 ì‹œìŠ¤í…œì˜ ìƒíƒœ ë˜ëŠ” 한 ì‹œìŠ¤í…œì— ëŒ€í•œ 특정 정보를 표시합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: \"@My Computer\")ì„ ì§€ì •í•  수 있습니다.", "commands.computercraft.dump.action": "ì´ ì»´í“¨í„°ì— ëŒ€í•œ 추가 정보를 봅니다.", - "commands.computercraft.shutdown.synopsis": "ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 종료하기", "commands.computercraft.shutdown.desc": "ë‚˜ì—´ëœ ì‹œìŠ¤í…œ ë˜ëŠ” ì§€ì •ëœ ì‹œìŠ¤í…œì´ ì—†ëŠ” 경우 ëª¨ë‘ ì¢…ë£Œí•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: \"@My Computer\")ì„ ì§€ì •í•  수 있습니다.", "commands.computercraft.shutdown.done": "%s/%s 컴퓨터 시스템 종료", - "commands.computercraft.turn_on.synopsis": "ì‹œìŠ¤í…œì„ ì›ê²©ìœ¼ë¡œ 실행하기", "commands.computercraft.turn_on.desc": "ë‚˜ì—´ëœ ì»´í“¨í„°ë¥¼ 실행합니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123)나 컴퓨터 ID(예: #123) ë˜ëŠ” ë¼ë²¨(예: \"@My Computer\")ì„ ì§€ì •í•  수 있습니다.", "commands.computercraft.turn_on.done": "%s/%s 컴퓨터 시스템 실행", - "commands.computercraft.tp.synopsis": "특정 컴퓨터로 순간ì´ë™í•˜ê¸°", "commands.computercraft.tp.desc": "ì»´í“¨í„°ì˜ ìœ„ì¹˜ë¡œ 순간ì´ë™í•©ë‹ˆë‹¤. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", "commands.computercraft.tp.action": "ì´ ì»´í“¨í„°ë¡œ 순간ì´ë™í•˜ê¸°", "commands.computercraft.tp.not_there": "월드ì—서 컴퓨터를 위치시킬 수 없습니다.", - "commands.computercraft.view.synopsis": "ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ë³´ê¸°", "commands.computercraft.view.desc": "ì»´í“¨í„°ì˜ ì›ê²© 제어를 허용하는 ì»´í“¨í„°ì˜ í„°ë¯¸ë„ì„ ì—½ë‹ˆë‹¤. ì´ê²ƒì€ í„°í‹€ì˜ ì¸ë²¤í† ë¦¬ì— 대한 ì ‘ê·¼ì„ ì œê³µí•˜ì§€ 않습니다. ì»´í“¨í„°ì˜ ì¸ìŠ¤í„´ìŠ¤ ID(예: 123) ë˜ëŠ” 컴퓨터 ID(예: #123)를 지정할 수 있습니다.", "commands.computercraft.view.action": "ì´ ì»´í“¨í„°ë¥¼ 봅니다.", "commands.computercraft.view.not_player": "비플레ì´ì–´í•œí…Œ 터미ë„ì„ ì—´ 수 없습니다.", - "commands.computercraft.track.synopsis": "ì»´í“¨í„°ì˜ ì‹¤í–‰ ì‹œê°„ì„ ì¶”ì í•˜ê¸°", "commands.computercraft.track.desc": "컴퓨터가 실행ë˜ëŠ” 기간과 처리ë˜ëŠ” ì´ë²¤íЏ 수를 ì¶”ì í•©ë‹ˆë‹¤. ì´ëŠ” /forge 트랙과 유사한 방법으로 정보를 제공하며 지연 ë¡œê·¸ì— ìœ ìš©í•  수 있습니다.", - "commands.computercraft.track.start.synopsis": "모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 시작하기", "commands.computercraft.track.start.desc": "모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 시작합니다. ì´ëŠ” ì´ì „ ì‹¤í–‰ì˜ ê²°ê³¼ë¥¼ í기할 것입니다.", "commands.computercraft.track.start.stop": "%sì„(를) 실행하여 ì¶”ì ì„ 중지하고 결과를 확ì¸í•©ë‹ˆë‹¤.", - "commands.computercraft.track.stop.synopsis": "모든 ì»´í“¨í„°ì˜ ì¶”ì ì„ 중지하기", "commands.computercraft.track.stop.desc": "모든 ì»´í“¨í„°ì˜ ì´ë²¤íЏ ë° ì‹¤í–‰ 시간 ì¶”ì ì„ 중지합니다.", "commands.computercraft.track.stop.action": "ì¶”ì ì„ 중지하려면 í´ë¦­í•˜ì„¸ìš”.", "commands.computercraft.track.stop.not_enabled": "현재 ì¶”ì í•˜ëŠ” 컴퓨터가 없습니다.", - "commands.computercraft.track.dump.synopsis": "최신 ì¶”ì  ê²°ê³¼ë¥¼ ë¤í”„하기", "commands.computercraft.track.dump.desc": "최신 컴퓨터 ì¶”ì ì˜ 결과를 ë¤í”„합니다.", "commands.computercraft.track.dump.no_timings": "사용가능한 ì‹œê°„ì´ ì—†ìŠµë‹ˆë‹¤.", "commands.computercraft.track.dump.computer": "컴퓨터", - "commands.computercraft.reload.synopsis": "컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드하기", "commands.computercraft.reload.desc": "컴퓨터í¬ëž˜í”„트 구성파ì¼ì„ 리로드합니다.", "commands.computercraft.reload.done": "ë¦¬ë¡œë“œëœ êµ¬ì„±", - "commands.computercraft.queue.synopsis": "computer_command ì´ë²¤íŠ¸ë¥¼ 명령 ì»´í“¨í„°ì— ë³´ë‚´ê¸°", "commands.computercraft.queue.desc": "computer_command ì´ë²¤íŠ¸ë¥¼ 명령 컴퓨터로 전송하여 추가 ì¸ìˆ˜ë¥¼ 전달합니다. ì´ëŠ” 대부분 ì§€ë„ ì œìž‘ìžë¥¼ 위해 설계ë˜ì—ˆìœ¼ë©°, 보다 컴퓨터 친화ì ì¸ ë²„ì „ì˜ /trigger ì—­í• ì„ í•©ë‹ˆë‹¤. ì–´ë–¤ 플레ì´ì–´ë“  ëª…ë ¹ì„ ì‹¤í–‰í•  수 있으며, ì´ëŠ” í…스트 구성 ìš”ì†Œì˜ í´ë¦­ ì´ë²¤íŠ¸ë¥¼ 통해 ìˆ˜í–‰ë  ê°€ëŠ¥ì„±ì´ ê°€ìž¥ 높습니다.", - "commands.computercraft.generic.no_position": "", "commands.computercraft.generic.position": "%s, %s, %s", "commands.computercraft.generic.yes": "Y", "commands.computercraft.generic.no": "N", "commands.computercraft.generic.exception": "처리ë˜ì§€ ì•Šì€ ì˜ˆì™¸ (%s)", "commands.computercraft.generic.additional_rows": "%dê°œì˜ ì¶”ê°€ í–‰...", - "argument.computercraft.computer.no_matching": "'%s'와 ì¼ì¹˜í•˜ëŠ” 컴퓨터가 없습니다.", "argument.computercraft.computer.many_matching": "'%s'와 ì¼ì¹˜í•˜ëŠ” 여러 컴퓨터 (ì¸ìŠ¤í„´ìŠ¤ %s)", - "tracking_field.computercraft.tasks.name": "작업", "tracking_field.computercraft.total.name": "ì „ì²´ 시간", "tracking_field.computercraft.average.name": "í‰ê·  시간", "tracking_field.computercraft.max.name": "최대 시간", - "tracking_field.computercraft.server_count.name": "서버 작업 수", "tracking_field.computercraft.server_time.name": "서버 작업 시간", - "tracking_field.computercraft.peripheral.name": "주변 호출", "tracking_field.computercraft.fs.name": "파ì¼ì‹œìŠ¤í…œ 작업", "tracking_field.computercraft.turtle.name": "í„°í‹€ 작업", - "tracking_field.computercraft.http.name": "HTTP 요청", "tracking_field.computercraft.http_upload.name": "HTTP 업로드", "tracking_field.computercraft.http_download.name": "HTTT 다운로드", - "tracking_field.computercraft.websocket_incoming.name": "웹소켓 수신", "tracking_field.computercraft.websocket_outgoing.name": "웹소켓 송신", - "tracking_field.computercraft.coroutines_created.name": "코루틴 ìƒì„±ë¨", "tracking_field.computercraft.coroutines_dead.name": "코루틴 처리ë¨", - "gui.computercraft.tooltip.copy": "í´ë¦½ë³´ë“œì— 복사", "gui.computercraft.tooltip.computer_id": "컴퓨터 ID: %s", - "gui.computercraft.tooltip.disk_id": "ë””ìŠ¤í¬ ID: %s", - - "gui.computercraft.config.computer_space_limit": "컴퓨터 공간 제한 (ë°”ì´íЏ)", - "gui.computercraft.config.floppy_space_limit": "플로피 ë””ìŠ¤í¬ ê³µê°„ 제한 (ë°”ì´íЏ)", - "gui.computercraft.config.maximum_open_files": "컴퓨터당 최대 íŒŒì¼ ì—´ê¸°", - "gui.computercraft.config.disable_lua51_features": "Lua 5.1 기능 미사용", - "gui.computercraft.config.default_computer_settings": "기본 컴퓨터 설정", - "gui.computercraft.config.debug_enabled": "디버그 ë¼ì´ë¸ŒëŸ¬ë¦¬ 사용", - "gui.computercraft.config.log_computer_errors": "컴퓨터 오류 로그", - - "gui.computercraft.config.execution": "실행", - "gui.computercraft.config.execution.computer_threads": "컴퓨터 쓰레드", - "gui.computercraft.config.execution.max_main_global_time": "ì „ì—­ 시간 당 서버 제한", - "gui.computercraft.config.execution.max_main_computer_time": "컴퓨터 시간 당 서버 제한", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "HTTP API 사용하기", - "gui.computercraft.config.http.websocket_enabled": "웹소켓 사용", - - "gui.computercraft.config.http.timeout": "타임아웃", - "gui.computercraft.config.http.max_requests": "최대 ë™ì‹œ 요청 수", - "gui.computercraft.config.http.max_download": "최대 ì‘답 í¬ê¸°", - "gui.computercraft.config.http.max_upload": "최대 요청 í¬ê¸°", - "gui.computercraft.config.http.max_websockets": "최대 ë™ì‹œ 웹소켓 수", - "gui.computercraft.config.http.max_websocket_message": "최대 웹 í¬ì¼“ 메시지 í¬ê¸°", - - "gui.computercraft.config.peripheral": "주변", - "gui.computercraft.config.peripheral.command_block_enabled": "명령 ë¸”ë¡ ì£¼ë³€ 장치 사용", - "gui.computercraft.config.peripheral.modem_range": "모뎀 범위(기본값)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "모뎀 범위(ë†’ì€ ê³ ë„)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "모뎀 범위(ë‚˜ìœ ë‚ ì”¨)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "모뎀 범위(ë†’ì€ ê³ ë„, ë‚˜ìœ ë‚ ì”¨)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "컴퓨터가 한 ë²ˆì— ìž¬ìƒí•  수 있는 최대 소리 수", - - "gui.computercraft.config.turtle": "í„°í‹€", - "gui.computercraft.config.turtle.need_fuel": "연료 사용", - "gui.computercraft.config.turtle.normal_fuel_limit": "í„°í‹€ 연료 제한", - "gui.computercraft.config.turtle.advanced_fuel_limit": "고급 í„°í‹€ 연료 제한", - "gui.computercraft.config.turtle.obey_block_protection": "í„°í‹€ì´ ë¸”ë¡ ë³´í˜¸ì— ë”°ë¥´ê¸°", - "gui.computercraft.config.turtle.can_push": "í„°í‹€ì´ ì—”í‹°í‹° 밀어내기", - "gui.computercraft.config.turtle.disabled_actions": "í„°í‹€ ì•¡ì…˜ 미사용", - - "gui.computercraft.config.http.allowed_domains": "í—ˆìš©ëœ ë„ë©”ì¸", - "gui.computercraft.config.http.blocked_domains": "ì°¨ë‹¨ëœ ë„ë©”ì¸" + "gui.computercraft.tooltip.disk_id": "ë””ìŠ¤í¬ ID: %s" } diff --git a/src/main/resources/assets/computercraft/lang/nl_nl.json b/src/main/resources/assets/computercraft/lang/nl_nl.json new file mode 100644 index 000000000..a06022278 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/nl_nl.json @@ -0,0 +1,54 @@ +{ + "itemGroup.computercraft": "ComputerCraft", + "block.computercraft.computer_normal": "Computer", + "block.computercraft.computer_advanced": "Geavanceerde Computer", + "block.computercraft.computer_command": "Commandocomputer", + "block.computercraft.disk_drive": "Diskettestation", + "block.computercraft.printer": "Printer", + "block.computercraft.speaker": "Luidspreker", + "block.computercraft.monitor_normal": "Beeldscherm", + "block.computercraft.monitor_advanced": "Geavanceerd Beeldscherm", + "block.computercraft.wireless_modem_normal": "Draadloze Modem", + "block.computercraft.wireless_modem_advanced": "Ender Modem", + "block.computercraft.wired_modem": "Bedrade Modem", + "block.computercraft.cable": "Netwerkkabel", + "block.computercraft.wired_modem_full": "Bedrade Modem", + "block.computercraft.turtle_normal": "Turtle", + "block.computercraft.turtle_normal.upgraded": "%s Turtle", + "block.computercraft.turtle_normal.upgraded_twice": "%s %s Turtle", + "block.computercraft.turtle_advanced": "Geavanceerde Turtle", + "block.computercraft.turtle_advanced.upgraded": "Geavanceerde %s Turtle", + "block.computercraft.turtle_advanced.upgraded_twice": "Geavanceerde %s %s Turtle", + "item.computercraft.disk": "Diskette", + "item.computercraft.treasure_disk": "Diskette", + "item.computercraft.printed_page": "Geprinte Pagina", + "item.computercraft.printed_pages": "Geprinte Pagina's", + "item.computercraft.printed_book": "Geprint Boek", + "item.computercraft.pocket_computer_normal": "Zakcomputer", + "item.computercraft.pocket_computer_normal.upgraded": "%s Zakcomputer", + "item.computercraft.pocket_computer_advanced": "Geavanceerde Zakcomputer", + "item.computercraft.pocket_computer_advanced.upgraded": "Geavanceerde %s Zakcomputer", + "upgrade.minecraft.diamond_sword.adjective": "Vechtende", + "upgrade.minecraft.diamond_shovel.adjective": "Gravende", + "upgrade.minecraft.diamond_pickaxe.adjective": "Mijnbouw", + "upgrade.minecraft.diamond_axe.adjective": "Kappende", + "upgrade.minecraft.diamond_hoe.adjective": "Landbouw", + "upgrade.minecraft.crafting_table.adjective": "Craftende", + "upgrade.computercraft.wireless_modem_normal.adjective": "Draadloos", + "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", + "upgrade.computercraft.speaker.adjective": "Lawaaierige", + "chat.computercraft.wired_modem.peripheral_connected": "Randapperaat \"%s\" gekoppeld met netwerk", + "chat.computercraft.wired_modem.peripheral_disconnected": "Randapperaat \"%s\" ontkoppeld van netwerk", + "commands.computercraft.synopsis": "Verschillende commando's voor het beheren van computers.", + "commands.computercraft.desc": "Het /computercraft commando biedt verschillende debug- en administrator-tools voor het beheren van en werken met Computers.", + "commands.computercraft.help.synopsis": "Biedt hulp voor een specifiek commando", + "commands.computercraft.help.desc": "Geeft dit hulpbericht weer", + "commands.computercraft.help.no_children": "%s heeft geen sub-commando's", + "commands.computercraft.help.no_command": "Er bestaat geen commando als '%s'", + "commands.computercraft.dump.synopsis": "Geef de status van computers weer.", + "commands.computercraft.dump.desc": "Geef de status van alle computers of specifieke informatie over \\u00e9\\u00e9n computer weer. Je kunt een instance-id (bijv. 123), computer-id (bijv. #123) of computer-label (bijv. \\\"@Mijn Computer\\\") opgeven.", + "commands.computercraft.dump.action": "Geef meer informatie over deze computer weer", + "commands.computercraft.shutdown.synopsis": "Sluit computers af op afstand.", + "commands.computercraft.shutdown.desc": "Sluit alle genoemde computers af, of geen enkele wanneer niet gespecificeerd. Je kunt een instance-id (bijv. 123), computer-id (bijv. #123) of computer-label (bijv. \\\"@Mijn Computer\\\") opgeven.", + "commands.computercraft.shutdown.done": "%s/%s computers afgesloten" +} diff --git a/src/main/resources/assets/computercraft/lang/pl_pl.json b/src/main/resources/assets/computercraft/lang/pl_pl.json new file mode 100644 index 000000000..027fc006e --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/pl_pl.json @@ -0,0 +1,43 @@ +{ + "itemGroup.computercraft": "ComputerCraft", + "block.computercraft.computer_normal": "Komputer", + "block.computercraft.computer_advanced": "Zaawansowany Komputer", + "block.computercraft.computer_command": "Komputer Komendowy", + "block.computercraft.disk_drive": "Stacja Dyskietek", + "block.computercraft.printer": "Drukarka", + "block.computercraft.speaker": "GÅ‚oÅ›nik", + "block.computercraft.monitor_normal": "Monitor", + "block.computercraft.monitor_advanced": "Zaawansowany Monitor", + "block.computercraft.wireless_modem_normal": "Bezprzewodowy Adapter Sieciowy", + "block.computercraft.wired_modem": "Adapter Sieciowy", + "block.computercraft.cable": "Kabel Sieciowy", + "block.computercraft.wired_modem_full": "Adapter Sieciowy", + "item.computercraft.disk": "Dyskietka", + "item.computercraft.treasure_disk": "Dyskietka", + "item.computercraft.printed_page": "Wydrukowana Strona", + "item.computercraft.printed_pages": "Wydrukowane Strony", + "item.computercraft.printed_book": "Wydrukowana Książka", + "item.computercraft.pocket_computer_normal": "Komputer PrzenoÅ›ny", + "item.computercraft.pocket_computer_normal.upgraded": "%s Komputer PrzenoÅ›ny", + "item.computercraft.pocket_computer_advanced": "Zaawansowany Komputer PrzenoÅ›ny", + "chat.computercraft.wired_modem.peripheral_connected": "UrzÄ…dzenie \"%s\" zostaÅ‚o podłączone do sieci", + "chat.computercraft.wired_modem.peripheral_disconnected": "UrzÄ…dzenie \"%s\" zostaÅ‚o odłączone od sieci", + "commands.computercraft.synopsis": "Różne komendy do kontrolowania komputerami.", + "commands.computercraft.desc": "Komenda /computercraft dostarcza wiele narzÄ™dzi do zarzÄ…dzania, kontrolowania i administrowania komputerami.", + "commands.computercraft.help.synopsis": "Uzyskaj pomoc do konkretnej komendy", + "commands.computercraft.help.no_children": "%s nie ma pod-komend", + "commands.computercraft.help.no_command": "Nie odnaleziono komendy '%s'", + "commands.computercraft.dump.synopsis": "WyÅ›wietl stan komputerów.", + "commands.computercraft.dump.desc": "WyÅ›wietla status wszystkich komputerów lub informacje o jednym komputerze. Możesz wybrać numer sesji komputera (np. 123), ID komputera (np. #123) lub jego etykietÄ™ (np. \"@Mój Komputer\").", + "commands.computercraft.dump.action": "WyÅ›wietl wiÄ™cej informacji o tym komputerze", + "commands.computercraft.shutdown.synopsis": "Zdalnie wyłącz komputery.", + "commands.computercraft.shutdown.desc": "Wyłącz wszystkie, lub tylko wylistowane komputery. Możesz wybrać numer sesji komputera (np. 123), ID komputera (np. #123) lub jego etykietÄ™ (np. \"@Mój Komputer\").", + "commands.computercraft.shutdown.done": "Wyłączono %s z %s komputerów", + "commands.computercraft.turn_on.synopsis": "Zdalnie włącz komputery.", + "commands.computercraft.turn_on.desc": "Włącz podane komputery. Możesz wybrać numer sesji komputera (np. 123), ID komputera (np. #123) lub jego etykietÄ™ (np. \"@Mój Komputer\").", + "commands.computercraft.turn_on.done": "Włączono %s z %s komputerów", + "commands.computercraft.tp.synopsis": "Przeteleportuj siÄ™ do podanego komputera.", + "commands.computercraft.tp.desc": "Przeteleportuj siÄ™ do lokalizacji komputera. Możesz wybrać numer sesji komputera (np. 123) lub ID komputera (np. #123).", + "commands.computercraft.tp.action": "Przeteleportuj siÄ™ do podanego komputera", + "commands.computercraft.view.synopsis": "WyÅ›wietl ekran komputera." +} diff --git a/src/main/resources/assets/computercraft/lang/pt_br.json b/src/main/resources/assets/computercraft/lang/pt_br.json index c4b1f4963..0f7df3362 100644 --- a/src/main/resources/assets/computercraft/lang/pt_br.json +++ b/src/main/resources/assets/computercraft/lang/pt_br.json @@ -1,42 +1,32 @@ { - "block.computercraft.computer_normal": "Computador", "block.computercraft.computer_advanced": "Computador Avançado", "block.computercraft.computer_command": "Computador de Comandos", - "block.computercraft.disk_drive": "Leitor de Disco", "block.computercraft.printer": "Impressora", "block.computercraft.speaker": "Alto-Falante", - "block.computercraft.monitor_normal": "Monitor", "block.computercraft.monitor_advanced": "Monitor Avançado", - "block.computercraft.wireless_modem_normal": "Modem sem Fio", "block.computercraft.wireless_modem_advanced": "Modem Ender", - "block.computercraft.wired_modem": "Modem com Fio", "block.computercraft.cable": "Cabo de Rede", "block.computercraft.wired_modem_full": "Modem com Fio", - "block.computercraft.turtle_normal": "Tartaruga", "block.computercraft.turtle_normal.upgraded": "Tartaruga %s", "block.computercraft.turtle_normal.upgraded_twice": "Tartaruga %s %s", - "block.computercraft.turtle_advanced": "Tartaruga Avançada", "block.computercraft.turtle_advanced.upgraded": "Tartaruga Avançada %s", "block.computercraft.turtle_advanced.upgraded_twice": "Tartaruga Avançada %s %s", - "item.computercraft.disk": "Disquete", "item.computercraft.treasure_disk": "Disquete", "item.computercraft.printed_page": "Página Impressa", "item.computercraft.printed_pages": "Páginas Impressas", "item.computercraft.printed_book": "Livro Impresso", - "item.computercraft.pocket_computer_normal": "Computador Portátil", "item.computercraft.pocket_computer_normal.upgraded": "Computador Portátil %s", "item.computercraft.pocket_computer_advanced": "Computador Portátil Avançado", "item.computercraft.pocket_computer_advanced.upgraded": "Computador Portátil Avançado %s", - "upgrade.minecraft.diamond_sword.adjective": "Lutadora", "upgrade.minecraft.diamond_shovel.adjective": "Escavadora", "upgrade.minecraft.diamond_pickaxe.adjective": "Mineiradora", @@ -46,48 +36,7 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "sem Fio", "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", "upgrade.computercraft.speaker.adjective": "(Alto-Falante)", - "chat.computercraft.wired_modem.peripheral_connected": "Periférico \"%s\" conectado à rede", "chat.computercraft.wired_modem.peripheral_disconnected": "Periférico \"%s\" desconectado da rede", - - "gui.computercraft.tooltip.copy": "Copiar para a área de transferência", - - "gui.computercraft.config.computer_space_limit": "Limite de espaço dos Computadores (bytes)", - "gui.computercraft.config.floppy_space_limit": "Limite de espaço dos Disquetes (bytes)", - "gui.computercraft.config.maximum_open_files": "Número máximo de arquivos em um computador", - "gui.computercraft.config.disable_lua51_features": "Desabilitar funcionalidade da Lua 5.1", - "gui.computercraft.config.default_computer_settings": "Configurações padrão para Computadores", - "gui.computercraft.config.debug_enabled": "Habilitar biblioteca de debug", - "gui.computercraft.config.log_computer_errors": "Registrar erros de computadores", - - "gui.computercraft.config.execution.computer_threads": "Threads por computador", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "Habilitar a biblioteca de HTTP", - "gui.computercraft.config.http.websocket_enabled": "Habilitar websockets", - "gui.computercraft.config.http.whitelist": "Lista de endereços autorizados", - "gui.computercraft.config.http.blacklist": "Lista de endereços proíbidos", - - "gui.computercraft.config.http.timeout": "Tempo limite para conexões", - "gui.computercraft.config.http.max_requests": "Limite de conexões paralelas", - "gui.computercraft.config.http.max_download": "Tamanho limite de respostas", - "gui.computercraft.config.http.max_upload": "Tamanho limite de pedidos", - "gui.computercraft.config.http.max_websockets": "Limite de conexões websocket", - "gui.computercraft.config.http.max_websocket_message": "Tamanho limite de mensagens websocket", - - "gui.computercraft.config.peripheral": "Periféricos", - "gui.computercraft.config.peripheral.command_block_enabled": "Habilitar periférico do bloco de comando", - "gui.computercraft.config.peripheral.modem_range": "Alcance do modem (padrão)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Alcance do modem (altitude elevada)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Alcance do modem (clima ruim)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Alcance do modem (altitude elevada, clima ruim)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Número de notas que um computador pode tocar simultâneamente", - - "gui.computercraft.config.turtle": "Tartarugas", - "gui.computercraft.config.turtle.need_fuel": "Habilitar combustível", - "gui.computercraft.config.turtle.normal_fuel_limit": "Limite de combustível de Tartarugas", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Limite de combustível de Tartarugas Avançadas", - "gui.computercraft.config.turtle.obey_block_protection": "Tartarugas obedecem proteção de blocos", - "gui.computercraft.config.turtle.can_push": "Tartarugas podem empurrar entidades", - "gui.computercraft.config.turtle.disabled_actions": "Ações proíbidas para tartarugas" + "gui.computercraft.tooltip.copy": "Copiar para a área de transferência" } diff --git a/src/main/resources/assets/computercraft/lang/sv_se.json b/src/main/resources/assets/computercraft/lang/sv_se.json index 81648dec6..b71e4fecb 100644 --- a/src/main/resources/assets/computercraft/lang/sv_se.json +++ b/src/main/resources/assets/computercraft/lang/sv_se.json @@ -1,42 +1,32 @@ { - "block.computercraft.computer_normal": "Dator", "block.computercraft.computer_advanced": "Avancerad Dator", "block.computercraft.computer_command": "Kommando Dator", - "block.computercraft.disk_drive": "Diskettläsare", "block.computercraft.printer": "Skrivare", "block.computercraft.speaker": "Högtalare", - "block.computercraft.monitor_normal": "Skärm", "block.computercraft.monitor_advanced": "Avancerad Skärm", - "block.computercraft.wireless_modem_normal": "TrÃ¥dlöst Modem", "block.computercraft.wireless_modem_advanced": "Ender Modem", - "block.computercraft.wired_modem": "TrÃ¥dat Modem", "block.computercraft.cable": "Nätverkskabel", "block.computercraft.wired_modem_full": "TrÃ¥dat Modem", - "block.computercraft.turtle_normal": "Turtle", "block.computercraft.turtle_normal.upgraded": "%s Turtle", "block.computercraft.turtle_normal.upgraded_twice": "%s %s Turtle", - "block.computercraft.turtle_advanced": "Avancerad Turtle", "block.computercraft.turtle_advanced.upgraded": "Avancerad %s Turtle", "block.computercraft.turtle_advanced.upgraded_twice": "Avancerad %s %s Turtle", - "item.computercraft.disk": "Diskett", "item.computercraft.treasure_disk": "Diskett", "item.computercraft.printed_page": "Utskriven Sida", "item.computercraft.printed_pages": "Utskrivna Sidor", "item.computercraft.printed_book": "Tryckt bok", - "item.computercraft.pocket_computer_normal": "Fickdator", "item.computercraft.pocket_computer_normal.upgraded": "%s Fickdator", "item.computercraft.pocket_computer_advanced": "Avancerad Fickdator", "item.computercraft.pocket_computer_advanced.upgraded": "Avancerad %s Fickdator", - "upgrade.minecraft.diamond_sword.adjective": "Närstridande", "upgrade.minecraft.diamond_shovel.adjective": "Grävande", "upgrade.minecraft.diamond_pickaxe.adjective": "Brytande", @@ -46,48 +36,7 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "TrÃ¥dlös", "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", "upgrade.computercraft.speaker.adjective": "Högljudd", - "chat.computercraft.wired_modem.peripheral_connected": "Kringutrustning \"%s\" är kopplad till nätverket", "chat.computercraft.wired_modem.peripheral_disconnected": "Kringutrustning \"%s\" är frÃ¥nkopplad frÃ¥n nätverket", - - "gui.computercraft.tooltip.copy": "Kopiera till urklipp", - - "gui.computercraft.config.computer_space_limit": "Dator maximalt utrymme (bytes)", - "gui.computercraft.config.floppy_space_limit": "Diskett maximalt utrymme (bytes)", - "gui.computercraft.config.maximum_open_files": "Max antal filer öppna per dator", - "gui.computercraft.config.disable_lua51_features": "Avaktivera Lua 5.1 funktioner", - "gui.computercraft.config.default_computer_settings": "Standard Datorinställningar", - "gui.computercraft.config.debug_enabled": "Aktivera debug bibliotek", - "gui.computercraft.config.log_computer_errors": "Logga datorfel", - - "gui.computercraft.config.execution.computer_threads": "Dator trÃ¥dar", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "Aktivera HTTP API", - "gui.computercraft.config.http.websocket_enabled": "Aktivera websockets", - "gui.computercraft.config.http.whitelist": "HTTP vitlista", - "gui.computercraft.config.http.blacklist": "HTTP svartlista", - - "gui.computercraft.config.http.timeout": "Timeout", - "gui.computercraft.config.http.max_requests": "Maximalt antal samgÃ¥ende förfrÃ¥gningar", - "gui.computercraft.config.http.max_download": "Maximal svarsstorlek", - "gui.computercraft.config.http.max_upload": "Maximal förfrÃ¥gan", - "gui.computercraft.config.http.max_websockets": "Maximalt antal samgÃ¥ende websockets", - "gui.computercraft.config.http.max_websocket_message": "Maximal websocket meddelandestorlek", - - "gui.computercraft.config.peripheral": "Kringutrustning", - "gui.computercraft.config.peripheral.command_block_enabled": "Aktivera kommandoblock som kringutrustning", - "gui.computercraft.config.peripheral.modem_range": "Modem räckvidd (standard)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "Modem räckvidd (hög altitud)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "Modem räckvidd (dÃ¥ligt väder)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Modem räckvidd (hög altitud, dÃ¥ligt väder)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "Maximalt antal musiknoter en dator kan spela samtidigt", - - "gui.computercraft.config.turtle": "Turtles", - "gui.computercraft.config.turtle.need_fuel": "Aktivera bränsle", - "gui.computercraft.config.turtle.normal_fuel_limit": "Turtle bränslegräns", - "gui.computercraft.config.turtle.advanced_fuel_limit": "Advanced Turtle bränslegräns", - "gui.computercraft.config.turtle.obey_block_protection": "Turtles lyder blockskydd", - "gui.computercraft.config.turtle.can_push": "Turtles kan putta entiteter", - "gui.computercraft.config.turtle.disabled_actions": "Avaktiverade turtle Ã¥tgärder" + "gui.computercraft.tooltip.copy": "Kopiera till urklipp" } diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.json b/src/main/resources/assets/computercraft/lang/zh_cn.json index 7df723d40..c5c672e62 100644 --- a/src/main/resources/assets/computercraft/lang/zh_cn.json +++ b/src/main/resources/assets/computercraft/lang/zh_cn.json @@ -1,43 +1,33 @@ { "itemGroup.computercraft": "CC: Tweaked", - "block.computercraft.computer_normal": "计算机", "block.computercraft.computer_advanced": "高级计算机", "block.computercraft.computer_command": "命令电脑", - "block.computercraft.disk_drive": "ç£ç›˜é©±åЍ噍", "block.computercraft.printer": "æ‰“å°æœº", "block.computercraft.speaker": "扬声器", - "block.computercraft.monitor_normal": "显示器", "block.computercraft.monitor_advanced": "高级显示器", - "block.computercraft.wireless_modem_normal": "无线调制解调器", "block.computercraft.wireless_modem_advanced": "末影调制解调器", - "block.computercraft.wired_modem": "有线调制解调器", "block.computercraft.cable": "网络电缆", "block.computercraft.wired_modem_full": "有线调制解调器", - "block.computercraft.turtle_normal": "海龟", "block.computercraft.turtle_normal.upgraded": "%s海龟", "block.computercraft.turtle_normal.upgraded_twice": "%s%s海龟", - "block.computercraft.turtle_advanced": "高级海龟", "block.computercraft.turtle_advanced.upgraded": "高级%s海龟", "block.computercraft.turtle_advanced.upgraded_twice": "高级%s%s海龟", - "item.computercraft.disk": "软盘", "item.computercraft.treasure_disk": "软盘", "item.computercraft.printed_page": "打å°çº¸", "item.computercraft.printed_pages": "打å°çº¸", "item.computercraft.printed_book": "打å°ä¹¦", - "item.computercraft.pocket_computer_normal": "手æè®¡ç®—机", "item.computercraft.pocket_computer_normal.upgraded": "%s手æè®¡ç®—机", "item.computercraft.pocket_computer_advanced": "高级手æè®¡ç®—机", "item.computercraft.pocket_computer_advanced.upgraded": "高级%s手æè®¡ç®—机", - "upgrade.minecraft.diamond_sword.adjective": "战斗", "upgrade.minecraft.diamond_shovel.adjective": "挖掘", "upgrade.minecraft.diamond_pickaxe.adjective": "采掘", @@ -47,144 +37,76 @@ "upgrade.computercraft.wireless_modem_normal.adjective": "无线", "upgrade.computercraft.wireless_modem_advanced.adjective": "末影", "upgrade.computercraft.speaker.adjective": "å–§é—¹", - "chat.computercraft.wired_modem.peripheral_connected": "外部设备\"%s\"连接到网络", "chat.computercraft.wired_modem.peripheral_disconnected": "外部设备\"%s\"与网络断开连接", - "commands.computercraft.synopsis": "å„ç§æŽ§åˆ¶è®¡ç®—æœºçš„å‘½ä»¤.", "commands.computercraft.desc": "/computercraft命令æä¾›å„ç§è°ƒè¯•和管ç†å·¥å…·ï¼Œç”¨äºŽæŽ§åˆ¶å’Œä¸Žè®¡ç®—机交互.", - "commands.computercraft.help.synopsis": "为特定的命令æä¾›å¸®åŠ©", - "commands.computercraft.help.desc": "", "commands.computercraft.help.no_children": "%s没有å­å‘½ä»¤", "commands.computercraft.help.no_command": "没有这样的命令'%s'", - "commands.computercraft.dump.synopsis": "显示计算机的状æ€.", "commands.computercraft.dump.desc": "æ˜¾ç¤ºæ‰€æœ‰è®¡ç®—æœºçš„çŠ¶æ€æˆ–æŸå°è®¡ç®—机的特定信æ¯. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. \"@My Computer\").", "commands.computercraft.dump.action": "查看有关此计算机的更多信æ¯", - "commands.computercraft.shutdown.synopsis": "远程关闭计算机.", "commands.computercraft.shutdown.desc": "关闭列出的计算机或全部计算机(如果未指定). ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. \"@My Computer\").", "commands.computercraft.shutdown.done": "关闭%s/%s计算机", - "commands.computercraft.turn_on.synopsis": "远程打开计算机.", "commands.computercraft.turn_on.desc": "打开列出的计算机. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. \"@My Computer\").", "commands.computercraft.turn_on.done": "打开%s/%s计算机", - "commands.computercraft.tp.synopsis": "ä¼ é€åˆ°ç‰¹å®šçš„计算机.", "commands.computercraft.tp.desc": "ä¼ é€åˆ°è®¡ç®—机的ä½ç½®. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123)或计算机id (例如. #123).", "commands.computercraft.tp.action": "ä¼ é€åˆ°è¿™å°ç”µè„‘", "commands.computercraft.tp.not_player": "无法为éžçŽ©å®¶æ‰“å¼€ç»ˆç«¯", "commands.computercraft.tp.not_there": "无法在世界上定ä½ç”µè„‘", - "commands.computercraft.view.synopsis": "查看计算机的终端.", "commands.computercraft.view.desc": "打开计算机的终端,å…许远程控制计算机. è¿™ä¸æä¾›å¯¹æµ·é¾Ÿåº“å­˜çš„è®¿é—®. ä½ å¯ä»¥æŒ‡å®šè®¡ç®—机的实例id (例如. 123)或计算机id (例如. #123).", "commands.computercraft.view.action": "查看此计算机", "commands.computercraft.view.not_player": "无法为éžçŽ©å®¶æ‰“å¼€ç»ˆç«¯", - "commands.computercraft.track.synopsis": "跟踪计算机的执行时间.", "commands.computercraft.track.desc": "跟踪计算机执行的时间以åŠå®ƒä»¬å¤„ç†çš„事件数. 这以/forge track类似的方å¼å‘ˆçŽ°ä¿¡æ¯ï¼Œå¯ç”¨äºŽè¯Šæ–­æ»žåŽ.", - "commands.computercraft.track.start.synopsis": "开始跟踪所有计算机", "commands.computercraft.track.start.desc": "开始跟踪所有计算机的执行时间和事件计数. 这将放弃先å‰è¿è¡Œçš„结果.", "commands.computercraft.track.start.stop": "è¿è¡Œ%sä»¥åœæ­¢è·Ÿè¸ªå¹¶æŸ¥çœ‹ç»“æžœ", - "commands.computercraft.track.stop.synopsis": "åœæ­¢è·Ÿè¸ªæ‰€æœ‰è®¡ç®—机", "commands.computercraft.track.stop.desc": "åœæ­¢è·Ÿè¸ªæ‰€æœ‰è®¡ç®—机的事件和执行时间", "commands.computercraft.track.stop.action": "ç‚¹å‡»åœæ­¢è·Ÿè¸ª", "commands.computercraft.track.stop.not_enabled": "ç›®å‰æ²¡æœ‰è·Ÿè¸ªè®¡ç®—机", - "commands.computercraft.track.dump.synopsis": "输出最新的跟踪结果", "commands.computercraft.track.dump.desc": "输出计算机跟踪的最新结果.", "commands.computercraft.track.dump.no_timings": "没有时åºå¯ç”¨", "commands.computercraft.track.dump.computer": "计算机", - "commands.computercraft.reload.synopsis": "釿–°åŠ è½½ComputerCrafté…置文件", "commands.computercraft.reload.desc": "釿–°åŠ è½½ComputerCrafté…置文件", "commands.computercraft.reload.done": "釿–°åŠ è½½é…ç½®", - "commands.computercraft.queue.synopsis": "å°†computer_command事件å‘é€åˆ°å‘½ä»¤è®¡ç®—机", "commands.computercraft.queue.desc": "å‘é€computer_command事件到命令计算机,并传递其他傿•°. è¿™ä¸»è¦æ˜¯ä¸ºåœ°å›¾åˆ¶ä½œè€…设计的, 作为/trigger更加计算机å‹å¥½çš„版本. 任何玩家都å¯ä»¥è¿è¡Œå‘½ä»¤, 这很å¯èƒ½æ˜¯é€šè¿‡æ–‡æœ¬ç»„件的点击事件完æˆçš„.", - "commands.computercraft.generic.no_position": "<æ— ä½ç½®>", "commands.computercraft.generic.position": "%s, %s, %s", "commands.computercraft.generic.yes": "Y", "commands.computercraft.generic.no": "N", "commands.computercraft.generic.exception": "未处ç†çš„异常(%s)", "commands.computercraft.generic.additional_rows": "%dé¢å¤–的行…", - "argument.computercraft.computer.no_matching": "没有计算机匹é…'%s'", "argument.computercraft.computer.many_matching": "多å°è®¡ç®—机匹é…'%s' (实例%s)", - "argument.computercraft.tracking_field.no_field": "未知字段'%s'", - "argument.computercraft.argument_expected": "预期自å˜é‡", - "tracking_field.computercraft.tasks.name": "任务", "tracking_field.computercraft.total.name": "总计时间", "tracking_field.computercraft.average.name": "平凿—¶é—´", "tracking_field.computercraft.max.name": "最大时间", - "tracking_field.computercraft.server_count.name": "æœåŠ¡å™¨ä»»åŠ¡è®¡æ•°", "tracking_field.computercraft.server_time.name": "æœåŠ¡å™¨ä»»åŠ¡æ—¶é—´", - "tracking_field.computercraft.peripheral.name": "外部设备呼å«", "tracking_field.computercraft.fs.name": "文件系统æ“作", "tracking_field.computercraft.turtle.name": "海龟æ“作", - "tracking_field.computercraft.http.name": "HTTP需求", "tracking_field.computercraft.http_upload.name": "HTTP上传", "tracking_field.computercraft.http_download.name": "HTTT下载", - "tracking_field.computercraft.websocket_incoming.name": "Websocketä¼ å…¥", "tracking_field.computercraft.websocket_outgoing.name": "Websocket传出", - "tracking_field.computercraft.coroutines_created.name": "ååŒåˆ›å»º", "tracking_field.computercraft.coroutines_dead.name": "ååŒå¤„ç†", - "gui.computercraft.tooltip.copy": "å¤åˆ¶åˆ°å‰ªè´´æ¿", "gui.computercraft.tooltip.computer_id": "计算机ID: %s", - "gui.computercraft.tooltip.disk_id": "ç£ç›˜ID: %s", - - "gui.computercraft.config.computer_space_limit": "计算机空间é™åˆ¶(字节)", - "gui.computercraft.config.floppy_space_limit": "软盘空间é™åˆ¶(字节)", - "gui.computercraft.config.maximum_open_files": "æ¯å°è®¡ç®—机打开的最大文件数", - "gui.computercraft.config.disable_lua51_features": "ç¦ç”¨Lua 5.1功能", - "gui.computercraft.config.default_computer_settings": "默认计算机设置", - "gui.computercraft.config.debug_enabled": "å¯ç”¨debug库", - "gui.computercraft.config.log_computer_errors": "记录计算机错误", - - "gui.computercraft.config.execution": "执行", - "gui.computercraft.config.execution.computer_threads": "计算机线程数", - "gui.computercraft.config.execution.max_main_global_time": "æœåС噍免局tickæ—¶é—´é™åˆ¶", - "gui.computercraft.config.execution.max_main_computer_time": "æœåŠ¡å™¨è®¡ç®—æœºtickæ—¶é—´é™åˆ¶", - - "gui.computercraft.config.http": "HTTP", - "gui.computercraft.config.http.enabled": "å¯ç”¨HTTP API", - "gui.computercraft.config.http.websocket_enabled": "å¯ç”¨websockets", - "gui.computercraft.config.http.whitelist": "HTTP白åå•", - "gui.computercraft.config.http.blacklist": "HTTP黑åå•", - - "gui.computercraft.config.http.timeout": "Timeout", - "gui.computercraft.config.http.max_requests": "最大并å‘请求数", - "gui.computercraft.config.http.max_download": "最大å“应数æ®å¤§å°", - "gui.computercraft.config.http.max_upload": "最大请求数æ®å¤§å°", - "gui.computercraft.config.http.max_websockets": "最大并å‘websocketsæ•°", - "gui.computercraft.config.http.max_websocket_message": "最大websockets消æ¯å¤§å°", - - "gui.computercraft.config.peripheral": "外部设备", - "gui.computercraft.config.peripheral.command_block_enabled": "å¯ç”¨å‘½ä»¤æ–¹å—外设", - "gui.computercraft.config.peripheral.modem_range": "调制解调器范围(默认)", - "gui.computercraft.config.peripheral.modem_high_altitude_range": "调制解调器范围(高海拔)", - "gui.computercraft.config.peripheral.modem_range_during_storm": "调制解调器范围(æ¶åŠ£å¤©æ°”)", - "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "调制解调器范围(高海拔, æ¶åŠ£å¤©æ°”)", - "gui.computercraft.config.peripheral.max_notes_per_tick": "计算机一次å¯ä»¥æ’­æ”¾çš„æœ€å¤§éŸ³ç¬¦æ•°é‡", - - "gui.computercraft.config.turtle": "海龟", - "gui.computercraft.config.turtle.need_fuel": "å¯ç”¨ç‡ƒæ–™", - "gui.computercraft.config.turtle.normal_fuel_limit": "海龟燃料é™åˆ¶", - "gui.computercraft.config.turtle.advanced_fuel_limit": "高级海龟燃料é™åˆ¶", - "gui.computercraft.config.turtle.obey_block_protection": "海龟æœä»Žæ–¹å—ä¿æŠ¤", - "gui.computercraft.config.turtle.can_push": "海龟å¯ä»¥æŽ¨åŠ¨å®žä½“", - "gui.computercraft.config.turtle.disabled_actions": "ç¦ç”¨æµ·é¾ŸåŠ¨ä½œ" + "gui.computercraft.tooltip.disk_id": "ç£ç›˜ID: %s" } diff --git a/tools/language.py b/tools/language.py new file mode 100644 index 000000000..9689e2ca0 --- /dev/null +++ b/tools/language.py @@ -0,0 +1,42 @@ +""" +Rewrites language files in order to be consistent with en_us. + +This will take every given language file and rewrite it to be in the same +order as the en_us file. Any keys which appear in the given file, but not +in en_us are removed. + +Note, this is not intended to be a fool-proof tool, rather a quick way to +ensure language files are mostly correct. +""" + +import pathlib, sys, json +from collections import OrderedDict + +root = pathlib.Path("src/main/resources/assets/computercraft/lang") + +with (root / "en_us.json").open(encoding="utf-8") as file: + en_us = json.load(file, object_hook=OrderedDict) + +for path in root.glob("*.json"): + if path.name == "en_us.json": + continue + + with path.open(encoding="utf-8") as file: + lang = json.load(file) + + out = OrderedDict() + missing = 0 + for k in en_us.keys(): + if k not in lang: + missing += 1 + elif lang[k] == "": + print("{} has empty translation for {}".format(path.name, k)) + else: + out[k] = lang[k] + + with path.open("w", encoding="utf-8", newline="\n") as file: + json.dump(out, file, indent=4, ensure_ascii=False) + file.write("\n") + + if missing > 0: + print("{} has {} missing translations.".format(path.name, missing)) From 58a2995bbc739ce44b46b18339c720937f77b628 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 18 Jun 2020 14:10:23 +0000 Subject: [PATCH 254/711] Translations for Dutch Translations for Chinese (Simplified) Translations for Korean Translations for German Co-authored-by: SquidDev --- .../assets/computercraft/lang/de_de.json | 4 +- .../assets/computercraft/lang/ko_kr.json | 4 +- .../assets/computercraft/lang/nl_nl.json | 61 ++++++++++++++++++- .../assets/computercraft/lang/zh_cn.json | 4 +- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/main/resources/assets/computercraft/lang/de_de.json b/src/main/resources/assets/computercraft/lang/de_de.json index 255a1d794..20e56e205 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.json +++ b/src/main/resources/assets/computercraft/lang/de_de.json @@ -1,5 +1,5 @@ { - "itemGroup.computercraft": "CC: Tweaked", + "itemGroup.computercraft": "ComputerCraft", "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Erweiterter Computer", "block.computercraft.computer_command": "Befehlscomputer", @@ -100,7 +100,7 @@ "tracking_field.computercraft.turtle.name": "Turtle Operationen", "tracking_field.computercraft.http.name": "HTTP-Requests", "tracking_field.computercraft.http_upload.name": "HTTP Upload", - "tracking_field.computercraft.http_download.name": "HTTT Download", + "tracking_field.computercraft.http_download.name": "HTTP Download", "tracking_field.computercraft.websocket_incoming.name": "Websocket eingehend", "tracking_field.computercraft.websocket_outgoing.name": "Websocket ausgehend", "tracking_field.computercraft.coroutines_created.name": "Koroutinen erstellt", diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.json b/src/main/resources/assets/computercraft/lang/ko_kr.json index 7b5d65208..919d7e56d 100644 --- a/src/main/resources/assets/computercraft/lang/ko_kr.json +++ b/src/main/resources/assets/computercraft/lang/ko_kr.json @@ -83,7 +83,7 @@ "commands.computercraft.generic.yes": "Y", "commands.computercraft.generic.no": "N", "commands.computercraft.generic.exception": "처리ë˜ì§€ ì•Šì€ ì˜ˆì™¸ (%s)", - "commands.computercraft.generic.additional_rows": "%dê°œì˜ ì¶”ê°€ í–‰...", + "commands.computercraft.generic.additional_rows": "%dê°œì˜ ì¶”ê°€ 행…", "argument.computercraft.computer.no_matching": "'%s'와 ì¼ì¹˜í•˜ëŠ” 컴퓨터가 없습니다.", "argument.computercraft.computer.many_matching": "'%s'와 ì¼ì¹˜í•˜ëŠ” 여러 컴퓨터 (ì¸ìŠ¤í„´ìŠ¤ %s)", "tracking_field.computercraft.tasks.name": "작업", @@ -97,7 +97,7 @@ "tracking_field.computercraft.turtle.name": "í„°í‹€ 작업", "tracking_field.computercraft.http.name": "HTTP 요청", "tracking_field.computercraft.http_upload.name": "HTTP 업로드", - "tracking_field.computercraft.http_download.name": "HTTT 다운로드", + "tracking_field.computercraft.http_download.name": "HTTP 다운로드", "tracking_field.computercraft.websocket_incoming.name": "웹소켓 수신", "tracking_field.computercraft.websocket_outgoing.name": "웹소켓 송신", "tracking_field.computercraft.coroutines_created.name": "코루틴 ìƒì„±ë¨", diff --git a/src/main/resources/assets/computercraft/lang/nl_nl.json b/src/main/resources/assets/computercraft/lang/nl_nl.json index a06022278..98a174583 100644 --- a/src/main/resources/assets/computercraft/lang/nl_nl.json +++ b/src/main/resources/assets/computercraft/lang/nl_nl.json @@ -50,5 +50,64 @@ "commands.computercraft.dump.action": "Geef meer informatie over deze computer weer", "commands.computercraft.shutdown.synopsis": "Sluit computers af op afstand.", "commands.computercraft.shutdown.desc": "Sluit alle genoemde computers af, of geen enkele wanneer niet gespecificeerd. Je kunt een instance-id (bijv. 123), computer-id (bijv. #123) of computer-label (bijv. \\\"@Mijn Computer\\\") opgeven.", - "commands.computercraft.shutdown.done": "%s/%s computers afgesloten" + "commands.computercraft.shutdown.done": "%s/%s computers afgesloten", + "commands.computercraft.track.stop.not_enabled": "Er worden op dit moment geen computers bijgehouden", + "commands.computercraft.track.dump.desc": "Dump de laatste resultaten van het bijhouden van computers.", + "commands.computercraft.queue.desc": "Verzend een computer_commando event naar een commandocomputer. Additionele argumenten worden doorgegeven. Dit is vooral bedoeld voor mapmakers. Het doet dienst als een computer-vriendelijke versie van /trigger. Elke speler kan het commando uitvoeren, wat meestal gedaan zal worden door een text-component klik-event.", + "commands.computercraft.turn_on.synopsis": "Zet computers aan op afstand.", + "commands.computercraft.turn_on.desc": "Zet de genoemde computers aan op afstand. Je kunt een instance-id (bijv. 123), computer-id (bijv. #123) of computer-label (bijv. \"@Mijn Computer\") opgeven.", + "commands.computercraft.turn_on.done": "%s/%s computers aangezet", + "commands.computercraft.tp.synopsis": "Teleporteer naar een specifieke computer.", + "commands.computercraft.tp.desc": "Teleporteer naar de locatie van een specefieke computer. Je kunt een instance-id (bijv. 123) of computer-id (bijv. #123) opgeven.", + "commands.computercraft.tp.action": "Teleporteer naar deze computer", + "commands.computercraft.tp.not_player": "Kan geen terminal openen voor non-speler", + "commands.computercraft.tp.not_there": "Kan de computer niet lokaliseren", + "commands.computercraft.view.synopsis": "De terminal van een computer weergeven.", + "commands.computercraft.view.desc": "De terminal van een computer weergeven, voor controle op afstand. Dit biedt geen toegang tot turtle's inventarissen. Je kunt een instance-id (bijv. 123) of computer-id (bijv. #123) opgeven.", + "commands.computercraft.view.action": "Geef deze computer weer", + "commands.computercraft.view.not_player": "Kan geen terminal openen voor non-speler", + "commands.computercraft.track.synopsis": "Houd uitvoertijd van computers bij.", + "commands.computercraft.track.desc": "Houd uitvoertijd en het aantal behandelde events van computers bij. Dit biedt informatie op een gelijke manier als /forge track en kan nuttig zijn in het opsloren van lag.", + "commands.computercraft.track.start.synopsis": "Start met het bijhouden van alle computers", + "commands.computercraft.track.start.desc": "Start met het bijhouden van uitvoertijden en aantal behandelde events van alle computers. Dit gooit de resultaten van eerdere runs weg.", + "commands.computercraft.track.start.stop": "Voer %s uit om het bijhouden te stoppen en de resultaten te tonen", + "commands.computercraft.track.stop.synopsis": "Stop het bijhouden van alle computers", + "commands.computercraft.track.stop.desc": "Stop het bijhouden van uitvoertijd en aantal behandelde events van alle computers", + "commands.computercraft.track.stop.action": "Klik om bijhouden te stoppen", + "commands.computercraft.track.dump.no_timings": "Geen tijden beschikbaar", + "commands.computercraft.track.dump.computer": "Computer", + "commands.computercraft.reload.synopsis": "Herlaad het ComputerCraft configuratiebestand", + "commands.computercraft.reload.desc": "Herlaad het ComputerCraft configuratiebestand", + "commands.computercraft.reload.done": "Configuratie herladen", + "commands.computercraft.queue.synopsis": "Verzend een computer_command event naar een commandocomputer", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.yes": "J", + "commands.computercraft.generic.no": "N", + "commands.computercraft.generic.exception": "Niet-afgehandelde exception (%s)", + "commands.computercraft.generic.additional_rows": "%d additionele rijen…", + "argument.computercraft.computer.no_matching": "Geen computer matcht '%s'", + "argument.computercraft.computer.many_matching": "Meerdere computers matchen '%s' (instanties %s)", + "argument.computercraft.argument_expected": "Argument verwacht", + "tracking_field.computercraft.tasks.name": "Taken", + "tracking_field.computercraft.total.name": "Totale tijd", + "tracking_field.computercraft.average.name": "Gemiddelde tijd", + "tracking_field.computercraft.max.name": "Maximale tijd", + "tracking_field.computercraft.server_count.name": "Aantal server-taken", + "tracking_field.computercraft.server_time.name": "Server-taak tijd", + "tracking_field.computercraft.peripheral.name": "Randapparatuur aanroepen", + "tracking_field.computercraft.turtle.name": "Turtle operaties", + "tracking_field.computercraft.http.name": "HTTP verzoeken", + "tracking_field.computercraft.http_upload.name": "HTTP upload", + "tracking_field.computercraft.websocket_incoming.name": "Websocket inkomend", + "tracking_field.computercraft.websocket_outgoing.name": "Websocket uitgaand", + "tracking_field.computercraft.coroutines_created.name": "Coroutines gecreëerd", + "gui.computercraft.tooltip.copy": "Kopiëren naar klembord", + "gui.computercraft.tooltip.computer_id": "Computer ID: %s", + "gui.computercraft.tooltip.disk_id": "Diskette ID: %s", + "tracking_field.computercraft.http_download.name": "HTTP download", + "commands.computercraft.generic.no_position": "", + "commands.computercraft.track.dump.synopsis": "Dump de laatste resultaten van het bijhouden van computers", + "tracking_field.computercraft.fs.name": "Restandssysteem operaties", + "tracking_field.computercraft.coroutines_dead.name": "Coroutines verwijderd", + "argument.computercraft.tracking_field.no_field": "Onbekend veld '%s'" } diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.json b/src/main/resources/assets/computercraft/lang/zh_cn.json index c5c672e62..83b373f69 100644 --- a/src/main/resources/assets/computercraft/lang/zh_cn.json +++ b/src/main/resources/assets/computercraft/lang/zh_cn.json @@ -1,5 +1,5 @@ { - "itemGroup.computercraft": "CC: Tweaked", + "itemGroup.computercraft": "ComputerCraft", "block.computercraft.computer_normal": "计算机", "block.computercraft.computer_advanced": "高级计算机", "block.computercraft.computer_command": "命令电脑", @@ -101,7 +101,7 @@ "tracking_field.computercraft.turtle.name": "海龟æ“作", "tracking_field.computercraft.http.name": "HTTP需求", "tracking_field.computercraft.http_upload.name": "HTTP上传", - "tracking_field.computercraft.http_download.name": "HTTT下载", + "tracking_field.computercraft.http_download.name": "HTTP下载", "tracking_field.computercraft.websocket_incoming.name": "Websocketä¼ å…¥", "tracking_field.computercraft.websocket_outgoing.name": "Websocket传出", "tracking_field.computercraft.coroutines_created.name": "ååŒåˆ›å»º", From 48edcde4ef3daee708cb241e8b896714295a8596 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 19 Jun 2020 18:49:19 +0100 Subject: [PATCH 255/711] Fix handling of CC: T's version We never added back replacing of ${version} strings, which means that CC was reporting incorrect version numbers in _HOST, the user agent and network versions. This meant we would allow connections even on mismatched versions (#464). We shift all version handling into ComputerCraftAPI(Impl) - this now relies on Forge code, so we don't want to run it in emulators. --- build.gradle | 2 - .../dan200/computercraft/ComputerCraft.java | 5 -- .../computercraft/ComputerCraftAPIImpl.java | 15 +++--- .../computercraft/api/ComputerCraftAPI.java | 3 +- .../apis/http/request/HttpRequestHandler.java | 2 +- .../core/computer/IComputerEnvironment.java | 9 ++++ .../shared/computer/core/ServerComputer.java | 11 ++++- .../shared/network/NetworkHandler.java | 49 ++++++++++--------- .../peripheral/monitor/TileMonitor.java | 2 +- .../core/computer/BasicEnvironment.java | 11 ++++- 10 files changed, 66 insertions(+), 43 deletions(-) diff --git a/build.gradle b/build.gradle index 4b6864ec8..debd2965b 100644 --- a/build.gradle +++ b/build.gradle @@ -202,8 +202,6 @@ task proguardMove(dependsOn: proguard) { } } - - processResources { inputs.property "version", mod_version inputs.property "mcversion", mc_version diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 4403a2334..22c039874 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -197,11 +197,6 @@ public final class ComputerCraft Config.load(); } - public static String getVersion() - { - return "${version}"; - } - public static InputStream getResourceFile( String domain, String subPath ) { IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 1610ea5fb..28f6d4e71 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -5,7 +5,6 @@ */ package dan200.computercraft; -import com.google.common.collect.MapMaker; import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -28,17 +27,15 @@ import dan200.computercraft.shared.wired.WiredNode; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fml.ModList; import net.minecraftforge.fml.server.ServerLifecycleHooks; import javax.annotation.Nonnull; import java.io.File; -import java.lang.ref.WeakReference; -import java.util.Map; import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT; @@ -46,18 +43,20 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { public static final ComputerCraftAPIImpl INSTANCE = new ComputerCraftAPIImpl(); + private String version; + private ComputerCraftAPIImpl() { } - private WeakReference currentResources; - private final Map mountCache = new MapMaker().weakValues().concurrencyLevel( 1 ).makeMap(); - @Nonnull @Override public String getInstalledVersion() { - return "${version}"; + if( version != null ) return version; + return version = ModList.get().getModContainerById( ComputerCraft.MOD_ID ) + .map( x -> x.getModInfo().getVersion().toString() ) + .orElse( "unknown" ); } @Override diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 4eb417e8c..42fa4dcce 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -43,9 +43,10 @@ public final class ComputerCraftAPI } @Nonnull + @Deprecated public static String getAPIVersion() { - return "${version}"; + return getInstalledVersion(); } /** diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index 0f164d4f0..fac72ecfa 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -84,7 +84,7 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler version ) .clientAcceptedVersions( version::equals ).serverAcceptedVersions( version::equals ) .simpleChannel(); // Server messages - registerMainThread( 0, ComputerActionServerMessage::new ); - registerMainThread( 1, QueueEventServerMessage::new ); - registerMainThread( 2, RequestComputerMessage::new ); - registerMainThread( 3, KeyEventServerMessage::new ); - registerMainThread( 4, MouseEventServerMessage::new ); + registerMainThread( 0, NetworkDirection.PLAY_TO_SERVER, ComputerActionServerMessage::new ); + registerMainThread( 1, NetworkDirection.PLAY_TO_SERVER, QueueEventServerMessage::new ); + registerMainThread( 2, NetworkDirection.PLAY_TO_SERVER, RequestComputerMessage::new ); + registerMainThread( 3, NetworkDirection.PLAY_TO_SERVER, KeyEventServerMessage::new ); + registerMainThread( 4, NetworkDirection.PLAY_TO_SERVER, MouseEventServerMessage::new ); // Client messages - registerMainThread( 10, ChatTableClientMessage::new ); - registerMainThread( 11, ComputerDataClientMessage::new ); - registerMainThread( 12, ComputerDeletedClientMessage::new ); - registerMainThread( 13, ComputerTerminalClientMessage::new ); - registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); - registerMainThread( 15, MonitorClientMessage.class, MonitorClientMessage::new ); + registerMainThread( 10, NetworkDirection.PLAY_TO_CLIENT, ChatTableClientMessage::new ); + registerMainThread( 11, NetworkDirection.PLAY_TO_CLIENT, ComputerDataClientMessage::new ); + registerMainThread( 12, NetworkDirection.PLAY_TO_CLIENT, ComputerDeletedClientMessage::new ); + registerMainThread( 13, NetworkDirection.PLAY_TO_CLIENT, ComputerTerminalClientMessage::new ); + registerMainThread( 14, NetworkDirection.PLAY_TO_CLIENT, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); + registerMainThread( 15, NetworkDirection.PLAY_TO_CLIENT, MonitorClientMessage.class, MonitorClientMessage::new ); } public static void sendToPlayer( PlayerEntity player, NetworkMessage packet ) @@ -90,13 +91,14 @@ public final class NetworkHandler * /** * Register packet, and a thread-unsafe handler for it. * - * @param The type of the packet to send. - * @param id The identifier for this packet type - * @param factory The factory for this type of packet. + * @param The type of the packet to send. + * @param id The identifier for this packet type. + * @param direction A network direction which will be asserted before any processing of this message occurs. + * @param factory The factory for this type of packet. */ - private static void registerMainThread( int id, Supplier factory ) + private static void registerMainThread( int id, NetworkDirection direction, Supplier factory ) { - registerMainThread( id, getType( factory ), buf -> { + registerMainThread( id, direction, getType( factory ), buf -> { T instance = factory.get(); instance.fromBytes( buf ); return instance; @@ -107,14 +109,15 @@ public final class NetworkHandler * /** * Register packet, and a thread-unsafe handler for it. * - * @param The type of the packet to send. - * @param type The class of the type of packet to send. - * @param id The identifier for this packet type - * @param decoder The factory for this type of packet. + * @param The type of the packet to send. + * @param type The class of the type of packet to send. + * @param id The identifier for this packet type. + * @param direction A network direction which will be asserted before any processing of this message occurs + * @param decoder The factory for this type of packet. */ - private static void registerMainThread( int id, Class type, Function decoder ) + private static void registerMainThread( int id, NetworkDirection direction, Class type, Function decoder ) { - network.messageBuilder( type, id ) + network.messageBuilder( type, id, direction ) .encoder( NetworkMessage::toBytes ) .decoder( decoder ) .consumer( ( packet, contextSup ) -> { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 4409fe6ad..b51277910 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -11,8 +11,8 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.network.client.TerminalState; +import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.entity.player.PlayerEntity; diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index c57226bc9..ccdcc751b 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -12,6 +12,7 @@ import dan200.computercraft.core.filesystem.FileMount; import dan200.computercraft.core.filesystem.JarMount; import dan200.computercraft.core.filesystem.MemoryMount; +import javax.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -73,10 +74,18 @@ public class BasicEnvironment implements IComputerEnvironment return ComputerCraft.computerSpaceLimit; } + @Nonnull @Override public String getHostString() { - return "ComputerCraft ${version} (Test environment)"; + return "ComputerCraft 1.0 (Test environment)"; + } + + @Nonnull + @Override + public String getUserAgent() + { + return "ComputerCraft/1.0"; } @Override From 2a8efb3fd53409acf23e8610ddc024f374868267 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 21 Jun 2020 12:03:24 +0100 Subject: [PATCH 256/711] Fix crashes when rendering monitors of varying sizes When calling .flip(), we limit the size of the buffer. However, this limit is not reset when writing the next time, which means we get out-of-bounds errors, even if the buffer is /technically/ big enough. Clearing the buffer before drawing (rather than just resetting the position) is enough to fix this. Fixes #476 (and closes #477, which is a duplicate) --- gradle.properties | 2 +- .../client/render/TileEntityMonitorRenderer.java | 2 +- .../assets/computercraft/lua/rom/help/changelog.txt | 4 ++++ .../assets/computercraft/lua/rom/help/whatsnew.txt | 9 ++------- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index 3fe94fba4..f71c4f6e1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.89.0 +mod_version=1.89.1 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 7dd003152..9e4620574 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -170,7 +170,7 @@ public class TileEntityMonitorRenderer extends TileEntitySpecialRenderer Date: Sun, 21 Jun 2020 13:24:47 +0100 Subject: [PATCH 257/711] Upload on all (active) mc-* branches --- .github/workflows/make-doc.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index f1b728ad6..16a905dae 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -2,7 +2,9 @@ name: Build documentation on: push: - branches: [ master ] + branches: + - master + - mc-1.15.x tags: release: types: [ published ] From ab0310e27c385187103b05b0489a1175cf99f69a Mon Sep 17 00:00:00 2001 From: Weblate Date: Sun, 21 Jun 2020 16:42:35 +0000 Subject: [PATCH 258/711] Translations for Italian Translations for French Translations for French Co-authored-by: hds Co-authored-by: Anavrins Co-authored-by: AxelFontarive --- .../assets/computercraft/lang/fr_fr.json | 74 ++++++++++++++++++- .../assets/computercraft/lang/it_it.json | 41 ++++++---- 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/src/main/resources/assets/computercraft/lang/fr_fr.json b/src/main/resources/assets/computercraft/lang/fr_fr.json index e1e05ff7c..fdc7e4cb4 100644 --- a/src/main/resources/assets/computercraft/lang/fr_fr.json +++ b/src/main/resources/assets/computercraft/lang/fr_fr.json @@ -37,5 +37,77 @@ "upgrade.computercraft.wireless_modem_advanced.adjective": "de l'Ender", "upgrade.computercraft.speaker.adjective": "parlante", "chat.computercraft.wired_modem.peripheral_connected": "Le periphérique \"%s\" est connecté au réseau", - "chat.computercraft.wired_modem.peripheral_disconnected": "Le periphérique \"%s\" est déconnecté du réseau" + "chat.computercraft.wired_modem.peripheral_disconnected": "Le periphérique \"%s\" est déconnecté du réseau", + "commands.computercraft.help.desc": "Affiche ce message d'aide", + "itemGroup.computercraft": "ComputerCraft", + "commands.computercraft.help.no_children": "%s n'a pas de sous-commandes", + "commands.computercraft.dump.synopsis": "Affiche le statut des ordinateurs.", + "commands.computercraft.dump.action": "Visualiser plus d'informations à propos de cet ordinateur", + "commands.computercraft.shutdown.synopsis": "Éteindre des ordinateurs à distance.", + "commands.computercraft.shutdown.desc": "Éteint les ordinateurs dans la liste ou tous, si aucun n'est spécifié dans cette liste. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", + "commands.computercraft.turn_on.synopsis": "Démarre des ordinateurs à distance.", + "commands.computercraft.turn_on.done": "%s/%s ordinateurs ont été allumés", + "commands.computercraft.tp.synopsis": "Se téléporter à la position de l'ordinateur spécifié.", + "commands.computercraft.tp.desc": "Se téléporter à la position de l'ordinateur. Vous pouvez spécifier l'identifiant d'instance (ex. 123) ou l'identifiant d'ordinateur (ex. #123).", + "commands.computercraft.tp.action": "Se téléporter vers cet ordinateur", + "commands.computercraft.tp.not_player": "Impossible d'ouvrir un terminal pour un non-joueur", + "commands.computercraft.tp.not_there": "Impossible de localiser cet ordinateur dans le monde", + "commands.computercraft.view.action": "Visualiser cet ordinateur", + "commands.computercraft.view.not_player": "Impossible d'ouvrir un terminal pour un non-joueur", + "commands.computercraft.track.synopsis": "Surveille les temps d'exécution des ordinateurs.", + "commands.computercraft.track.desc": "Surveillez combien de temps prend une exécutions sur les ordinateurs, ainsi que le nombre d’événements capturés. Les informations sont affichées d'une manière similaire à la commande /forge track, utile pour diagnostiquer les sources de latence.", + "commands.computercraft.track.start.synopsis": "Démarrer la surveillance de tous les ordinateurs", + "commands.computercraft.track.start.stop": "Exécutez %s pour arrêter la surveillance et visualiser les résultats", + "commands.computercraft.track.stop.synopsis": "Arrêter la surveillance de tous les ordinateurs", + "commands.computercraft.track.stop.desc": "Arrêter la surveillance des événements et des temps d'exécution", + "commands.computercraft.track.stop.action": "Cliquez pour arrêter la surveillance", + "commands.computercraft.help.no_command": "Commande '%s' non reconnue", + "commands.computercraft.generic.no": "N", + "commands.computercraft.generic.exception": "Exception non gérée (%s)", + "gui.computercraft.tooltip.disk_id": "ID de disque : %s", + "commands.computercraft.track.stop.not_enabled": "Surveillance actuellement désactivée", + "commands.computercraft.track.dump.synopsis": "Effacer les dernières informations de surveillance", + "commands.computercraft.track.dump.desc": "Efface les derniers résultats de surveillance des ordinateurs.", + "commands.computercraft.track.dump.computer": "Ordinateur", + "commands.computercraft.reload.synopsis": "Actualiser le fichier de configuration de ComputerCraft", + "commands.computercraft.reload.desc": "Actualise le fichier de configuration de ComputerCraft", + "commands.computercraft.reload.done": "Configuration actualisée", + "commands.computercraft.queue.synopsis": "Envoyer un événement computer_command à un ordinateur de commande", + "commands.computercraft.generic.no_position": "", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.yes": "O", + "commands.computercraft.generic.additional_rows": "%d lignes supplémentaires…", + "argument.computercraft.computer.no_matching": "Pas d'ordinateurs correspondant à '%s'", + "argument.computercraft.computer.many_matching": "Plusieurs ordinateurs correspondent à '%s' (instances %s)", + "argument.computercraft.tracking_field.no_field": "Champ '%s' inconnu", + "argument.computercraft.argument_expected": "Argument attendu", + "tracking_field.computercraft.tasks.name": "Tâches", + "tracking_field.computercraft.total.name": "Temps total", + "tracking_field.computercraft.average.name": "Temps moyen", + "tracking_field.computercraft.max.name": "Temps maximal", + "tracking_field.computercraft.server_count.name": "Nombre de tâches serveur", + "tracking_field.computercraft.server_time.name": "Temps de la tâche serveur", + "tracking_field.computercraft.peripheral.name": "Appels aux périphériques", + "tracking_field.computercraft.fs.name": "Opérations sur le système de fichiers", + "tracking_field.computercraft.turtle.name": "Opérations sur les tortues", + "tracking_field.computercraft.http.name": "Requêtes HTTP", + "tracking_field.computercraft.websocket_incoming.name": "Websocket entrant", + "tracking_field.computercraft.websocket_outgoing.name": "Websocket sortant", + "tracking_field.computercraft.coroutines_created.name": "Coroutines créées", + "tracking_field.computercraft.coroutines_dead.name": "Coroutines mortes", + "gui.computercraft.tooltip.copy": "Copier dans le Presse-Papiers", + "gui.computercraft.tooltip.computer_id": "ID d'ordinateur : %s", + "commands.computercraft.track.dump.no_timings": "Temps non disponibles", + "tracking_field.computercraft.http_upload.name": "Publication HTTP", + "commands.computercraft.desc": "La commande /computercraft fournit des outils d'administration et de débogage variés pour contrôler et interagir avec les ordinateurs.", + "commands.computercraft.dump.desc": "Affiche les statuts de tous les ordinateurs, ou des information spécifiques sur un ordinateur. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", + "commands.computercraft.turn_on.desc": "Démarre les ordinateurs dans la liste. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", + "commands.computercraft.view.synopsis": "Visualiser le terminal de cet ordinateur.", + "commands.computercraft.view.desc": "Ouvre le terminal d'un ordinateur, autorisant le contrôle à distance. Ceci ne permet pas d'accéder à l'inventaire des tortues. Vous pouvez spécifier l'identifiant d'instance (ex. 123) ou l'identifiant d'ordinateur (ex. #123).", + "commands.computercraft.track.start.desc": "Démarre la surveillance de tous les temps d'exécution et du nombre d'événements gérés. Ceci effacera les résultats de la dernière exécution.", + "commands.computercraft.queue.desc": "Envoie un événement computer_command à un ordinateur de commande, en passant les éventuels arguments additionnels. Ceci est principalement conçu pour les map makers, imitant la commande /trigger, pour une utilisation avec les ordinateurs. N'importe quel joueur peut exécuter cette commande, qui sera exécutée le plus souvent avec un événement de clic sur du texte.", + "commands.computercraft.help.synopsis": "Fournit de l'aide pour une commande spécifique", + "tracking_field.computercraft.http_download.name": "Téléchargement HTTP", + "commands.computercraft.synopsis": "Diverses commandes pour contrôler les ordinateurs.", + "commands.computercraft.shutdown.done": "%s/%s ordinateurs arrêté" } diff --git a/src/main/resources/assets/computercraft/lang/it_it.json b/src/main/resources/assets/computercraft/lang/it_it.json index ef5c67d68..765604081 100644 --- a/src/main/resources/assets/computercraft/lang/it_it.json +++ b/src/main/resources/assets/computercraft/lang/it_it.json @@ -2,8 +2,8 @@ "itemGroup.computercraft": "ComputerCraft", "block.computercraft.computer_normal": "Computer", "block.computercraft.computer_advanced": "Computer Avanzato", - "block.computercraft.computer_command": "Computer Commando", - "block.computercraft.disk_drive": "Lettore disco", + "block.computercraft.computer_command": "Computer Comando", + "block.computercraft.disk_drive": "Lettore Di Dischi", "block.computercraft.printer": "Stampante", "block.computercraft.speaker": "Altoparlante", "block.computercraft.monitor_normal": "Monitor", @@ -12,7 +12,7 @@ "block.computercraft.wireless_modem_advanced": "Modem di Ender", "block.computercraft.wired_modem": "Modem Cablato", "block.computercraft.cable": "Cavo Di Rete", - "block.computercraft.wired_modem_full": "Modem cablato", + "block.computercraft.wired_modem_full": "Modem Cablato", "block.computercraft.turtle_normal": "Tartaruga", "block.computercraft.turtle_normal.upgraded": "Tartaruga %s", "block.computercraft.turtle_normal.upgraded_twice": "Tartaruga %s %s", @@ -33,12 +33,12 @@ "upgrade.minecraft.diamond_pickaxe.adjective": "Minatrice", "upgrade.minecraft.diamond_axe.adjective": "Taglialegna", "upgrade.minecraft.diamond_hoe.adjective": "Contadina", - "upgrade.minecraft.crafting_table.adjective": "Artigiano", + "upgrade.minecraft.crafting_table.adjective": "Artigiana", "upgrade.computercraft.wireless_modem_normal.adjective": "Wireless", "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", - "upgrade.computercraft.speaker.adjective": "Rumoroso", + "upgrade.computercraft.speaker.adjective": "Che Produce Rumori", "chat.computercraft.wired_modem.peripheral_connected": "Periferica \"%s\" connessa alla rete", - "chat.computercraft.wired_modem.peripheral_disconnected": "Periferica \"%s\" disconessa dalla rete", + "chat.computercraft.wired_modem.peripheral_disconnected": "Periferica \"%s\" disconnessa dalla rete", "commands.computercraft.synopsis": "Vari comandi per controllare i computer.", "commands.computercraft.desc": "Il comando /computercraft dà accesso a vari strumenti di debug e amministrazione per controllare e interagire con i computer.", "commands.computercraft.help.synopsis": "Dà aiuto su un determinato comando", @@ -57,30 +57,30 @@ "commands.computercraft.tp.synopsis": "Teletrasporta al computer specificato.", "commands.computercraft.tp.desc": "Teletrasporta alla posizione di un computer. Puoi specificare il computer con l'instance id (e.g. 123) o con l'id (e.g. #123).", "commands.computercraft.tp.action": "Teletrasporta a questo computer", - "commands.computercraft.tp.not_player": "Puoi aprire un terminale solo per un giocatore", + "commands.computercraft.tp.not_player": "Non è possibile aprire un terminale per un non giocatore", "commands.computercraft.tp.not_there": "Impossibile trovare il computer nel mondo", "commands.computercraft.view.synopsis": "Mostra il terminale di un computer.", "commands.computercraft.view.desc": "Apre il terminale di un computer, in modo da poterlo controllare da remoto. Non permette l'accesso all'inventario di una tartaruga. Puoi specificare l'instance id del computer (e.g. 123) o l'id (e.g. #123).", "commands.computercraft.view.action": "Mostra questo computer", - "commands.computercraft.view.not_player": "Il terminale può essere aperto solo da un giocatore", - "commands.computercraft.track.synopsis": "Registra il tempo di esecuzione di tutti i computer.", - "commands.computercraft.track.desc": "Registra per quanto tempo i computer vengono eseguiti e quanti eventi ricevono. Questo comando fornisce le informazioni in modo simile a /forge track e può essere utile per monitorare il lag.", + "commands.computercraft.view.not_player": "Non è possibile aprire un terminale per un non giocatore", + "commands.computercraft.track.synopsis": "Monitora il tempo di esecuzione di tutti i computer.", + "commands.computercraft.track.desc": "Monitora per quanto tempo i computer vengono eseguiti e quanti eventi ricevono. Questo comando fornisce le informazioni in modo simile a /forge track e può essere utile per diagnosticare il lag.", "commands.computercraft.track.start.synopsis": "Inizia a monitorare tutti i computer", "commands.computercraft.track.start.desc": "Inizia a monitorare tutti i tempi di esecuzione e il numero di eventi dei computer. Questo comando cancellerà i risultati precedenti.", "commands.computercraft.track.start.stop": "Esegui %s per smettere di monitorare e mostrare i risultati", "commands.computercraft.track.stop.synopsis": "Smetti di monitorare tutti i computer", "commands.computercraft.track.stop.desc": "Smetti di monitorare tutti gli eventi e i tempi di esecuzione dei computer", "commands.computercraft.track.stop.action": "Premi per smettere di monitorare", - "commands.computercraft.track.stop.not_enabled": "Non stanno venendo monitorati computer", + "commands.computercraft.track.stop.not_enabled": "In questo momento non stanno venendo monitorati computer", "commands.computercraft.track.dump.synopsis": "Cancella gli ultimi risultati monitorati", "commands.computercraft.track.dump.desc": "Cancella gli ultimi risultati del monitoraggio dei computer.", - "commands.computercraft.track.dump.no_timings": "No tempi disponibili", + "commands.computercraft.track.dump.no_timings": "No ci sono tempi disponibili", "commands.computercraft.track.dump.computer": "Computer", "commands.computercraft.reload.synopsis": "Ricarica il file di configurazione della ComputerCraft", "commands.computercraft.reload.desc": "Ricarica il file di configurazione della ComputerCraft", "commands.computercraft.reload.done": "File di configurazione ricaricato", - "commands.computercraft.queue.synopsis": "Invia un evento computer_command ad un computer dei comandi", - "commands.computercraft.queue.desc": "Invia un evento computer_command ad un computer dei comandi, passando gli argomenti aggiuntivi. Questo comando è pensato per i map makers, è un versione più amichevole verso i computer di /trigger. Qualsiasi giocatore può eseguire il comando, è più probabile che venga fatto attraverso un evento click di un componente di testo.", + "commands.computercraft.queue.synopsis": "Invia un evento computer_command ad un computer comando", + "commands.computercraft.queue.desc": "Invia un evento computer_command ad un computer comando, passando gli argomenti aggiuntivi. Questo comando è pensato per i map makers, è un versione più amichevole verso i computer di /trigger. Qualsiasi giocatore può eseguire il comando, è più probabile che venga fatto attraverso un evento click di un componente di testo.", "commands.computercraft.generic.no_position": "", "commands.computercraft.generic.position": "%s, %s, %s", "commands.computercraft.generic.yes": "S", @@ -98,5 +98,16 @@ "tracking_field.computercraft.coroutines_created.name": "Coroutine create", "gui.computercraft.tooltip.copy": "Copia negli appunti", "gui.computercraft.tooltip.computer_id": "ID Computer: %s", - "gui.computercraft.tooltip.disk_id": "ID Disco: %s" + "gui.computercraft.tooltip.disk_id": "ID Disco: %s", + "commands.computercraft.generic.exception": "Eccezione non gestita (%s)", + "argument.computercraft.computer.many_matching": "Molteplici computer che combaciano con '%s' (istanze %s)", + "argument.computercraft.tracking_field.no_field": "Campo sconosciuto '%s'", + "argument.computercraft.argument_expected": "È previsto un argomento", + "tracking_field.computercraft.tasks.name": "Compiti", + "tracking_field.computercraft.total.name": "Tempo totale", + "tracking_field.computercraft.server_count.name": "Numero di compiti del server", + "tracking_field.computercraft.server_time.name": "Tempo di compito del server", + "tracking_field.computercraft.websocket_incoming.name": "Websocket in arrivo", + "tracking_field.computercraft.websocket_outgoing.name": "Websocket in uscita", + "tracking_field.computercraft.coroutines_dead.name": "Coroutine cancellate" } From 5bd8d84d14ff7d837e92e15d9b271e989947006a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 22 Jun 2020 11:35:21 +0100 Subject: [PATCH 259/711] Add missing config option for command computers Fixes #479 --- src/main/java/dan200/computercraft/shared/Config.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index a93805b15..567f2dba3 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -45,6 +45,7 @@ public final class Config private static final ConfigValue defaultComputerSettings; private static final ConfigValue debugEnabled; private static final ConfigValue logComputerErrors; + private static final ConfigValue commandRequireCreative; private static final ConfigValue computerThreads; private static final ConfigValue maxMainGlobalTime; @@ -118,6 +119,11 @@ public final class Config .comment( "Log exceptions thrown by peripherals and other Lua objects.\n" + "This makes it easier for mod authors to debug problems, but may result in log spam should people use buggy methods." ) .define( "log_computer_errors", ComputerCraft.logComputerErrors ); + + commandRequireCreative = builder + .comment( "Require players to be in creative mode and be opped in order to interact with command computers." + + "This is the default behaviour for vanilla's Command blocks." ) + .define( "command_require_creative", ComputerCraft.commandRequireCreative ); } { @@ -281,6 +287,7 @@ public final class Config ComputerCraft.debugEnable = debugEnabled.get(); ComputerCraft.computerThreads = computerThreads.get(); ComputerCraft.logComputerErrors = logComputerErrors.get(); + ComputerCraft.commandRequireCreative = commandRequireCreative.get(); // Execution ComputerCraft.computerThreads = computerThreads.get(); From c5138c535c080ee9c1513f816f6b996ae35f45f6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 23 Jun 2020 10:00:46 +0100 Subject: [PATCH 260/711] Fix write method missing from printers I'm really not very good at this modding lark am I? I've done a basic search for other missing methods, and can't see anything, but goodness knows. Fixes #480 --- .../shared/peripheral/printer/PrinterPeripheral.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index ee83959d4..cada0513d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.peripheral.printer; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; @@ -36,9 +37,10 @@ public class PrinterPeripheral implements IPeripheral // FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be // persisted correctly. - public final void write( Object[] args ) throws LuaException + @LuaFunction + public final void write( IArguments arguments ) throws LuaException { - String text = args.length > 0 && args[0] != null ? args[0].toString() : ""; + String text = StringUtil.toString( arguments.get( 0 ) ); Terminal page = getCurrentPage(); page.write( text ); page.setCursorPos( page.getCursorX() + text.length(), page.getCursorY() ); From 9499654757c747d10664cf2d919e2a0f63319020 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 24 Jun 2020 12:10:54 +0100 Subject: [PATCH 261/711] Add documentation for peripherals No clue how we're going to do this for the dynamic peripheral system if/when that ships, but this is a good first stage. Like the Java APIs, this relies on stub files, so we can't link to the implementation which is a bit of a shame. However, it's a good first step. --- doc/stub/computer.lua | 27 +++++++ doc/stub/drive.lua | 12 +++ doc/stub/modem.lua | 73 +++++++++++++++++++ doc/stub/monitor.lua | 32 ++++++++ doc/stub/printer.lua | 11 +++ doc/styles.css | 7 +- illuaminate.sexp | 11 ++- .../computercraft/lua/rom/apis/peripheral.lua | 4 +- .../computercraft/lua/rom/apis/textutils.lua | 2 +- 9 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 doc/stub/computer.lua create mode 100644 doc/stub/drive.lua create mode 100644 doc/stub/modem.lua create mode 100644 doc/stub/monitor.lua create mode 100644 doc/stub/printer.lua diff --git a/doc/stub/computer.lua b/doc/stub/computer.lua new file mode 100644 index 000000000..421fae547 --- /dev/null +++ b/doc/stub/computer.lua @@ -0,0 +1,27 @@ +--- A computer or turtle wrapped as a peripheral. +-- +-- This allows for basic interaction with adjacent computers. Computers wrapped +-- as peripherals will have the type `computer` while turtles will be `turtle`. +-- +-- @module[kind=peripheral] computer + +function turnOn() end --- Turn the other computer on. +function shutdown() end --- Shutdown the other computer. +function reboot() end --- Reboot or turn on the other computer. + +--- Get the other computer's ID. +-- +-- @treturn number The computer's ID. +-- @see os.getComputerID To get your computer ID. +function getID() end + +--- Determine if the other computer is on. +-- +-- @treturn boolean If the computer is on. +function isOn() end + +--- Get the other computer's label. +-- +-- @treturn string|nil The computer's label. +-- @see os.getComputerLabel To get your label. +function getLabel() end diff --git a/doc/stub/drive.lua b/doc/stub/drive.lua new file mode 100644 index 000000000..f9c5ac469 --- /dev/null +++ b/doc/stub/drive.lua @@ -0,0 +1,12 @@ +--- @module[kind=peripheral] drive + +function isDiskPresent() end +function getDiskLabel() end +function setDiskLabel(label) end +function hasData() end +function getMountPath() end +function hasAudio() end +function getAudioTitle() end +function playAudio() end +function ejectDisk() end +function getDiskID() end diff --git a/doc/stub/modem.lua b/doc/stub/modem.lua new file mode 100644 index 000000000..874568c51 --- /dev/null +++ b/doc/stub/modem.lua @@ -0,0 +1,73 @@ +--- @module[kind=peripheral] modem + +function open(channel) end +function isOpen(channel) end +function close(channel) end + +--- Close all open channels. +function closeAll() end + +function transmit(channel, replyChannel, payload) end + +--- Determine if this is a wired or wireless modem. +-- +-- Some methods (namely those dealing with wired networks and remote +-- peripherals) are only available on wired modems. +-- +-- @treturn boolean @{true} if this is a wireless modem. +function isWireless() end + +-- Wired modem only + +--- List all remote peripherals on the wired network. +-- +-- If this computer is attached to the network, it _will not_ be included in +-- this list. +-- +-- > **Important:** This function only appears on wired modems. Check +-- > @{isWireless} returns false before calling it. +-- +-- @treturn { string... } Remote peripheral names on the network. +function getNamesRemote(name) end + +--- Determine if a peripheral is available on this wired network. +-- +-- > **Important:** This function only appears on wired modems. Check +-- > @{isWireless} returns false before calling it. +-- +-- @tparam string name The peripheral's name. +-- @treturn boolean If a peripheral is present with the given name. +-- @see peripheral.isPresent +function isPresentRemote(name) end + +--- Get the type of a peripheral is available on this wired network. +-- +-- > **Important:** This function only appears on wired modems. Check +-- > @{isWireless} returns false before calling it. +-- +-- @tparam string name The peripheral's name. +-- @treturn string|nil The peripheral's type, or `nil` if it is not present. +-- @see peripheral.getType +function getTypeRemote(name) end + +--- Call a method on a peripheral on this wired network. +-- +-- > **Important:** This function only appears on wired modems. Check +-- > @{isWireless} returns false before calling it. +-- +-- @tparam string remoteName The name of the peripheral to invoke the method on. +-- @tparam string method The name of the method +-- @param ... Additional arguments to pass to the method +-- @return The return values of the peripheral method. +-- @see peripheral.call +function callRemote(remoteName, method, ...) end + +--- Returns the network name of the current computer, if the modem is on. This +-- may be used by other computers on the network to wrap this computer as a +-- peripheral. +-- +-- > **Important:** This function only appears on wired modems. Check +-- > @{isWireless} returns false before calling it. +-- +-- @treturn string|nil The current computer's name on the wired network. +function getNameLocal() end diff --git a/doc/stub/monitor.lua b/doc/stub/monitor.lua new file mode 100644 index 000000000..cea79560d --- /dev/null +++ b/doc/stub/monitor.lua @@ -0,0 +1,32 @@ +--[[- Monitors are a block which act as a terminal, displaying information on +one side. This allows them to be read and interacted with in-world without +opening a GUI. + +Monitors act as @{term.Redirect|terminal redirects} and so expose the same +methods, as well as several additional ones, which are documented below. + +Like computers, monitors come in both normal (no colour) and advanced (colour) +varieties. + +@module[kind=peripheral] monitor +@usage Write "Hello, world!" to an adjacent monitor: + + local monitor = peripheral.find("monitor") + monitor.setCursorPos(1, 1) + monitor.write("Hello, world!") +]] + + +--- Set the scale of this monitor. A larger scale will result in the monitor +-- having a lower resolution, but display text much larger. +-- +-- @tparam number scale The monitor's scale. This must be a multiple of 0.5 +-- between 0.5 and 5. +-- @throws If the scale is out of range. +-- @see getTextScale +function setTextScale(scale) end + +--- Get the monitor's current text scale. +-- +-- @treturn number The monitor's current scale. +function getTextScale() end diff --git a/doc/stub/printer.lua b/doc/stub/printer.lua new file mode 100644 index 000000000..674aab13a --- /dev/null +++ b/doc/stub/printer.lua @@ -0,0 +1,11 @@ +--- @module[kind=peripheral] printer + +function write(text) end +function getCursorPos() end +function setCursorPos(x, y) end +function getPageSize() end +function newPage() end +function endPage() end +function setPageTitle(title) end +function getInkLevel() end +function getPaperLevel() end diff --git a/doc/styles.css b/doc/styles.css index 436a8c535..2bcc830cc 100644 --- a/doc/styles.css +++ b/doc/styles.css @@ -51,7 +51,12 @@ h4 { font-size: 1.06em; } a, a:visited, a:active { font-weight: bold; color: #004080; text-decoration: none; } a:hover { text-decoration: underline; } -blockquote { margin-left: 3em; } +blockquote { + padding: 0.3em; + margin: 1em 0; + background: #f0f0f0; + border-left: solid 0.5em #ccc; +} /* Stop sublists from having initial vertical space */ ul ul { margin-top: 0px; } diff --git a/illuaminate.sexp b/illuaminate.sexp index 769eba175..75e011de6 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -12,6 +12,9 @@ (index doc/index.md) (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) + (module-kinds + (peripheral Peripherals)) + (library-path /doc/stub/ @@ -70,11 +73,17 @@ ;; Suppress warnings for currently undocumented modules. (at - (/doc/stub/fs.lua + (; Java APIs + /doc/stub/fs.lua /doc/stub/http.lua /doc/stub/os.lua /doc/stub/term.lua /doc/stub/turtle.lua + ; Peripherals + /doc/stub/drive.lua + /doc/stub/modem.lua + /doc/stub/printer.lua + ; Lua APIs /src/main/resources/*/computercraft/lua/rom/apis/io.lua /src/main/resources/*/computercraft/lua/rom/apis/window.lua) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua index c737a915a..d8be09ad3 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua @@ -23,7 +23,7 @@ local sides = rs.getSides() -- listed as the side it is attached to. If a device is attached via a Wired -- Modem, then it'll be reported according to its name on the wired network. -- --- @treturn table A list of the names of all attached peripherals. +-- @treturn { string... } A list of the names of all attached peripherals. function getNames() local results = {} for n = 1, #sides do @@ -96,7 +96,7 @@ end --- Get all available methods for the peripheral with the given name. -- -- @tparam string name The name of the peripheral to find. --- @treturn table|nil A list of methods provided by this peripheral, or `nil` if +-- @treturn { string... }|nil A list of methods provided by this peripheral, or `nil` if -- it is not present. function getMethods(name) expect(1, name, "string") diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index d087c570c..0e96a287d 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -1,4 +1,4 @@ ---- The `textutils` API provides helpful utilities for formatting and +--- The @{textutils} API provides helpful utilities for formatting and -- manipulating strings. -- -- @module textutils From b54519d0e67218218a96749b83f8ae32182a9cd1 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Thu, 25 Jun 2020 10:08:35 +0200 Subject: [PATCH 262/711] Add functions for parsing and drawing nft (#458) --- .../lua/rom/modules/main/cc/image/nft.lua | 107 ++++++++++++++++++ .../spec/modules/cc/image/nft_spec.lua | 91 +++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua create mode 100644 src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua new file mode 100644 index 000000000..225abb6f7 --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua @@ -0,0 +1,107 @@ +--- Provides utilities for working with "nft" images. +-- +-- nft ("Nitrogen Fingers Text") is a file format for drawing basic images. +-- Unlike the images that @{paintutils.parseImage} uses, nft supports coloured +-- text. +-- +-- @module cc.image.nft +-- @usage Load an image from `example.nft` and draw it. +-- +-- local nft = require "cc.image.nft" +-- local image = assert(nft.load("example.nft")) +-- nft.draw(image) + +local expect = require "cc.expect".expect + +--- Parse an nft image from a string. +-- +-- @tparam string image The image contents. +-- @return table The parsed image. +local function parse(image) + expect(1, image, "string") + + local result = {} + local line = 1 + local foreground = "0" + local background = "f" + + local i, len = 1, #image + while i <= len do + local c = image:sub(i, i) + if c == "\31" and i < len then + i = i + 1 + foreground = image:sub(i, i) + elseif c == "\30" and i < len then + i = i + 1 + background = image:sub(i, i) + elseif c == "\n" then + if result[line] == nil then + result[line] = { text = "", foreground = "", background = "" } + end + + line = line + 1 + else + local next = image:find("[\n\30\31]", i) or #image + 1 + local seg_len = next - i + + local this_line = result[line] + if this_line == nil then + this_line = { foreground = "", background = "", text = "" } + result[line] = this_line + end + + this_line.text = this_line.text .. image:sub(i, next - 1) + this_line.foreground = this_line.foreground .. foreground:rep(seg_len) + this_line.background = this_line.background .. background:rep(seg_len) + + i = next - 1 + end + + i = i + 1 + end + return result +end + +--- Load an nft image from a file. +-- +-- @tparam string path The file to load. +-- @treturn[1] table The parsed image. +-- @treturn[2] nil If the file does not exist or could not be loaded. +-- @treturn[2] string An error message explaining why the file could not be +-- loaded. +local function load(path) + expect(1, path, "string") + local file, err = io.open(path, "r") + if not file then return nil, err end + + local result = file:read("*a") + file:close() + return parse(result) +end + +--- Draw an nft image to the screen. +-- +-- @tparam table image An image, as returned from @{load} or @{draw}. +-- @tparam number xPos The x position to start drawing at. +-- @tparam number xPos The y position to start drawing at. +-- @tparam[opt] term.Redirect target The terminal redirect to draw to. Defaults to the +-- current terminal. +local function draw(image, xPos, yPos, target) + expect(1, image, "table") + expect(2, xPos, "number") + expect(3, yPos, "number") + expect(4, target, "table", "nil") + + if not target then target = term end + + for y, line in ipairs(image) do + target.setCursorPos(xPos, yPos + y - 1) + target.blit(line.text, line.foreground, line.background) + end +end + +return { + parse = parse, + load = load, + draw = draw, +} diff --git a/src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua b/src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua new file mode 100644 index 000000000..f67c40898 --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/image/nft_spec.lua @@ -0,0 +1,91 @@ +local helpers = require "test_helpers" + +describe("cc.image.nft", function() + local nft = require("cc.image.nft") + + describe("parse", function() + it("validates arguments", function() + nft.parse("") + expect.error(nft.parse, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("parses an empty string", function() + expect(nft.parse("")):same {} + end) + + it("parses a string with no colours", function() + expect(nft.parse("Hello")):same { { text = "Hello", foreground = "00000", background = "fffff" } } + end) + + it("handles background and foreground colours", function() + expect(nft.parse("\30a\31bHello")) + :same { { text = "Hello", foreground = "bbbbb", background = "aaaaa" } } + end) + + it("parses multi-line files", function() + expect(nft.parse("Hello\nWorld")):same { + { text = "Hello", foreground = "00000", background = "fffff" }, + { text = "World", foreground = "00000", background = "fffff" }, + } + end) + + it("handles empty lines", function() + expect(nft.parse("\n\n")):same { + { text = "", foreground = "", background = "" }, + { text = "", foreground = "", background = "" }, + } + end) + end) + + describe("load", function() + it("validates arguments", function() + nft.load("") + expect.error(nft.load, nil):eq("bad argument #1 (expected string, got nil)") + end) + + it("loads from a file", function() + local image = fs.open("/test-files/example.nft", "w") + image.write("\30aHello, world!") + image.close() + + expect(nft.load("/test-files/example.nft")):same { + { background = "aaaaaaaaaaaaa", foreground = "0000000000000", text = "Hello, world!" }, + } + end) + + it("fails on missing files", function() + expect({ nft.load("/test-files/not_a_file.nft") }) + :same { nil, "/test-files/not_a_file.nft: No such file" } + end) + end) + + describe("draw", function() + it("validates arguments", function() + expect.error(nft.draw, nil):eq("bad argument #1 (expected table, got nil)") + expect.error(nft.draw, {}, nil):eq("bad argument #2 (expected number, got nil)") + expect.error(nft.draw, {}, 1, nil):eq("bad argument #3 (expected number, got nil)") + expect.error(nft.draw, {}, 1, 1, false):eq("bad argument #4 (expected table, got boolean)") + end) + + it("draws an image", function() + local win = helpers.with_window(7, 3, function() + nft.draw({ + { background = "aaaaa", foreground = "f000f", text = "Hello" }, + }, 2, 2) + end) + + expect(win.getLine(1)):eq(" ") + expect({ win.getLine(2) }):same { " Hello ", "0f000f0", "faaaaaf" } + expect(win.getLine(3)):eq(" ") + end) + + it("draws an image to a custom redirect", function() + local win = window.create(term.current(), 1, 1, 5, 1, false) + nft.draw({ + { background = "aaaaa", foreground = "f000f", text = "Hello" }, + }, 1, 1, win) + + expect({ win.getLine(1) }):same { "Hello", "f000f", "aaaaa" } + end) + end) +end) From 478f992dea780f7797d1573558f7f7082906e9d3 Mon Sep 17 00:00:00 2001 From: Weblate Date: Thu, 25 Jun 2020 16:49:08 +0000 Subject: [PATCH 263/711] Translations for German Co-authored-by: Jummit --- src/main/resources/assets/computercraft/lang/de_de.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lang/de_de.json b/src/main/resources/assets/computercraft/lang/de_de.json index 20e56e205..ec266f4cd 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.json +++ b/src/main/resources/assets/computercraft/lang/de_de.json @@ -107,5 +107,7 @@ "tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht", "gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren", "gui.computercraft.tooltip.computer_id": "Computer ID: %s", - "gui.computercraft.tooltip.disk_id": "Disketten ID: %s" + "gui.computercraft.tooltip.disk_id": "Disketten ID: %s", + "argument.computercraft.argument_expected": "Parameter erwartet", + "commands.computercraft.help.desc": "Zeigt diese Hilfe" } From e4c422d6f984aaf159e1a85e42c17f7aba2a5556 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sat, 27 Jun 2020 01:59:35 +0000 Subject: [PATCH 264/711] Translations for German Co-authored-by: Jummit --- src/main/resources/assets/computercraft/lang/de_de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lang/de_de.json b/src/main/resources/assets/computercraft/lang/de_de.json index ec266f4cd..b9ea46bed 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.json +++ b/src/main/resources/assets/computercraft/lang/de_de.json @@ -33,7 +33,7 @@ "upgrade.minecraft.diamond_pickaxe.adjective": "Bergbau", "upgrade.minecraft.diamond_axe.adjective": "Holzfällen", "upgrade.minecraft.diamond_hoe.adjective": "Ackerbau", - "upgrade.minecraft.crafting_table.adjective": "Fabrizierung", + "upgrade.minecraft.crafting_table.adjective": "Handwerk", "upgrade.computercraft.wireless_modem_normal.adjective": "Ender", "upgrade.computercraft.wireless_modem_advanced.adjective": "Kabellos", "upgrade.computercraft.speaker.adjective": "Laut", From 613a28a5af7177c1f67ca0acf33afbb5ff297349 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 27 Jun 2020 10:23:45 +0100 Subject: [PATCH 265/711] Switch to Forge's DeferredRegister Well, mostly. We currently don't do recipe serializers as I'm a little too lazy. For items, blocks and TE types this does make registration nicer - we've some helper functions which help reduce duplication. Some types (containers, TEs, etc..) are a little less nice, as we now must define the registry object (i.e. the WhateverType) in a separate class to the class it constructs. However, it's probably a worthwhile price to pay. --- .../dan200/computercraft/ComputerCraft.java | 67 +-- .../api/pocket/AbstractPocketUpgrade.java | 64 ++- .../api/turtle/AbstractTurtleUpgrade.java | 69 +++- .../computercraft/client/ClientRegistry.java | 11 +- .../proxy/ComputerCraftProxyClient.java | 40 +- .../client/render/CableHighlightRenderer.java | 3 +- .../dan200/computercraft/data/LootTables.java | 32 +- .../dan200/computercraft/data/Recipes.java | 45 +- .../java/dan200/computercraft/data/Tags.java | 15 +- .../dan200/computercraft/shared/Config.java | 2 +- .../dan200/computercraft/shared/Registry.java | 387 +++++++++--------- .../shared/common/BlockGeneric.java | 9 +- .../shared/common/ContainerHeldItem.java | 8 +- .../shared/computer/blocks/BlockComputer.java | 5 +- .../computer/blocks/BlockComputerBase.java | 19 +- .../computer/blocks/TileCommandComputer.java | 7 - .../shared/computer/blocks/TileComputer.java | 12 - .../computer/blocks/TileComputerBase.java | 4 +- .../computer/inventory/ContainerComputer.java | 11 +- .../inventory/ContainerComputerBase.java | 2 +- .../inventory/ContainerViewComputer.java | 9 +- .../computer/items/ComputerItemFactory.java | 8 +- .../integration/jei/JEIComputerCraft.java | 11 +- .../shared/media/items/ItemDisk.java | 7 +- .../shared/media/items/ItemPrintout.java | 14 +- .../shared/media/items/ItemTreasureDisk.java | 6 +- .../peripheral/diskdrive/BlockDiskDrive.java | 7 +- .../diskdrive/ContainerDiskDrive.java | 10 +- .../peripheral/diskdrive/TileDiskDrive.java | 20 +- .../peripheral/modem/wired/BlockCable.java | 28 +- .../modem/wired/BlockWiredModemFull.java | 3 +- .../modem/wired/ItemBlockCable.java | 8 +- .../peripheral/modem/wired/TileCable.java | 20 +- .../modem/wired/TileWiredModemFull.java | 17 +- .../wired/WiredModemLocalPeripheral.java | 4 +- .../modem/wireless/BlockWirelessModem.java | 11 +- .../modem/wireless/TileWirelessModem.java | 13 - .../peripheral/monitor/BlockMonitor.java | 9 +- .../peripheral/monitor/TileMonitor.java | 14 +- .../peripheral/printer/BlockPrinter.java | 7 +- .../peripheral/printer/ContainerPrinter.java | 10 +- .../peripheral/printer/TilePrinter.java | 15 +- .../peripheral/speaker/BlockSpeaker.java | 3 +- .../peripheral/speaker/TileSpeaker.java | 13 +- .../inventory/ContainerPocketComputer.java | 12 +- .../pocket/items/ItemPocketComputer.java | 4 +- .../items/PocketComputerItemFactory.java | 6 +- .../pocket/peripherals/PocketModem.java | 6 +- .../pocket/peripherals/PocketSpeaker.java | 4 +- .../shared/turtle/blocks/BlockTurtle.java | 15 +- .../shared/turtle/blocks/TileTurtle.java | 14 +- .../shared/turtle/core/TurtlePlayer.java | 28 +- .../turtle/inventory/ContainerTurtle.java | 11 +- .../turtle/items/TurtleItemFactory.java | 6 +- .../upgrades/TurtleInventoryCrafting.java | 2 +- .../shared/turtle/upgrades/TurtleModem.java | 8 +- .../shared/turtle/upgrades/TurtleSpeaker.java | 4 +- .../shared/util/CreativeTabMain.java | 3 +- .../shared/util/FakeNetHandler.java | 64 +-- .../shared/util/FixedPointTileEntityType.java | 60 +++ .../shared/util/ImpostorRecipe.java | 2 +- .../shared/util/ImpostorShapelessRecipe.java | 4 +- .../shared/util/InventoryDelegate.java | 2 +- .../shared/util/NamedTileEntityType.java | 75 ---- .../shared/util/ValidatingSlot.java | 4 +- .../computercraft/shared/util/WorldUtil.java | 2 +- 66 files changed, 670 insertions(+), 745 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java delete mode 100644 src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 22c039874..f5e540126 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -9,27 +9,12 @@ import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRule; import dan200.computercraft.shared.Config; -import dan200.computercraft.shared.computer.blocks.BlockComputer; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; import dan200.computercraft.shared.computer.core.ServerComputerRegistry; -import dan200.computercraft.shared.computer.items.ItemComputer; -import dan200.computercraft.shared.media.items.ItemDisk; -import dan200.computercraft.shared.media.items.ItemPrintout; -import dan200.computercraft.shared.media.items.ItemTreasureDisk; -import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; -import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; -import dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull; -import dan200.computercraft.shared.peripheral.modem.wired.ItemBlockCable; -import dan200.computercraft.shared.peripheral.modem.wireless.BlockWirelessModem; -import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; -import dan200.computercraft.shared.peripheral.printer.BlockPrinter; -import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker; -import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; -import dan200.computercraft.shared.turtle.blocks.BlockTurtle; -import dan200.computercraft.shared.turtle.items.ItemTurtle; import dan200.computercraft.shared.turtle.upgrades.*; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.util.ResourceLocation; @@ -117,53 +102,6 @@ public final class ComputerCraft public static final int terminalWidth_pocketComputer = 26; public static final int terminalHeight_pocketComputer = 20; - // Blocks and Items - public static final class Blocks - { - public static BlockComputer computerNormal; - public static BlockComputer computerAdvanced; - public static BlockComputer computerCommand; - - public static BlockTurtle turtleNormal; - public static BlockTurtle turtleAdvanced; - - public static BlockSpeaker speaker; - public static BlockDiskDrive diskDrive; - public static BlockPrinter printer; - - public static BlockMonitor monitorNormal; - public static BlockMonitor monitorAdvanced; - - public static BlockWirelessModem wirelessModemNormal; - public static BlockWirelessModem wirelessModemAdvanced; - - public static BlockWiredModemFull wiredModemFull; - public static BlockCable cable; - } - - public static final class Items - { - public static ItemComputer computerNormal; - public static ItemComputer computerAdvanced; - public static ItemComputer computerCommand; - - public static ItemPocketComputer pocketComputerNormal; - public static ItemPocketComputer pocketComputerAdvanced; - - public static ItemTurtle turtleNormal; - public static ItemTurtle turtleAdvanced; - - public static ItemDisk disk; - public static ItemTreasureDisk treasureDisk; - - public static ItemPrintout printedPage; - public static ItemPrintout printedPages; - public static ItemPrintout printedBook; - - public static ItemBlockCable.Cable cable; - public static ItemBlockCable.WiredModem wiredModem; - } - public static final class TurtleUpgrades { public static TurtleModem wirelessModemNormal; @@ -194,7 +132,8 @@ public final class ComputerCraft public ComputerCraft() { - Config.load(); + Config.setup(); + Registry.setup(); } public static InputStream getResourceFile( String domain, String subPath ) diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index 12dff18c6..33d756866 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -5,12 +5,15 @@ */ package dan200.computercraft.api.pocket; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Util; +import net.minecraftforge.common.util.NonNullSupplier; import javax.annotation.Nonnull; +import java.util.function.Supplier; /** * A base class for {@link IPocketUpgrade}s. @@ -21,23 +24,48 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade { private final ResourceLocation id; private final String adjective; - private final ItemStack stack; + private final NonNullSupplier stack; - protected AbstractPocketUpgrade( ResourceLocation id, String adjective, ItemStack stack ) + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, NonNullSupplier stack ) { this.id = id; this.adjective = adjective; this.stack = stack; } + protected AbstractPocketUpgrade( ResourceLocation id, NonNullSupplier item ) + { + this( id, Util.makeTranslationKey( "upgrade", id ) + ".adjective", item ); + } + + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, ItemStack stack ) + { + this( id, adjective, () -> stack ); + } + + protected AbstractPocketUpgrade( ResourceLocation id, ItemStack stack ) + { + this( id, () -> stack ); + } + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, IItemProvider item ) { - this( id, adjective, new ItemStack( item ) ); + this( id, adjective, new CachedStack( () -> item ) ); } protected AbstractPocketUpgrade( ResourceLocation id, IItemProvider item ) { - this( id, Util.makeTranslationKey( "upgrade", id ) + ".adjective", new ItemStack( item ) ); + this( id, new CachedStack( () -> item ) ); + } + + protected AbstractPocketUpgrade( ResourceLocation id, String adjective, Supplier item ) + { + this( id, adjective, new CachedStack( item ) ); + } + + protected AbstractPocketUpgrade( ResourceLocation id, Supplier item ) + { + this( id, new CachedStack( item ) ); } @Nonnull @@ -58,6 +86,32 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade @Override public final ItemStack getCraftingItem() { - return stack; + return stack.get(); + } + + /** + * Caches the construction of an item stack. + * + * @see dan200.computercraft.api.turtle.AbstractTurtleUpgrade For explanation of this class. + */ + private static final class CachedStack implements NonNullSupplier + { + private final Supplier provider; + private Item item; + private ItemStack stack; + + CachedStack( Supplier provider ) + { + this.provider = provider; + } + + @Nonnull + @Override + public ItemStack get() + { + Item item = provider.get().asItem(); + if( item == this.item && stack != null ) return stack; + return stack = new ItemStack( this.item = item ); + } } } diff --git a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java index 15bb43832..b3c92271c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java @@ -5,12 +5,15 @@ */ package dan200.computercraft.api.turtle; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; import net.minecraft.util.Util; +import net.minecraftforge.common.util.NonNullSupplier; import javax.annotation.Nonnull; +import java.util.function.Supplier; /** * A base class for {@link ITurtleUpgrade}s. @@ -22,9 +25,9 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade private final ResourceLocation id; private final TurtleUpgradeType type; private final String adjective; - private final ItemStack stack; + private final NonNullSupplier stack; - protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, NonNullSupplier stack ) { this.id = id; this.type = type; @@ -32,19 +35,39 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade this.stack = stack; } - protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, IItemProvider item ) - { - this( id, type, adjective, new ItemStack( item ) ); - } - - protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack ) + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, NonNullSupplier stack ) { this( id, type, Util.makeTranslationKey( "upgrade", id ) + ".adjective", stack ); } + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack ) + { + this( id, type, adjective, () -> stack ); + } + + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, ItemStack stack ) + { + this( id, type, () -> stack ); + } + + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, IItemProvider item ) + { + this( id, type, adjective, new CachedStack( () -> item ) ); + } + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, IItemProvider item ) { - this( id, type, new ItemStack( item ) ); + this( id, type, new CachedStack( () -> item ) ); + } + + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, Supplier item ) + { + this( id, type, adjective, new CachedStack( item ) ); + } + + protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, Supplier item ) + { + this( id, type, new CachedStack( item ) ); } @Nonnull @@ -72,6 +95,32 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade @Override public final ItemStack getCraftingItem() { - return stack; + return stack.get(); + } + + /** + * A supplier which converts an item into an item stack. + * + * Constructing item stacks is somewhat expensive due to attaching capabilities. We cache it if given a consistent item. + */ + private static final class CachedStack implements NonNullSupplier + { + private final Supplier provider; + private Item item; + private ItemStack stack; + + CachedStack( Supplier provider ) + { + this.provider = provider; + } + + @Nonnull + @Override + public ItemStack get() + { + Item item = provider.get().asItem(); + if( item == this.item && stack != null ) return stack; + return stack = new ItemStack( this.item = item ); + } } } diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 67f9f776a..57359e00c 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -7,6 +7,7 @@ package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.TurtleModelLoader; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemTreasureDisk; @@ -109,7 +110,7 @@ public final class ClientRegistry @SubscribeEvent public static void onItemColours( ColorHandlerEvent.Item event ) { - if( ComputerCraft.Items.disk == null || ComputerCraft.Blocks.turtleNormal == null ) + if( Registry.ModItems.DISK == null || Registry.ModBlocks.TURTLE_NORMAL == null ) { ComputerCraft.log.warn( "Block/item registration has failed. Skipping registration of item colours." ); return; @@ -117,12 +118,12 @@ public final class ClientRegistry event.getItemColors().register( ( stack, layer ) -> layer == 1 ? ((ItemDisk) stack.getItem()).getColour( stack ) : 0xFFFFFF, - ComputerCraft.Items.disk + Registry.ModItems.DISK.get() ); event.getItemColors().register( ( stack, layer ) -> layer == 1 ? ItemTreasureDisk.getColour( stack ) : 0xFFFFFF, - ComputerCraft.Items.treasureDisk + Registry.ModItems.TREASURE_DISK.get() ); event.getItemColors().register( ( stack, layer ) -> { @@ -139,12 +140,12 @@ public final class ClientRegistry return light == -1 ? Colour.BLACK.getHex() : light; } } - }, ComputerCraft.Items.pocketComputerNormal, ComputerCraft.Items.pocketComputerAdvanced ); + }, Registry.ModItems.POCKET_COMPUTER_NORMAL.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get() ); // Setup turtle colours event.getItemColors().register( ( stack, tintIndex ) -> tintIndex == 0 ? ((IColouredItem) stack.getItem()).getColour( stack ) : 0xFFFFFF, - ComputerCraft.Blocks.turtleNormal, ComputerCraft.Blocks.turtleAdvanced + Registry.ModBlocks.TURTLE_NORMAL.get(), Registry.ModBlocks.TURTLE_ADVANCED.get() ); } } diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 57911646b..70147c4c6 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -10,17 +10,11 @@ import dan200.computercraft.client.gui.*; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TurtlePlayerRenderer; -import dan200.computercraft.shared.common.ContainerHeldItem; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; -import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; -import dan200.computercraft.shared.turtle.blocks.TileTurtle; -import dan200.computercraft.shared.turtle.core.TurtlePlayer; -import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import net.minecraft.client.gui.ScreenManager; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderTypeLookup; @@ -41,36 +35,36 @@ public final class ComputerCraftProxyClient registerContainers(); // While turtles themselves are not transparent, their upgrades may be. - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleNormal, RenderType.getTranslucent() ); - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.turtleAdvanced, RenderType.getTranslucent() ); + RenderTypeLookup.setRenderLayer( Registry.ModBlocks.TURTLE_NORMAL.get(), RenderType.getTranslucent() ); + RenderTypeLookup.setRenderLayer( Registry.ModBlocks.TURTLE_ADVANCED.get(), RenderType.getTranslucent() ); // Monitors' textures have transparent fronts and so count as cutouts. - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorNormal, RenderType.getCutout() ); - RenderTypeLookup.setRenderLayer( ComputerCraft.Blocks.monitorAdvanced, RenderType.getCutout() ); + RenderTypeLookup.setRenderLayer( Registry.ModBlocks.MONITOR_NORMAL.get(), RenderType.getCutout() ); + RenderTypeLookup.setRenderLayer( Registry.ModBlocks.MONITOR_ADVANCED.get(), RenderType.getCutout() ); // Setup TESRs - ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_NORMAL, TileEntityMonitorRenderer::new ); - ClientRegistry.bindTileEntityRenderer( TileMonitor.FACTORY_ADVANCED, TileEntityMonitorRenderer::new ); - ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_NORMAL, TileEntityTurtleRenderer::new ); - ClientRegistry.bindTileEntityRenderer( TileTurtle.FACTORY_ADVANCED, TileEntityTurtleRenderer::new ); + ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.MONITOR_NORMAL.get(), TileEntityMonitorRenderer::new ); + ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.MONITOR_ADVANCED.get(), TileEntityMonitorRenderer::new ); + ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new ); + ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new ); // TODO: ClientRegistry.bindTileEntityRenderer( TileCable.FACTORY, x -> new TileEntityCableRenderer() ); - RenderingRegistry.registerEntityRenderingHandler( TurtlePlayer.TYPE, TurtlePlayerRenderer::new ); + RenderingRegistry.registerEntityRenderingHandler( Registry.ModEntities.TURTLE_PLAYER.get(), TurtlePlayerRenderer::new ); } private static void registerContainers() { // My IDE doesn't think so, but we do actually need these generics. - ScreenManager.>registerFactory( ContainerComputer.TYPE, GuiComputer::create ); - ScreenManager.>registerFactory( ContainerPocketComputer.TYPE, GuiComputer::createPocket ); - ScreenManager.registerFactory( ContainerTurtle.TYPE, GuiTurtle::new ); + ScreenManager.>registerFactory( Registry.ModContainers.COMPUTER.get(), GuiComputer::create ); + ScreenManager.>registerFactory( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::createPocket ); + ScreenManager.registerFactory( Registry.ModContainers.TURTLE.get(), GuiTurtle::new ); - ScreenManager.registerFactory( ContainerPrinter.TYPE, GuiPrinter::new ); - ScreenManager.registerFactory( ContainerDiskDrive.TYPE, GuiDiskDrive::new ); - ScreenManager.registerFactory( ContainerHeldItem.PRINTOUT_TYPE, GuiPrintout::new ); + ScreenManager.registerFactory( Registry.ModContainers.PRINTER.get(), GuiPrinter::new ); + ScreenManager.registerFactory( Registry.ModContainers.DISK_DRIVE.get(), GuiDiskDrive::new ); + ScreenManager.registerFactory( Registry.ModContainers.PRINTOUT.get(), GuiPrintout::new ); - ScreenManager.>registerFactory( ContainerViewComputer.TYPE, GuiComputer::createView ); + ScreenManager.>registerFactory( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::createView ); } @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index 42b6c90c3..f88700b98 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -8,6 +8,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.util.WorldUtil; @@ -51,7 +52,7 @@ public final class CableHighlightRenderer BlockState state = world.getBlockState( pos ); // We only care about instances with both cable and modem. - if( state.getBlock() != ComputerCraft.Blocks.cable || state.get( BlockCable.MODEM ).getFacing() == null || !state.get( BlockCable.CABLE ) ) + if( state.getBlock() != Registry.ModBlocks.CABLE.get() || state.get( BlockCable.MODEM ).getFacing() == null || !state.get( BlockCable.CABLE ) ) { return; } diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index 416516b1b..b85f0dea1 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -7,6 +7,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; @@ -17,6 +18,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.world.storage.loot.*; import net.minecraft.world.storage.loot.conditions.Alternative; import net.minecraft.world.storage.loot.conditions.SurvivesExplosion; +import net.minecraftforge.fml.RegistryObject; import java.util.function.BiConsumer; @@ -30,19 +32,19 @@ public class LootTables extends LootTableProvider @Override protected void registerLoot( BiConsumer add ) { - basicDrop( add, ComputerCraft.Blocks.diskDrive ); - basicDrop( add, ComputerCraft.Blocks.monitorNormal ); - basicDrop( add, ComputerCraft.Blocks.monitorAdvanced ); - basicDrop( add, ComputerCraft.Blocks.printer ); - basicDrop( add, ComputerCraft.Blocks.speaker ); - basicDrop( add, ComputerCraft.Blocks.wiredModemFull ); - basicDrop( add, ComputerCraft.Blocks.wirelessModemNormal ); - basicDrop( add, ComputerCraft.Blocks.wirelessModemAdvanced ); + basicDrop( add, Registry.ModBlocks.DISK_DRIVE ); + basicDrop( add, Registry.ModBlocks.MONITOR_NORMAL ); + basicDrop( add, Registry.ModBlocks.MONITOR_ADVANCED ); + basicDrop( add, Registry.ModBlocks.PRINTER ); + basicDrop( add, Registry.ModBlocks.SPEAKER ); + basicDrop( add, Registry.ModBlocks.WIRED_MODEM_FULL ); + basicDrop( add, Registry.ModBlocks.WIRELESS_MODEM_NORMAL ); + basicDrop( add, Registry.ModBlocks.WIRELESS_MODEM_ADVANCED ); - computerDrop( add, ComputerCraft.Blocks.computerNormal ); - computerDrop( add, ComputerCraft.Blocks.computerAdvanced ); - computerDrop( add, ComputerCraft.Blocks.turtleNormal ); - computerDrop( add, ComputerCraft.Blocks.turtleAdvanced ); + computerDrop( add, Registry.ModBlocks.COMPUTER_NORMAL ); + computerDrop( add, Registry.ModBlocks.COMPUTER_ADVANCED ); + computerDrop( add, Registry.ModBlocks.TURTLE_NORMAL ); + computerDrop( add, Registry.ModBlocks.TURTLE_ADVANCED ); add.accept( ComputerCraftProxyCommon.ForgeHandlers.LOOT_TREASURE_DISK, LootTable .builder() @@ -50,8 +52,9 @@ public class LootTables extends LootTableProvider .build() ); } - private static void basicDrop( BiConsumer add, Block block ) + private static void basicDrop( BiConsumer add, RegistryObject wrapper ) { + Block block = wrapper.get(); add.accept( block.getLootTable(), LootTable .builder() .setParameterSet( LootParameterSets.BLOCK ) @@ -63,8 +66,9 @@ public class LootTables extends LootTableProvider ).build() ); } - private static void computerDrop( BiConsumer add, Block block ) + private static void computerDrop( BiConsumer add, RegistryObject wrapper ) { + Block block = wrapper.get(); add.accept( block.getLootTable(), LootTable .builder() .setParameterSet( LootParameterSets.BLOCK ) diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java index 9523d80ac..a86ac212e 100644 --- a/src/main/java/dan200/computercraft/data/Recipes.java +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -8,6 +8,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; import dan200.computercraft.data.Tags.CCTags; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; @@ -55,12 +56,12 @@ public class Recipes extends RecipeProvider for( Colour colour : Colour.VALUES ) { ShapelessRecipeBuilder - .shapelessRecipe( ComputerCraft.Items.disk ) + .shapelessRecipe( Registry.ModItems.DISK.get() ) .addIngredient( Tags.Items.DUSTS_REDSTONE ) .addIngredient( Items.PAPER ) .addIngredient( DyeItem.getItem( ofColour( colour ) ) ) .setGroup( "computercraft:disk" ) - .addCriterion( "has_drive", inventoryChange( ComputerCraft.Blocks.diskDrive ) ) + .addCriterion( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE.get() ) ) .build( RecipeWrapper.wrap( ImpostorShapelessRecipe.SERIALIZER, add, x -> x.putInt( "color", colour.getHex() ) @@ -140,7 +141,7 @@ public class Recipes extends RecipeProvider private void basicRecipes( @Nonnull Consumer add ) { ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Items.cable, 6 ) + .shapedRecipe( Registry.ModItems.CABLE.get(), 6 ) .patternLine( " # " ) .patternLine( "#R#" ) .patternLine( " # " ) @@ -151,7 +152,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.computerNormal ) + .shapedRecipe( Registry.ModBlocks.COMPUTER_NORMAL.get() ) .patternLine( "###" ) .patternLine( "#R#" ) .patternLine( "#G#" ) @@ -162,7 +163,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.computerAdvanced ) + .shapedRecipe( Registry.ModBlocks.COMPUTER_ADVANCED.get() ) .patternLine( "###" ) .patternLine( "#R#" ) .patternLine( "#G#" ) @@ -173,7 +174,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.computerCommand ) + .shapedRecipe( Registry.ModBlocks.COMPUTER_COMMAND.get() ) .patternLine( "###" ) .patternLine( "#R#" ) .patternLine( "#G#" ) @@ -184,7 +185,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.diskDrive ) + .shapedRecipe( Registry.ModBlocks.DISK_DRIVE.get() ) .patternLine( "###" ) .patternLine( "#R#" ) .patternLine( "#R#" ) @@ -194,7 +195,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.monitorNormal ) + .shapedRecipe( Registry.ModBlocks.MONITOR_NORMAL.get() ) .patternLine( "###" ) .patternLine( "#G#" ) .patternLine( "###" ) @@ -204,7 +205,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.monitorAdvanced, 4 ) + .shapedRecipe( Registry.ModBlocks.MONITOR_ADVANCED.get(), 4 ) .patternLine( "###" ) .patternLine( "#G#" ) .patternLine( "###" ) @@ -214,7 +215,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Items.pocketComputerNormal ) + .shapedRecipe( Registry.ModItems.POCKET_COMPUTER_NORMAL.get() ) .patternLine( "###" ) .patternLine( "#A#" ) .patternLine( "#G#" ) @@ -226,7 +227,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Items.pocketComputerAdvanced ) + .shapedRecipe( Registry.ModItems.POCKET_COMPUTER_ADVANCED.get() ) .patternLine( "###" ) .patternLine( "#A#" ) .patternLine( "#G#" ) @@ -238,7 +239,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.printer ) + .shapedRecipe( Registry.ModBlocks.PRINTER.get() ) .patternLine( "###" ) .patternLine( "#R#" ) .patternLine( "#D#" ) @@ -249,7 +250,7 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.speaker ) + .shapedRecipe( Registry.ModBlocks.SPEAKER.get() ) .patternLine( "###" ) .patternLine( "#N#" ) .patternLine( "#R#" ) @@ -260,29 +261,29 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Items.wiredModem ) + .shapedRecipe( Registry.ModItems.WIRED_MODEM.get() ) .patternLine( "###" ) .patternLine( "#R#" ) .patternLine( "###" ) .key( '#', Tags.Items.STONE ) .key( 'R', Tags.Items.DUSTS_REDSTONE ) .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) - .addCriterion( "has_cable", inventoryChange( ComputerCraft.Items.cable ) ) + .addCriterion( "has_cable", inventoryChange( Registry.ModItems.CABLE.get() ) ) .build( add ); ShapelessRecipeBuilder - .shapelessRecipe( ComputerCraft.Blocks.wiredModemFull ) - .addIngredient( ComputerCraft.Items.wiredModem ) + .shapelessRecipe( Registry.ModBlocks.WIRED_MODEM_FULL.get() ) + .addIngredient( Registry.ModItems.WIRED_MODEM.get() ) .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) ) .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) ); ShapelessRecipeBuilder - .shapelessRecipe( ComputerCraft.Items.wiredModem ) - .addIngredient( ComputerCraft.Blocks.wiredModemFull ) + .shapelessRecipe( Registry.ModItems.WIRED_MODEM.get() ) + .addIngredient( Registry.ModBlocks.WIRED_MODEM_FULL.get() ) .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) ) .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.wirelessModemNormal ) + .shapedRecipe( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() ) .patternLine( "###" ) .patternLine( "#E#" ) .patternLine( "###" ) @@ -292,14 +293,14 @@ public class Recipes extends RecipeProvider .build( add ); ShapedRecipeBuilder - .shapedRecipe( ComputerCraft.Blocks.wirelessModemAdvanced ) + .shapedRecipe( Registry.ModBlocks.WIRELESS_MODEM_ADVANCED.get() ) .patternLine( "###" ) .patternLine( "#E#" ) .patternLine( "###" ) .key( '#', Tags.Items.INGOTS_GOLD ) .key( 'E', Items.ENDER_EYE ) .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) ) - .addCriterion( "has_wireless", inventoryChange( ComputerCraft.Blocks.wirelessModemNormal ) ) + .addCriterion( "has_wireless", inventoryChange( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() ) ) .build( add ); } diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java index bc78e3e7b..d822d6150 100644 --- a/src/main/java/dan200/computercraft/data/Tags.java +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -7,6 +7,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import net.minecraft.data.DataGenerator; import net.minecraft.data.ItemTagsProvider; import net.minecraft.item.Item; @@ -35,14 +36,14 @@ public class Tags extends ItemTagsProvider protected void registerTags() { getBuilder( COMPUTER ) - .add( ComputerCraft.Items.computerNormal ) - .add( ComputerCraft.Items.computerAdvanced ) - .add( ComputerCraft.Items.computerCommand ); - getBuilder( TURTLE ).add( ComputerCraft.Items.turtleNormal, ComputerCraft.Items.turtleAdvanced ); - getBuilder( WIRED_MODEM ).add( ComputerCraft.Items.wiredModem, ComputerCraft.Blocks.wiredModemFull.asItem() ); + .add( Registry.ModItems.COMPUTER_NORMAL.get() ) + .add( Registry.ModItems.COMPUTER_ADVANCED.get() ) + .add( Registry.ModItems.COMPUTER_COMMAND.get() ); + getBuilder( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() ); + getBuilder( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() ); getBuilder( MONITOR ) - .add( ComputerCraft.Blocks.monitorNormal.asItem() ) - .add( ComputerCraft.Blocks.monitorAdvanced.asItem() ); + .add( Registry.ModItems.MONITOR_NORMAL.get() ) + .add( Registry.ModItems.MONITOR_ADVANCED.get() ); } private static Tag item( String name ) diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 567f2dba3..7ccb2b99d 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -270,7 +270,7 @@ public final class Config clientSpec = clientBuilder.build(); } - public static void load() + public static void setup() { ModLoadingContext.get().registerConfig( ModConfig.Type.SERVER, serverSpec ); ModLoadingContext.get().registerConfig( ModConfig.Type.CLIENT, clientSpec ); diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index e76c03b21..fe8a2d448 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -22,6 +22,10 @@ import dan200.computercraft.shared.media.items.ItemPrintout; import dan200.computercraft.shared.media.items.ItemTreasureDisk; import dan200.computercraft.shared.media.recipes.DiskRecipe; import dan200.computercraft.shared.media.recipes.PrintoutRecipe; +import dan200.computercraft.shared.network.container.ComputerContainerData; +import dan200.computercraft.shared.network.container.ContainerData; +import dan200.computercraft.shared.network.container.HeldItemContainerData; +import dan200.computercraft.shared.network.container.ViewComputerContainerData; import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; @@ -49,10 +53,12 @@ import dan200.computercraft.shared.turtle.recipes.TurtleRecipe; import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe; import dan200.computercraft.shared.turtle.upgrades.*; import dan200.computercraft.shared.util.CreativeTabMain; +import dan200.computercraft.shared.util.FixedPointTileEntityType; import dan200.computercraft.shared.util.ImpostorRecipe; import dan200.computercraft.shared.util.ImpostorShapelessRecipe; import net.minecraft.block.Block; import net.minecraft.block.material.Material; +import net.minecraft.entity.EntityClassification; import net.minecraft.entity.EntityType; import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.BlockItem; @@ -60,12 +66,20 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.Items; import net.minecraft.item.crafting.IRecipeSerializer; +import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.registries.IForgeRegistry; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; + +import java.util.function.BiFunction; +import java.util.function.Function; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class Registry @@ -76,211 +90,153 @@ public final class Registry { } - @SubscribeEvent - public static void registerBlocks( RegistryEvent.Register event ) + public static final class ModBlocks { - IForgeRegistry registry = event.getRegistry(); + static final DeferredRegister BLOCKS = new DeferredRegister<>( ForgeRegistries.BLOCKS, ComputerCraft.MOD_ID ); - // Computers - ComputerCraft.Blocks.computerNormal = new BlockComputer( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), - ComputerFamily.NORMAL, TileComputer.FACTORY_NORMAL - ); + private static Block.Properties properties() + { + return Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ); + } - ComputerCraft.Blocks.computerAdvanced = new BlockComputer( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.0f ), - ComputerFamily.ADVANCED, TileComputer.FACTORY_ADVANCED - ); + private static Block.Properties turtleProperties() + { + return Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ); + } - ComputerCraft.Blocks.computerCommand = new BlockComputer( + private static Block.Properties modemProperties() + { + return Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f ); + } + + public static final RegistryObject COMPUTER_NORMAL = BLOCKS.register( "computer_normal", + () -> new BlockComputer( properties(), ComputerFamily.NORMAL, ModTiles.COMPUTER_NORMAL ) ); + public static final RegistryObject COMPUTER_ADVANCED = BLOCKS.register( "computer_advanced", + () -> new BlockComputer( properties(), ComputerFamily.ADVANCED, ModTiles.COMPUTER_ADVANCED ) ); + + public static final RegistryObject COMPUTER_COMMAND = BLOCKS.register( "computer_command", () -> new BlockComputer( Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ), - ComputerFamily.COMMAND, TileCommandComputer.FACTORY - ); + ComputerFamily.COMMAND, ModTiles.COMPUTER_COMMAND + ) ); - registry.registerAll( - ComputerCraft.Blocks.computerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ) ), - ComputerCraft.Blocks.computerAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ) ), - ComputerCraft.Blocks.computerCommand.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_command" ) ) - ); + public static final RegistryObject TURTLE_NORMAL = BLOCKS.register( "turtle_normal", + () -> new BlockTurtle( turtleProperties(), ComputerFamily.NORMAL, ModTiles.TURTLE_NORMAL ) ); + public static final RegistryObject TURTLE_ADVANCED = BLOCKS.register( "turtle_advanced", + () -> new BlockTurtle( turtleProperties(), ComputerFamily.ADVANCED, ModTiles.TURTLE_ADVANCED ) ); - // Turtles - ComputerCraft.Blocks.turtleNormal = new BlockTurtle( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), - ComputerFamily.NORMAL, TileTurtle.FACTORY_NORMAL - ); + public static final RegistryObject SPEAKER = BLOCKS.register( "speaker", () -> new BlockSpeaker( properties() ) ); + public static final RegistryObject DISK_DRIVE = BLOCKS.register( "disk_drive", () -> new BlockDiskDrive( properties() ) ); + public static final RegistryObject PRINTER = BLOCKS.register( "printer", () -> new BlockPrinter( properties() ) ); - ComputerCraft.Blocks.turtleAdvanced = new BlockTurtle( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f ), - ComputerFamily.ADVANCED, TileTurtle.FACTORY_ADVANCED - ); + public static final RegistryObject MONITOR_NORMAL = BLOCKS.register( "monitor_normal", + () -> new BlockMonitor( properties(), ModTiles.MONITOR_NORMAL ) ); + public static final RegistryObject MONITOR_ADVANCED = BLOCKS.register( "monitor_advanced", + () -> new BlockMonitor( properties(), ModTiles.MONITOR_ADVANCED ) ); - registry.registerAll( - ComputerCraft.Blocks.turtleNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ) ), - ComputerCraft.Blocks.turtleAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ) ) - ); + public static final RegistryObject WIRELESS_MODEM_NORMAL = BLOCKS.register( "wireless_modem_normal", + () -> new BlockWirelessModem( properties(), ModTiles.WIRELESS_MODEM_NORMAL ) ); + public static final RegistryObject WIRELESS_MODEM_ADVANCED = BLOCKS.register( "wireless_modem_advanced", + () -> new BlockWirelessModem( properties(), ModTiles.WIRELESS_MODEM_ADVANCED ) ); - // Peripherals - ComputerCraft.Blocks.speaker = new BlockSpeaker( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ) - ); - - ComputerCraft.Blocks.diskDrive = new BlockDiskDrive( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ) - ); - - ComputerCraft.Blocks.monitorNormal = new BlockMonitor( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), - TileMonitor.FACTORY_NORMAL - ); - - ComputerCraft.Blocks.monitorAdvanced = new BlockMonitor( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), - TileMonitor.FACTORY_ADVANCED - ); - - ComputerCraft.Blocks.printer = new BlockPrinter( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ) - ); - - ComputerCraft.Blocks.wirelessModemNormal = new BlockWirelessModem( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), - TileWirelessModem.FACTORY_NORMAL - ); - - ComputerCraft.Blocks.wirelessModemAdvanced = new BlockWirelessModem( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 ), - TileWirelessModem.FACTORY_ADVANCED - ); - - ComputerCraft.Blocks.wiredModemFull = new BlockWiredModemFull( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f ) - ); - - ComputerCraft.Blocks.cable = new BlockCable( - Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f ) - ); - - registry.registerAll( - ComputerCraft.Blocks.speaker.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ) ), - ComputerCraft.Blocks.diskDrive.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ) ), - ComputerCraft.Blocks.monitorNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ) ), - ComputerCraft.Blocks.monitorAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "monitor_advanced" ) ), - ComputerCraft.Blocks.printer.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ) ), - ComputerCraft.Blocks.wirelessModemNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) ), - ComputerCraft.Blocks.wirelessModemAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) ), - ComputerCraft.Blocks.wiredModemFull.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ) ), - ComputerCraft.Blocks.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ) - ); + public static final RegistryObject WIRED_MODEM_FULL = BLOCKS.register( "wired_modem_full", + () -> new BlockWiredModemFull( modemProperties() ) ); + public static final RegistryObject CABLE = BLOCKS.register( "cable", () -> new BlockCable( modemProperties() ) ); } - @SubscribeEvent - public static void registerTileEntities( RegistryEvent.Register> event ) + public static class ModTiles { - IForgeRegistry> registry = event.getRegistry(); + static final DeferredRegister> TILES = new DeferredRegister<>( ForgeRegistries.TILE_ENTITIES, ComputerCraft.MOD_ID ); - // Computers - registry.registerAll( TileComputer.FACTORY_NORMAL, TileComputer.FACTORY_ADVANCED, TileCommandComputer.FACTORY ); + private static RegistryObject> ofBlock( RegistryObject block, Function, T> factory ) + { + return TILES.register( block.getId().getPath(), () -> FixedPointTileEntityType.create( block, factory ) ); + } - // Turtles - registry.registerAll( TileTurtle.FACTORY_NORMAL, TileTurtle.FACTORY_ADVANCED ); + public static final RegistryObject> MONITOR_NORMAL = + ofBlock( ModBlocks.MONITOR_NORMAL, f -> new TileMonitor( f, false ) ); + public static final RegistryObject> MONITOR_ADVANCED = + ofBlock( ModBlocks.MONITOR_ADVANCED, f -> new TileMonitor( f, true ) ); - // Peripherals - registry.registerAll( - TileSpeaker.FACTORY, - TileDiskDrive.FACTORY, - TileMonitor.FACTORY_NORMAL, - TileMonitor.FACTORY_ADVANCED, - TilePrinter.FACTORY, - TileWirelessModem.FACTORY_NORMAL, - TileWirelessModem.FACTORY_ADVANCED, - TileWiredModemFull.FACTORY, - TileCable.FACTORY - ); + public static final RegistryObject> COMPUTER_NORMAL = + ofBlock( ModBlocks.COMPUTER_NORMAL, f -> new TileComputer( ComputerFamily.NORMAL, f ) ); + public static final RegistryObject> COMPUTER_ADVANCED = + ofBlock( ModBlocks.COMPUTER_ADVANCED, f -> new TileComputer( ComputerFamily.ADVANCED, f ) ); + public static final RegistryObject> COMPUTER_COMMAND = + ofBlock( ModBlocks.COMPUTER_COMMAND, f -> new TileCommandComputer( ComputerFamily.COMMAND, f ) ); + + public static final RegistryObject> TURTLE_NORMAL = + ofBlock( ModBlocks.TURTLE_NORMAL, f -> new TileTurtle( f, ComputerFamily.NORMAL ) ); + public static final RegistryObject> TURTLE_ADVANCED = + ofBlock( ModBlocks.TURTLE_ADVANCED, f -> new TileTurtle( f, ComputerFamily.ADVANCED ) ); + + public static final RegistryObject> SPEAKER = ofBlock( ModBlocks.SPEAKER, TileSpeaker::new ); + public static final RegistryObject> DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, TileDiskDrive::new ); + public static final RegistryObject> PRINTER = ofBlock( ModBlocks.PRINTER, TilePrinter::new ); + public static final RegistryObject> WIRED_MODEM_FULL = ofBlock( ModBlocks.WIRED_MODEM_FULL, TileWiredModemFull::new ); + public static final RegistryObject> CABLE = ofBlock( ModBlocks.CABLE, TileCable::new ); + + public static final RegistryObject> WIRELESS_MODEM_NORMAL = + ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL, f -> new TileWirelessModem( f, false ) ); + public static final RegistryObject> WIRELESS_MODEM_ADVANCED = + ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED, f -> new TileWirelessModem( f, true ) ); } - private static T setupItemBlock( T item ) + public static final class ModItems { - item.setRegistryName( item.getBlock().getRegistryName() ); - return item; - } + static final DeferredRegister ITEMS = new DeferredRegister<>( ForgeRegistries.ITEMS, ComputerCraft.MOD_ID ); - private static Item.Properties defaultItem() - { - return new Item.Properties().group( mainItemGroup ); + private static Item.Properties properties() + { + return new Item.Properties().group( mainItemGroup ); + } + + private static RegistryObject ofBlock( RegistryObject parent, BiFunction supplier ) + { + return ITEMS.register( parent.getId().getPath(), () -> supplier.apply( parent.get(), properties() ) ); + } + + public static final RegistryObject COMPUTER_NORMAL = ofBlock( ModBlocks.COMPUTER_NORMAL, ItemComputer::new ); + public static final RegistryObject COMPUTER_ADVANCED = ofBlock( ModBlocks.COMPUTER_ADVANCED, ItemComputer::new ); + public static final RegistryObject COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND, ItemComputer::new ); + + public static final RegistryObject POCKET_COMPUTER_NORMAL = ITEMS.register( "pocket_computer_normal", + () -> new ItemPocketComputer( properties().maxStackSize( 1 ), ComputerFamily.NORMAL ) ); + public static final RegistryObject POCKET_COMPUTER_ADVANCED = ITEMS.register( "pocket_computer_advanced", + () -> new ItemPocketComputer( properties().maxStackSize( 1 ), ComputerFamily.ADVANCED ) ); + + public static final RegistryObject TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL, ItemTurtle::new ); + public static final RegistryObject TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED, ItemTurtle::new ); + + public static final RegistryObject DISK = + ITEMS.register( "disk", () -> new ItemDisk( properties().maxStackSize( 1 ) ) ); + public static final RegistryObject TREASURE_DISK = + ITEMS.register( "treasure_disk", () -> new ItemTreasureDisk( properties().maxStackSize( 1 ) ) ); + + public static final RegistryObject PRINTED_PAGE = ITEMS.register( "printed_page", + () -> new ItemPrintout( properties().maxStackSize( 1 ), ItemPrintout.Type.PAGE ) ); + public static final RegistryObject PRINTED_PAGES = ITEMS.register( "printed_pages", + () -> new ItemPrintout( properties().maxStackSize( 1 ), ItemPrintout.Type.PAGES ) ); + public static final RegistryObject PRINTED_BOOK = ITEMS.register( "printed_book", + () -> new ItemPrintout( properties().maxStackSize( 1 ), ItemPrintout.Type.BOOK ) ); + + public static final RegistryObject SPEAKER = ofBlock( ModBlocks.SPEAKER, BlockItem::new ); + public static final RegistryObject DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, BlockItem::new ); + public static final RegistryObject PRINTER = ofBlock( ModBlocks.PRINTER, BlockItem::new ); + public static final RegistryObject MONITOR_NORMAL = ofBlock( ModBlocks.MONITOR_NORMAL, BlockItem::new ); + public static final RegistryObject MONITOR_ADVANCED = ofBlock( ModBlocks.MONITOR_ADVANCED, BlockItem::new ); + public static final RegistryObject WIRELESS_MODEM_NORMAL = ofBlock( ModBlocks.WIRELESS_MODEM_NORMAL, BlockItem::new ); + public static final RegistryObject WIRELESS_MODEM_ADVANCED = ofBlock( ModBlocks.WIRELESS_MODEM_ADVANCED, BlockItem::new ); + public static final RegistryObject WIRED_MODEM_FULL = ofBlock( ModBlocks.WIRED_MODEM_FULL, BlockItem::new ); + + public static final RegistryObject CABLE = ITEMS.register( "cable", + () -> new ItemBlockCable.Cable( ModBlocks.CABLE.get(), properties() ) ); + public static final RegistryObject WIRED_MODEM = ITEMS.register( "wired_modem", + () -> new ItemBlockCable.WiredModem( ModBlocks.CABLE.get(), properties() ) ); } @SubscribeEvent public static void registerItems( RegistryEvent.Register event ) { - IForgeRegistry registry = event.getRegistry(); - - // Computer - ComputerCraft.Items.computerNormal = new ItemComputer( ComputerCraft.Blocks.computerNormal, defaultItem() ); - ComputerCraft.Items.computerAdvanced = new ItemComputer( ComputerCraft.Blocks.computerAdvanced, defaultItem() ); - ComputerCraft.Items.computerCommand = new ItemComputer( ComputerCraft.Blocks.computerCommand, defaultItem() ); - - registry.registerAll( - setupItemBlock( ComputerCraft.Items.computerNormal ), - setupItemBlock( ComputerCraft.Items.computerAdvanced ), - setupItemBlock( ComputerCraft.Items.computerCommand ) - ); - - // Turtle - ComputerCraft.Items.turtleNormal = new ItemTurtle( ComputerCraft.Blocks.turtleNormal, defaultItem() ); - ComputerCraft.Items.turtleAdvanced = new ItemTurtle( ComputerCraft.Blocks.turtleAdvanced, defaultItem() ); - registry.registerAll( - setupItemBlock( ComputerCraft.Items.turtleNormal ), - setupItemBlock( ComputerCraft.Items.turtleAdvanced ) - ); - - // Pocket computer - ComputerCraft.Items.pocketComputerNormal = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.NORMAL ); - ComputerCraft.Items.pocketComputerAdvanced = new ItemPocketComputer( defaultItem().maxStackSize( 1 ), ComputerFamily.ADVANCED ); - - registry.registerAll( - ComputerCraft.Items.pocketComputerNormal.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_normal" ) ), - ComputerCraft.Items.pocketComputerAdvanced.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer_advanced" ) ) - ); - - // Floppy disk - ComputerCraft.Items.disk = new ItemDisk( defaultItem().maxStackSize( 1 ) ); - ComputerCraft.Items.treasureDisk = new ItemTreasureDisk( defaultItem().maxStackSize( 1 ) ); - - registry.registerAll( - ComputerCraft.Items.disk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk" ) ), - ComputerCraft.Items.treasureDisk.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "treasure_disk" ) ) - ); - - // Printouts - ComputerCraft.Items.printedPage = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.PAGE ); - ComputerCraft.Items.printedPages = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.PAGES ); - ComputerCraft.Items.printedBook = new ItemPrintout( defaultItem().maxStackSize( 1 ), ItemPrintout.Type.BOOK ); - - registry.registerAll( - ComputerCraft.Items.printedPage.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_page" ) ), - ComputerCraft.Items.printedPages.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_pages" ) ), - ComputerCraft.Items.printedBook.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printed_book" ) ) - ); - - // Peripherals - registry.registerAll( - setupItemBlock( new BlockItem( ComputerCraft.Blocks.speaker, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.diskDrive, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.printer, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.monitorNormal, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.monitorAdvanced, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.wirelessModemNormal, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.wirelessModemAdvanced, defaultItem() ) ), - setupItemBlock( new BlockItem( ComputerCraft.Blocks.wiredModemFull, defaultItem() ) ) - ); - - ComputerCraft.Items.cable = new ItemBlockCable.Cable( ComputerCraft.Blocks.cable, defaultItem() ); - ComputerCraft.Items.wiredModem = new ItemBlockCable.WiredModem( ComputerCraft.Blocks.cable, defaultItem() ); - registry.registerAll( - ComputerCraft.Items.cable.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "cable" ) ), - ComputerCraft.Items.wiredModem.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem" ) ) - ); - registerTurtleUpgrades(); registerPocketUpgrades(); } @@ -303,7 +259,7 @@ public final class Registry ComputerCraft.TurtleUpgrades.diamondSword = new TurtleSword( new ResourceLocation( "minecraft", "diamond_sword" ), Items.DIAMOND_SWORD ); ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondSword ); - ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), net.minecraft.item.Items.DIAMOND_SHOVEL ); + ComputerCraft.TurtleUpgrades.diamondShovel = new TurtleShovel( new ResourceLocation( "minecraft", "diamond_shovel" ), Items.DIAMOND_SHOVEL ); ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.diamondShovel ); ComputerCraft.TurtleUpgrades.diamondPickaxe = new TurtleTool( new ResourceLocation( "minecraft", "diamond_pickaxe" ), Items.DIAMOND_PICKAXE ); @@ -323,32 +279,47 @@ public final class Registry ComputerCraftAPI.registerPocketUpgrade( ComputerCraft.PocketUpgrades.speaker = new PocketSpeaker() ); } - @SubscribeEvent - public static void registerEntities( RegistryEvent.Register> registry ) + public static class ModEntities { - registry.getRegistry().register( TurtlePlayer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle_player" ) ) ); + static final DeferredRegister> ENTITIES = new DeferredRegister<>( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID ); + + public static final RegistryObject> TURTLE_PLAYER = ENTITIES.register( "turtle_player", () -> + EntityType.Builder.create( EntityClassification.MISC ) + .disableSerialization() + .disableSummoning() + .size( 0, 0 ) + .build( ComputerCraft.MOD_ID + ":turtle_player" ) ); + } + + public static class ModContainers + { + static final DeferredRegister> CONTAINERS = new DeferredRegister<>( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID ); + + public static final RegistryObject> COMPUTER = CONTAINERS.register( "computer", + () -> ContainerData.toType( ComputerContainerData::new, ContainerComputer::new ) ); + + public static final RegistryObject> POCKET_COMPUTER = CONTAINERS.register( "pocket_computer", + () -> ContainerData.toType( ComputerContainerData::new, ContainerPocketComputer::new ) ); + + public static final RegistryObject> TURTLE = CONTAINERS.register( "turtle", + () -> ContainerData.toType( ComputerContainerData::new, ContainerTurtle::new ) ); + + public static final RegistryObject> DISK_DRIVE = CONTAINERS.register( "disk_drive", + () -> new ContainerType<>( ContainerDiskDrive::new ) ); + + public static final RegistryObject> PRINTER = CONTAINERS.register( "printer", + () -> new ContainerType<>( ContainerPrinter::new ) ); + + public static final RegistryObject> PRINTOUT = CONTAINERS.register( "printout", + () -> ContainerData.toType( HeldItemContainerData::new, ContainerHeldItem::createPrintout ) ); + + public static final RegistryObject> VIEW_COMPUTER = CONTAINERS.register( "view_computer", + () -> ContainerData.toType( ViewComputerContainerData::new, ContainerViewComputer::new ) ); } @SubscribeEvent - public static void registerContainers( RegistryEvent.Register> event ) + public static void registerRecipeSerializers( RegistryEvent.Register> event ) { - event.getRegistry().registerAll( - ContainerComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ), - ContainerPocketComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "pocket_computer" ) ), - ContainerTurtle.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "turtle" ) ), - - ContainerDiskDrive.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ) ), - ContainerPrinter.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printer" ) ), - ContainerHeldItem.PRINTOUT_TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "printout" ) ), - - ContainerViewComputer.TYPE.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "view_computer" ) ) - ); - } - - @SubscribeEvent - public static void regsterRecipeSerializers( RegistryEvent.Register> event ) - { - event.getRegistry().registerAll( ColourableRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "colour" ) ), ComputerUpgradeRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "computer_upgrade" ) ), @@ -361,4 +332,14 @@ public final class Registry ImpostorRecipe.SERIALIZER.setRegistryName( new ResourceLocation( ComputerCraft.MOD_ID, "impostor_shaped" ) ) ); } + + public static void setup() + { + IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); + ModBlocks.BLOCKS.register( bus ); + ModTiles.TILES.register( bus ); + ModItems.ITEMS.register( bus ); + ModEntities.ENTITIES.register( bus ); + ModContainers.CONTAINERS.register( bus ); + } } diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index b7cad192e..d83089b7d 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.shared.common; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; @@ -19,6 +18,7 @@ import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorldReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -26,13 +26,12 @@ import java.util.Random; public abstract class BlockGeneric extends Block { - private final TileEntityType type; + private final RegistryObject> type; - public BlockGeneric( Properties settings, NamedTileEntityType type ) + public BlockGeneric( Properties settings, RegistryObject> type ) { super( settings ); this.type = type; - type.setBlock( this ); } @Override @@ -89,7 +88,7 @@ public abstract class BlockGeneric extends Block @Override public TileEntity createTileEntity( @Nonnull BlockState state, @Nonnull IBlockReader world ) { - return type.create(); + return type.get().create(); } @Override diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index 6300cc0d7..8514a9133 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.shared.common; -import dan200.computercraft.shared.network.container.ContainerData; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.network.container.HeldItemContainerData; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; @@ -21,8 +21,6 @@ import javax.annotation.Nullable; public class ContainerHeldItem extends Container { - public static final ContainerType PRINTOUT_TYPE = ContainerData.toType( HeldItemContainerData::new, ContainerHeldItem::createPrintout ); - private final ItemStack stack; private final Hand hand; @@ -34,9 +32,9 @@ public class ContainerHeldItem extends Container stack = player.getHeldItem( hand ).copy(); } - private static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) + public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data ) { - return new ContainerHeldItem( PRINTOUT_TYPE, id, inventory.player, data.getHand() ); + return new ContainerHeldItem( Registry.ModContainers.PRINTOUT.get(), id, inventory.player, data.getHand() ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index 06b0c0339..e2386f667 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.items.ComputerItemFactory; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.item.BlockItemUseContext; @@ -17,7 +16,9 @@ import net.minecraft.state.DirectionProperty; import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -27,7 +28,7 @@ public class BlockComputer extends BlockComputerBase public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class ); public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public BlockComputer( Properties settings, ComputerFamily family, NamedTileEntityType type ) + public BlockComputer( Properties settings, ComputerFamily family, RegistryObject> type ) { super( settings, family, type ); setDefaultState( getDefaultState() diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 6f768dbbc..0bf82c8e2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -12,13 +12,13 @@ import dan200.computercraft.shared.common.IBundledRedstoneBlock; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.items.IComputerItem; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.BlockState; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.stats.Stats; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -28,6 +28,7 @@ import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import net.minecraft.world.storage.loot.LootContext; import net.minecraft.world.storage.loot.LootParameters; +import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -38,7 +39,7 @@ public abstract class BlockComputerBase extends Bloc private final ComputerFamily family; - protected BlockComputerBase( Properties settings, ComputerFamily family, NamedTileEntityType type ) + protected BlockComputerBase( Properties settings, ComputerFamily family, RegistryObject> type ) { super( settings, type ); this.family = family; @@ -46,7 +47,7 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public void onBlockAdded( BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving ) + public void onBlockAdded( @Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState oldState, boolean isMoving ) { super.onBlockAdded( state, world, pos, oldState, isMoving ); @@ -56,14 +57,14 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public boolean canProvidePower( BlockState state ) + public boolean canProvidePower( @Nonnull BlockState state ) { return true; } @Override @Deprecated - public int getStrongPower( BlockState state, IBlockReader world, BlockPos pos, Direction incomingSide ) + public int getStrongPower( @Nonnull BlockState state, IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) { TileEntity entity = world.getTileEntity( pos ); if( !(entity instanceof TileComputerBase) ) return 0; @@ -86,7 +87,7 @@ public abstract class BlockComputerBase extends Bloc @Override @Deprecated - public int getWeakPower( BlockState state, IBlockReader world, BlockPos pos, Direction incomingSide ) + public int getWeakPower( @Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide ) { return getStrongPower( state, world, pos, incomingSide ); } @@ -126,7 +127,7 @@ public abstract class BlockComputerBase extends Bloc } @Override - public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, BlockState state, @Nullable TileEntity tile, @Nonnull ItemStack tool ) + public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity tile, @Nonnull ItemStack tool ) { // Don't drop blocks here - see onBlockHarvested. player.addStat( Stats.BLOCK_MINED.get( this ) ); @@ -134,7 +135,7 @@ public abstract class BlockComputerBase extends Bloc } @Override - public void onBlockHarvested( World world, @Nonnull BlockPos pos, BlockState state, @Nonnull PlayerEntity player ) + public void onBlockHarvested( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player ) { if( !(world instanceof ServerWorld) ) return; @@ -162,7 +163,7 @@ public abstract class BlockComputerBase extends Bloc } @Override - public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) + public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack ) { super.onBlockPlacedBy( world, pos, state, placer, stack ); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index bfd7bfd52..20d542463 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -9,13 +9,11 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.apis.CommandAPI; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.command.CommandSource; import net.minecraft.command.ICommandSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.ITextComponent; @@ -30,11 +28,6 @@ import java.util.Map; public class TileCommandComputer extends TileComputer { - public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "command_computer" ), - f -> new TileCommandComputer( ComputerFamily.COMMAND, f ) - ); - public class CommandReceiver implements ICommandSource { private final Map output = new HashMap<>(); diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 34a768af3..82d10dea2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -13,14 +13,12 @@ import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.util.CapabilityUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -31,16 +29,6 @@ import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; public class TileComputer extends TileComputerBase { - public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "computer_normal" ), - f -> new TileComputer( ComputerFamily.NORMAL, f ) - ); - - public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "computer_advanced" ), - f -> new TileComputer( ComputerFamily.ADVANCED, f ) - ); - private ComputerProxy proxy; private LazyOptional peripheral; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 9bf2df439..b384810b9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -178,7 +178,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nonnull @Override - public CompoundNBT write( CompoundNBT nbt ) + public CompoundNBT write( @Nonnull CompoundNBT nbt ) { // Save ID, label and power state if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); @@ -189,7 +189,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } @Override - public void read( CompoundNBT nbt ) + public void read( @Nonnull CompoundNBT nbt ) { super.read( nbt ); diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java index 83bb7aff8..9ce948931 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java @@ -5,23 +5,20 @@ */ package dan200.computercraft.shared.computer.inventory; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.network.container.ComputerContainerData; -import dan200.computercraft.shared.network.container.ContainerData; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.container.ContainerType; public class ContainerComputer extends ContainerComputerBase { - public static final ContainerType TYPE = ContainerData.toType( ComputerContainerData::new, ContainerComputer::new ); - public ContainerComputer( int id, TileComputer tile ) { - super( TYPE, id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() ); + super( Registry.ModContainers.COMPUTER.get(), id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() ); } - private ContainerComputer( int id, PlayerInventory player, ComputerContainerData data ) + public ContainerComputer( int id, PlayerInventory player, ComputerContainerData data ) { - super( TYPE, id, player, data ); + super( Registry.ModContainers.COMPUTER.get(), id, player, data ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index 52e532550..699474012 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -74,7 +74,7 @@ public class ContainerComputerBase extends Container implements IContainerComput } @Override - public void onContainerClosed( PlayerEntity player ) + public void onContainerClosed( @Nonnull PlayerEntity player ) { super.onContainerClosed( player ); input.close(); diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index ef8595d11..ccc8b24d9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -6,34 +6,31 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.network.container.ViewComputerContainerData; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.container.ContainerType; import javax.annotation.Nonnull; public class ContainerViewComputer extends ContainerComputerBase implements IContainerComputer { - public static final ContainerType TYPE = ContainerData.toType( ViewComputerContainerData::new, ContainerViewComputer::new ); - private final int width; private final int height; public ContainerViewComputer( int id, ServerComputer computer ) { - super( TYPE, id, player -> canInteractWith( computer, player ), computer, computer.getFamily() ); + super( Registry.ModContainers.VIEW_COMPUTER.get(), id, player -> canInteractWith( computer, player ), computer, computer.getFamily() ); this.width = this.height = 0; } public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data ) { - super( TYPE, id, player, data ); + super( Registry.ModContainers.VIEW_COMPUTER.get(), id, player, data ); this.width = data.getWidth(); this.height = data.getHeight(); } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index 9cf4465e7..3be415994 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.shared.computer.items; -import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.blocks.TileComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.item.ItemStack; @@ -28,11 +28,11 @@ public final class ComputerItemFactory switch( family ) { case NORMAL: - return ComputerCraft.Items.computerNormal.create( id, label ); + return Registry.ModItems.COMPUTER_NORMAL.get().create( id, label ); case ADVANCED: - return ComputerCraft.Items.computerAdvanced.create( id, label ); + return Registry.ModItems.COMPUTER_ADVANCED.get().create( id, label ); case COMMAND: - return ComputerCraft.Items.computerCommand.create( id, label ); + return Registry.ModItems.COMPUTER_COMMAND.get().create( id, label ); default: return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index d368ed7b9..c7d99cebb 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -10,6 +10,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.PocketUpgrades; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.media.items.ItemDisk; @@ -51,13 +52,13 @@ public class JEIComputerCraft implements IModPlugin @Override public void registerItemSubtypes( ISubtypeRegistration subtypeRegistry ) { - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleNormal, turtleSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.turtleAdvanced, turtleSubtype ); + subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.TURTLE_NORMAL.get(), turtleSubtype ); + subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.TURTLE_ADVANCED.get(), turtleSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.pocketComputerNormal, pocketSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.pocketComputerAdvanced, pocketSubtype ); + subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.POCKET_COMPUTER_NORMAL.get(), pocketSubtype ); + subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(), pocketSubtype ); - subtypeRegistry.registerSubtypeInterpreter( ComputerCraft.Items.disk, diskSubtype ); + subtypeRegistry.registerSubtypeInterpreter( Registry.ModItems.DISK.get(), diskSubtype ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 0c670ed81..6ef877402 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -9,6 +9,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.util.ITooltipFlag; @@ -42,9 +43,9 @@ public class ItemDisk extends Item implements IMedia, IColouredItem @Nonnull public static ItemStack createFromIDAndColour( int id, String label, int colour ) { - ItemStack stack = new ItemStack( ComputerCraft.Items.disk ); + ItemStack stack = new ItemStack( Registry.ModItems.DISK.get() ); setDiskID( stack, id ); - ComputerCraft.Items.disk.setLabel( stack, label ); + Registry.ModItems.DISK.get().setLabel( stack, label ); IColouredItem.setColourBasic( stack, colour ); return stack; } @@ -60,7 +61,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem } @Override - public void addInformation( ItemStack stack, @Nullable World world, List list, ITooltipFlag options ) + public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, ITooltipFlag options ) { if( options.isAdvanced() ) { diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index ad3a64874..d34d4a897 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.shared.media.items; -import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.ContainerHeldItem; import dan200.computercraft.shared.network.container.HeldItemContainerData; import net.minecraft.client.util.ITooltipFlag; @@ -50,7 +50,7 @@ public class ItemPrintout extends Item } @Override - public void addInformation( @Nonnull ItemStack stack, World world, List list, ITooltipFlag options ) + public void addInformation( @Nonnull ItemStack stack, World world, @Nonnull List list, @Nonnull ITooltipFlag options ) { String title = getTitle( stack ); if( title != null && !title.isEmpty() ) list.add( new StringTextComponent( title ) ); @@ -58,12 +58,12 @@ public class ItemPrintout extends Item @Nonnull @Override - public ActionResult onItemRightClick( World world, PlayerEntity player, @Nonnull Hand hand ) + public ActionResult onItemRightClick( World world, @Nonnull PlayerEntity player, @Nonnull Hand hand ) { if( !world.isRemote ) { new HeldItemContainerData( hand ) - .open( player, new ContainerHeldItem.Factory( ContainerHeldItem.PRINTOUT_TYPE, player.getHeldItem( hand ), hand ) ); + .open( player, new ContainerHeldItem.Factory( Registry.ModContainers.PRINTOUT.get(), player.getHeldItem( hand ), hand ) ); } return new ActionResult<>( ActionResultType.SUCCESS, player.getHeldItem( hand ) ); } @@ -100,19 +100,19 @@ public class ItemPrintout extends Item @Nonnull public static ItemStack createSingleFromTitleAndText( String title, String[] text, String[] colours ) { - return ComputerCraft.Items.printedPage.createFromTitleAndText( title, text, colours ); + return Registry.ModItems.PRINTED_PAGE.get().createFromTitleAndText( title, text, colours ); } @Nonnull public static ItemStack createMultipleFromTitleAndText( String title, String[] text, String[] colours ) { - return ComputerCraft.Items.printedPages.createFromTitleAndText( title, text, colours ); + return Registry.ModItems.PRINTED_PAGES.get().createFromTitleAndText( title, text, colours ); } @Nonnull public static ItemStack createBookFromTitleAndText( String title, String[] text, String[] colours ) { - return ComputerCraft.Items.printedBook.createFromTitleAndText( title, text, colours ); + return Registry.ModItems.PRINTED_BOOK.get().createFromTitleAndText( title, text, colours ); } public Type getType() diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index c284e7fff..345f36e68 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -5,11 +5,11 @@ */ package dan200.computercraft.shared.media.items; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.core.filesystem.SubMount; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.player.PlayerEntity; @@ -46,7 +46,7 @@ public class ItemTreasureDisk extends Item implements IMedia } @Override - public void addInformation( ItemStack stack, @Nullable World world, List list, ITooltipFlag tooltipOptions ) + public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag tooltipOptions ) { String label = getTitle( stack ); if( !label.isEmpty() ) list.add( new StringTextComponent( label ) ); @@ -92,7 +92,7 @@ public class ItemTreasureDisk extends Item implements IMedia public static ItemStack create( String subPath, int colourIndex ) { - ItemStack result = new ItemStack( ComputerCraft.Items.treasureDisk ); + ItemStack result = new ItemStack( Registry.ModItems.TREASURE_DISK.get() ); CompoundNBT nbt = result.getOrCreateTag(); nbt.putString( NBT_SUB_PATH, subPath ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java index c87d1ba50..17104f9ec 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.peripheral.diskdrive; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -33,7 +34,7 @@ public class BlockDiskDrive extends BlockGeneric public BlockDiskDrive( Properties settings ) { - super( settings, TileDiskDrive.FACTORY ); + super( settings, Registry.ModTiles.DISK_DRIVE ); setDefaultState( getStateContainer().getBaseState() .with( FACING, Direction.NORTH ) .with( STATE, DiskDriveState.EMPTY ) ); @@ -54,7 +55,7 @@ public class BlockDiskDrive extends BlockGeneric } @Override - public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, ItemStack stack ) + public void harvestBlock( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack ) { if( te instanceof INameable && ((INameable) te).hasCustomName() ) { @@ -72,7 +73,7 @@ public class BlockDiskDrive extends BlockGeneric } @Override - public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) + public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack ) { if( stack.hasDisplayName() ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index ee43ebb4f..88725bdfa 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -5,12 +5,12 @@ */ package dan200.computercraft.shared.peripheral.diskdrive; +import dan200.computercraft.shared.Registry; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Inventory; import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; @@ -18,13 +18,11 @@ import javax.annotation.Nonnull; public class ContainerDiskDrive extends Container { - public static final ContainerType TYPE = new ContainerType<>( ContainerDiskDrive::new ); - private final IInventory inventory; public ContainerDiskDrive( int id, PlayerInventory player, IInventory inventory ) { - super( TYPE, id ); + super( Registry.ModContainers.DISK_DRIVE.get(), id ); this.inventory = inventory; @@ -44,7 +42,7 @@ public class ContainerDiskDrive extends Container } } - private ContainerDiskDrive( int id, PlayerInventory player ) + public ContainerDiskDrive( int id, PlayerInventory player ) { this( id, player, new Inventory( 1 ) ); } @@ -57,7 +55,7 @@ public class ContainerDiskDrive extends Container @Nonnull @Override - public ItemStack transferStackInSlot( PlayerEntity player, int slotIndex ) + public ItemStack transferStackInSlot( @Nonnull PlayerEntity player, int slotIndex ) { Slot slot = inventorySlots.get( slotIndex ); if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index fbbfc4bef..8e53b02b4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.shared.peripheral.diskdrive; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.media.IMedia; @@ -13,7 +12,10 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.util.*; +import dan200.computercraft.shared.util.CapabilityUtil; +import dan200.computercraft.shared.util.DefaultInventory; +import dan200.computercraft.shared.util.InventoryUtil; +import dan200.computercraft.shared.util.RecordUtil; import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; @@ -24,6 +26,7 @@ import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; @@ -49,11 +52,6 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private static final String NBT_NAME = "CustomName"; private static final String NBT_ITEM = "Item"; - public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "disk_drive" ), - TileDiskDrive::new - ); - private static class MountInfo { String mountPath; @@ -74,9 +72,9 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private boolean m_restartRecord = false; private boolean m_ejectQueued; - private TileDiskDrive() + public TileDiskDrive( TileEntityType type ) { - super( FACTORY ); + super( type ); } @Override @@ -124,7 +122,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public void read( CompoundNBT nbt ) + public void read( @Nonnull CompoundNBT nbt ) { super.read( nbt ); customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; @@ -138,7 +136,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Nonnull @Override - public CompoundNBT write( CompoundNBT nbt ) + public CompoundNBT write( @Nonnull CompoundNBT nbt ) { if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 530b81bda..3bdbfee7a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.collect.ImmutableMap; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; @@ -61,7 +61,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable public BlockCable( Properties settings ) { - super( settings, TileCable.FACTORY ); + super( settings, Registry.ModTiles.CABLE ); setDefaultState( getStateContainer().getBaseState() .with( MODEM, CableModemVariant.None ) @@ -94,7 +94,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public VoxelShape getShape( BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context ) + public VoxelShape getShape( @Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context ) { return CableShapes.getShape( state ); } @@ -121,12 +121,12 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) ) { newState = state.with( MODEM, CableModemVariant.None ); - item = new ItemStack( ComputerCraft.Items.wiredModem ); + item = new ItemStack( Registry.ModItems.WIRED_MODEM.get() ); } else { newState = state.with( CABLE, false ); - item = new ItemStack( ComputerCraft.Items.cable ); + item = new ItemStack( Registry.ModItems.CABLE.get() ); } world.setBlockState( pos, correctConnections( world, pos, newState ), 3 ); @@ -154,18 +154,18 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable boolean cable = state.get( CABLE ); // If we've only got one, just use that. - if( !cable ) return new ItemStack( ComputerCraft.Items.wiredModem ); - if( modem == null ) return new ItemStack( ComputerCraft.Items.cable ); + if( !cable ) return new ItemStack( Registry.ModItems.WIRED_MODEM.get() ); + if( modem == null ) return new ItemStack( Registry.ModItems.CABLE.get() ); // We've a modem and cable, so try to work out which one we're interacting with return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) - ? new ItemStack( ComputerCraft.Items.wiredModem ) - : new ItemStack( ComputerCraft.Items.cable ); + ? new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) + : new ItemStack( Registry.ModItems.CABLE.get() ); } @Override - public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) + public void onBlockPlacedBy( World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack ) { TileEntity tile = world.getTileEntity( pos ); if( tile instanceof TileCable ) @@ -180,7 +180,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public IFluidState getFluidState( BlockState state ) + public IFluidState getFluidState( @Nonnull BlockState state ) { return getWaterloggedFluidState( state ); } @@ -188,7 +188,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public BlockState updatePostPlacement( @Nonnull BlockState state, Direction side, BlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + public BlockState updatePostPlacement( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); // Should never happen, but handle the case where we've no modem or cable. @@ -202,7 +202,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable @Override @Deprecated - public boolean isValidPosition( BlockState state, IWorldReader world, BlockPos pos ) + public boolean isValidPosition( BlockState state, @Nonnull IWorldReader world, @Nonnull BlockPos pos ) { Direction facing = state.get( MODEM ).getFacing(); if( facing == null ) return true; @@ -214,7 +214,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable @Nullable @Override - public BlockState getStateForPlacement( BlockItemUseContext context ) + public BlockState getStateForPlacement( @Nonnull BlockItemUseContext context ) { BlockState state = getDefaultState() .with( WATERLOGGED, getWaterloggedStateForPlacement( context ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index 6b8407e25..63408e7d6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.peripheral.modem.wired; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -18,7 +19,7 @@ public class BlockWiredModemFull extends BlockGeneric public BlockWiredModemFull( Properties settings ) { - super( settings, TileWiredModemFull.FACTORY ); + super( settings, Registry.ModTiles.WIRED_MODEM_FULL ); setDefaultState( getStateContainer().getBaseState() .with( MODEM_ON, false ) .with( PERIPHERAL_ON, false ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java index c8c985e96..d1591bd18 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.shared.peripheral.modem.wired; -import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import net.minecraft.block.BlockState; import net.minecraft.block.SoundType; import net.minecraft.entity.player.PlayerEntity; @@ -93,7 +93,7 @@ public abstract class ItemBlockCable extends BlockItem BlockState existingState = world.getBlockState( pos ); // Try to add a modem to a cable - if( existingState.getBlock() == ComputerCraft.Blocks.cable && existingState.get( MODEM ) == CableModemVariant.None ) + if( existingState.getBlock() == Registry.ModBlocks.CABLE.get() && existingState.get( MODEM ) == CableModemVariant.None ) { Direction side = context.getFace().getOpposite(); BlockState newState = existingState @@ -130,7 +130,7 @@ public abstract class ItemBlockCable extends BlockItem // Try to add a cable to a modem inside the block we're clicking on. BlockPos insidePos = pos.offset( context.getFace().getOpposite() ); BlockState insideState = world.getBlockState( insidePos ); - if( insideState.getBlock() == ComputerCraft.Blocks.cable && !insideState.get( BlockCable.CABLE ) + if( insideState.getBlock() == Registry.ModBlocks.CABLE.get() && !insideState.get( BlockCable.CABLE ) && placeAtCorrected( world, insidePos, insideState.with( BlockCable.CABLE, true ) ) ) { stack.shrink( 1 ); @@ -139,7 +139,7 @@ public abstract class ItemBlockCable extends BlockItem // Try to add a cable to a modem adjacent to this block BlockState existingState = world.getBlockState( pos ); - if( existingState.getBlock() == ComputerCraft.Blocks.cable && !existingState.get( BlockCable.CABLE ) + if( existingState.getBlock() == Registry.ModBlocks.CABLE.get() && !existingState.get( BlockCable.CABLE ) && placeAtCorrected( world, pos, existingState.with( BlockCable.CABLE, true ) ) ) { stack.shrink( 1 ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 1844bb405..7d548ec5a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -6,27 +6,26 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.DirectionUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; @@ -46,11 +45,6 @@ import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT; public class TileCable extends TileGeneric { - public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "cable" ), - TileCable::new - ); - private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess"; private class CableElement extends WiredModemElement @@ -126,9 +120,9 @@ public class TileCable extends TileGeneric private final NonNullConsumer> connectedNodeChanged = x -> connectionsChanged(); - public TileCable() + public TileCable( TileEntityType type ) { - super( FACTORY ); + super( type ); } private void onRemove() @@ -219,7 +213,7 @@ public class TileCable extends TileGeneric if( hasCable() ) { // Drop the modem and convert to cable - Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( ComputerCraft.Items.wiredModem ) ); + Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) ); getWorld().setBlockState( getPos(), getBlockState().with( BlockCable.MODEM, CableModemVariant.None ) ); modemChanged(); connectionsChanged(); @@ -227,7 +221,7 @@ public class TileCable extends TileGeneric else { // Drop everything and remove block - Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( ComputerCraft.Items.wiredModem ) ); + Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) ); getWorld().removeBlock( getPos(), false ); // This'll call #destroy(), so we don't need to reset the network here. } @@ -287,7 +281,7 @@ public class TileCable extends TileGeneric } @Override - public void read( CompoundNBT nbt ) + public void read( @Nonnull CompoundNBT nbt ) { super.read( nbt ); m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 054da8aad..349cb6d28 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.peripheral.modem.wired; import com.google.common.base.Objects; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; @@ -14,14 +13,17 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; -import dan200.computercraft.shared.util.*; +import dan200.computercraft.shared.util.CapabilityUtil; +import dan200.computercraft.shared.util.DirectionUtil; +import dan200.computercraft.shared.util.SidedCaps; +import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; @@ -43,11 +45,6 @@ import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModem public class TileWiredModemFull extends TileGeneric { - public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full" ), - TileWiredModemFull::new - ); - private static final String NBT_PERIPHERAL_ENABLED = "PeripheralAccess"; private static final class FullElement extends WiredModemElement @@ -111,9 +108,9 @@ public class TileWiredModemFull extends TileGeneric private final NonNullConsumer> connectedNodeChanged = x -> connectionsChanged(); - public TileWiredModemFull() + public TileWiredModemFull( TileEntityType type ) { - super( FACTORY ); + super( type ); for( int i = 0; i < m_peripherals.length; i++ ) { Direction facing = Direction.byIndex( i ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index 9314c4d74..94e5c7ade 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -5,9 +5,9 @@ */ package dan200.computercraft.shared.peripheral.modem.wired; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.Peripherals; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.util.IDAssigner; import net.minecraft.block.Block; import net.minecraft.nbt.CompoundNBT; @@ -144,7 +144,7 @@ public final class WiredModemLocalPeripheral BlockPos offset = pos.offset( direction ); Block block = world.getBlockState( offset ).getBlock(); - if( block == ComputerCraft.Blocks.wiredModemFull || block == ComputerCraft.Blocks.cable ) return null; + if( block == Registry.ModBlocks.WIRED_MODEM_FULL.get() || block == Registry.ModBlocks.CABLE.get() ) return null; IPeripheral peripheral = Peripherals.getPeripheral( world, offset, direction.getOpposite(), invalidate ); return peripheral instanceof WiredModemPeripheral ? null : peripheral; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index 33d0619ac..f95066025 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.shared.common.BlockGeneric; import dan200.computercraft.shared.peripheral.modem.ModemShapes; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.IWaterLoggable; @@ -17,6 +16,7 @@ import net.minecraft.state.BooleanProperty; import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.shapes.ISelectionContext; @@ -24,6 +24,7 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorld; import net.minecraft.world.IWorldReader; +import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -35,7 +36,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable public static final DirectionProperty FACING = BlockStateProperties.FACING; public static final BooleanProperty ON = BooleanProperty.create( "on" ); - public BlockWirelessModem( Properties settings, NamedTileEntityType type ) + public BlockWirelessModem( Properties settings, RegistryObject> type ) { super( settings, type ); setDefaultState( getStateContainer().getBaseState() @@ -53,7 +54,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public VoxelShape getShape( BlockState blockState, IBlockReader blockView, BlockPos blockPos, ISelectionContext context ) + public VoxelShape getShape( BlockState blockState, @Nonnull IBlockReader blockView, @Nonnull BlockPos blockPos, @Nonnull ISelectionContext context ) { return ModemShapes.getBounds( blockState.get( FACING ) ); } @@ -61,7 +62,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public IFluidState getFluidState( BlockState state ) + public IFluidState getFluidState( @Nonnull BlockState state ) { return getWaterloggedFluidState( state ); } @@ -69,7 +70,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public BlockState updatePostPlacement( @Nonnull BlockState state, Direction side, BlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + public BlockState updatePostPlacement( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return side == state.get( FACING ) && !state.isValidPosition( world, pos ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 620c86e5b..d13915afc 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -5,18 +5,15 @@ */ package dan200.computercraft.shared.peripheral.modem.wireless; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.util.CapabilityUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -30,16 +27,6 @@ import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; public class TileWirelessModem extends TileGeneric { - public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ), - f -> new TileWirelessModem( f, false ) - ); - - public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ), - f -> new TileWirelessModem( f, true ) - ); - private static class Peripheral extends WirelessModemPeripheral { private final TileWirelessModem entity; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index c1e5d0ed4..a6df660e4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -6,8 +6,6 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.shared.common.BlockGeneric; -import dan200.computercraft.shared.common.TileGeneric; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.LivingEntity; @@ -18,10 +16,13 @@ import net.minecraft.state.EnumProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.RegistryObject; +import javax.annotation.Nonnull; import javax.annotation.Nullable; public class BlockMonitor extends BlockGeneric @@ -33,7 +34,7 @@ public class BlockMonitor extends BlockGeneric static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class ); - public BlockMonitor( Properties settings, NamedTileEntityType type ) + public BlockMonitor( Properties settings, RegistryObject> type ) { super( settings, type ); // TODO: Test underwater - do we need isSolid at all? @@ -76,7 +77,7 @@ public class BlockMonitor extends BlockGeneric } @Override - public void onBlockPlacedBy( World world, BlockPos pos, BlockState blockState, @Nullable LivingEntity livingEntity, ItemStack itemStack ) + public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, @Nonnull ItemStack itemStack ) { super.onBlockPlacedBy( world, pos, blockState, livingEntity, itemStack ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index b51277910..92603cae8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -13,7 +13,6 @@ import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.util.CapabilityUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; import dan200.computercraft.shared.util.TickScheduler; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; @@ -22,7 +21,6 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; import net.minecraft.util.Hand; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; @@ -39,16 +37,6 @@ import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; public class TileMonitor extends TileGeneric { - public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "monitor_normal" ), - f -> new TileMonitor( f, false ) - ); - - public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "monitor_advanced" ), - f -> new TileMonitor( f, true ) - ); - public static final double RENDER_BORDER = 2.0 / 16.0; public static final double RENDER_MARGIN = 0.5 / 16.0; public static final double RENDER_PIXEL_SCALE = 1.0 / 64.0; @@ -149,7 +137,7 @@ public class TileMonitor extends TileGeneric } @Override - public void read( CompoundNBT tag ) + public void read( @Nonnull CompoundNBT tag ) { super.read( tag ); m_xIndex = tag.getInt( NBT_X ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java index ce6f7fd92..27bb47348 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.peripheral.printer; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -34,7 +35,7 @@ public class BlockPrinter extends BlockGeneric public BlockPrinter( Properties settings ) { - super( settings, TilePrinter.FACTORY ); + super( settings, Registry.ModTiles.PRINTER ); setDefaultState( getStateContainer().getBaseState() .with( FACING, Direction.NORTH ) .with( TOP, false ) @@ -55,7 +56,7 @@ public class BlockPrinter extends BlockGeneric } @Override - public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, ItemStack stack ) + public void harvestBlock( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack ) { if( te instanceof INameable && ((INameable) te).hasCustomName() ) { @@ -73,7 +74,7 @@ public class BlockPrinter extends BlockGeneric } @Override - public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack ) + public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack ) { if( stack.hasDisplayName() ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index e4466a8ed..9f0666645 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -5,13 +5,13 @@ */ package dan200.computercraft.shared.peripheral.printer; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.util.SingleIntArray; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Inventory; import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.Slot; import net.minecraft.item.DyeItem; import net.minecraft.item.ItemStack; @@ -22,14 +22,12 @@ import javax.annotation.Nonnull; public class ContainerPrinter extends Container { - public static final ContainerType TYPE = new ContainerType<>( ContainerPrinter::new ); - private final IInventory inventory; private final IIntArray properties; private ContainerPrinter( int id, PlayerInventory player, IInventory inventory, IIntArray properties ) { - super( TYPE, id ); + super( Registry.ModContainers.PRINTER.get(), id ); this.properties = properties; this.inventory = inventory; @@ -60,7 +58,7 @@ public class ContainerPrinter extends Container } } - private ContainerPrinter( int id, PlayerInventory player ) + public ContainerPrinter( int id, PlayerInventory player ) { this( id, player, new Inventory( TilePrinter.SLOTS ), new IntArray( 1 ) ); } @@ -83,7 +81,7 @@ public class ContainerPrinter extends Container @Nonnull @Override - public ItemStack transferStackInSlot( PlayerEntity player, int index ) + public ItemStack transferStackInSlot( @Nonnull PlayerEntity player, int index ) { Slot slot = inventorySlots.get( index ); if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 65513f569..ac560c8b4 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.shared.peripheral.printer; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.TileGeneric; @@ -20,6 +19,7 @@ import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.*; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.*; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.Vec3d; @@ -40,11 +40,6 @@ import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABI public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, INameable, INamedContainerProvider { - public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "printer" ), - TilePrinter::new - ); - private static final String NBT_NAME = "CustomName"; private static final String NBT_PRINTING = "Printing"; private static final String NBT_PAGE_TITLE = "PageTitle"; @@ -66,9 +61,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private String m_pageTitle = ""; private boolean m_printing = false; - private TilePrinter() + public TilePrinter( TileEntityType type ) { - super( FACTORY ); + super( type ); } @Override @@ -96,7 +91,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } @Override - public void read( CompoundNBT nbt ) + public void read( @Nonnull CompoundNBT nbt ) { super.read( nbt ); @@ -116,7 +111,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nonnull @Override - public CompoundNBT write( CompoundNBT nbt ) + public CompoundNBT write( @Nonnull CompoundNBT nbt ) { if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java index 902e4de47..bcc2b5149 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.shared.peripheral.speaker; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.common.BlockGeneric; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -22,7 +23,7 @@ public class BlockSpeaker extends BlockGeneric public BlockSpeaker( Properties settings ) { - super( settings, TileSpeaker.FACTORY ); + super( settings, Registry.ModTiles.SPEAKER ); setDefaultState( getStateContainer().getBaseState() .with( FACING, Direction.NORTH ) ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 16fb6e5c2..793ef4aad 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -5,14 +5,12 @@ */ package dan200.computercraft.shared.peripheral.speaker; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.util.CapabilityUtil; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; @@ -28,17 +26,12 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity { public static final int MIN_TICKS_BETWEEN_SOUNDS = 1; - public static final NamedTileEntityType FACTORY = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "speaker" ), - TileSpeaker::new - ); - private final SpeakerPeripheral peripheral; private LazyOptional peripheralCap; - public TileSpeaker() + public TileSpeaker( TileEntityType type ) { - super( FACTORY ); + super( type ); peripheral = new Peripheral( this ); } diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java index 5de391f62..25f0151d8 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java @@ -5,15 +5,14 @@ */ package dan200.computercraft.shared.pocket.inventory; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.network.container.ComputerContainerData; -import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; @@ -24,24 +23,21 @@ import javax.annotation.Nullable; public final class ContainerPocketComputer extends ContainerComputerBase { - public static final ContainerType TYPE = ContainerData.toType( ComputerContainerData::new, ContainerPocketComputer::new ); - private ContainerPocketComputer( int id, ServerComputer computer, ItemPocketComputer item, Hand hand ) { - super( TYPE, id, p -> { + super( Registry.ModContainers.POCKET_COMPUTER.get(), id, p -> { ItemStack stack = p.getHeldItem( hand ); return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer; }, computer, item.getFamily() ); } - private ContainerPocketComputer( int id, PlayerInventory player, ComputerContainerData data ) + public ContainerPocketComputer( int id, PlayerInventory player, ComputerContainerData data ) { - super( TYPE, id, player, data ); + super( Registry.ModContainers.POCKET_COMPUTER.get(), id, player, data ); } public static class Factory implements INamedContainerProvider { - private final ServerComputer computer; private final ITextComponent name; private final ItemPocketComputer item; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index bdc5318ed..a6258216a 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -86,7 +86,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I } @Override - public void inventoryTick( ItemStack stack, World world, Entity entity, int slotNum, boolean selected ) + public void inventoryTick( @Nonnull ItemStack stack, World world, @Nonnull Entity entity, int slotNum, boolean selected ) { if( !world.isRemote ) { @@ -182,7 +182,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Override - public void addInformation( @Nonnull ItemStack stack, @Nullable World world, List list, ITooltipFlag flag ) + public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, ITooltipFlag flag ) { if( flag.isAdvanced() || getLabel( stack ) == null ) { diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index 5789b09c3..25b2210d1 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.shared.pocket.items; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.pocket.IPocketUpgrade; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.item.ItemStack; @@ -22,9 +22,9 @@ public final class PocketComputerItemFactory switch( family ) { case NORMAL: - return ComputerCraft.Items.pocketComputerNormal.create( id, label, colour, upgrade ); + return Registry.ModItems.POCKET_COMPUTER_NORMAL.get().create( id, label, colour, upgrade ); case ADVANCED: - return ComputerCraft.Items.pocketComputerAdvanced.create( id, label, colour, upgrade ); + return Registry.ModItems.POCKET_COMPUTER_ADVANCED.get().create( id, label, colour, upgrade ); default: return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index 4d508a361..d8b626198 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -5,10 +5,10 @@ */ package dan200.computercraft.shared.pocket.peripherals; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.peripheral.modem.ModemState; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; @@ -25,8 +25,8 @@ public class PocketModem extends AbstractPocketUpgrade super( new ResourceLocation( "computercraft", advanced ? "wireless_modem_advanced" : "wireless_modem_normal" ), advanced - ? ComputerCraft.Blocks.wirelessModemAdvanced - : ComputerCraft.Blocks.wirelessModemNormal + ? Registry.ModBlocks.WIRELESS_MODEM_ADVANCED + : Registry.ModBlocks.WIRELESS_MODEM_NORMAL ); this.advanced = advanced; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index 4a3ea0dc8..84ed6d85d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -5,10 +5,10 @@ */ package dan200.computercraft.shared.pocket.peripherals; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.pocket.AbstractPocketUpgrade; import dan200.computercraft.api.pocket.IPocketAccess; +import dan200.computercraft.shared.Registry; import net.minecraft.entity.Entity; import net.minecraft.util.ResourceLocation; @@ -19,7 +19,7 @@ public class PocketSpeaker extends AbstractPocketUpgrade { public PocketSpeaker() { - super( new ResourceLocation( "computercraft", "speaker" ), ComputerCraft.Blocks.speaker ); + super( new ResourceLocation( "computercraft", "speaker" ), Registry.ModBlocks.SPEAKER ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 4db44703d..6c1eb4871 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -12,7 +12,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import dan200.computercraft.shared.util.NamedTileEntityType; import net.minecraft.block.Block; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; @@ -28,6 +27,7 @@ import net.minecraft.state.DirectionProperty; import net.minecraft.state.StateContainer; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; @@ -36,6 +36,7 @@ import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.world.*; +import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -52,7 +53,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater 0.875, 0.875, 0.875 ); - public BlockTurtle( Properties settings, ComputerFamily family, NamedTileEntityType type ) + public BlockTurtle( Properties settings, ComputerFamily family, RegistryObject> type ) { super( settings, family, type ); setDefaultState( getStateContainer().getBaseState() @@ -70,7 +71,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater @Nonnull @Override @Deprecated - public BlockRenderType getRenderType( BlockState state ) + public BlockRenderType getRenderType( @Nonnull BlockState state ) { return BlockRenderType.ENTITYBLOCK_ANIMATED; } @@ -78,7 +79,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater @Nonnull @Override @Deprecated - public VoxelShape getShape( BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context ) + public VoxelShape getShape( @Nonnull BlockState state, IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context ) { TileEntity tile = world.getTileEntity( pos ); Vec3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3d.ZERO; @@ -97,7 +98,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater @Nonnull @Override @Deprecated - public IFluidState getFluidState( BlockState state ) + public IFluidState getFluidState( @Nonnull BlockState state ) { return getWaterloggedFluidState( state ); } @@ -105,14 +106,14 @@ public class BlockTurtle extends BlockComputerBase implements IWater @Nonnull @Override @Deprecated - public BlockState updatePostPlacement( @Nonnull BlockState state, Direction side, BlockState otherState, IWorld world, BlockPos pos, BlockPos otherPos ) + public BlockState updatePostPlacement( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos ) { updateWaterloggedPostPlacement( state, world, pos ); return state; } @Override - public void onBlockPlacedBy( World world, BlockPos pos, BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack ) + public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack ) { super.onBlockPlacedBy( world, pos, state, player, stack ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 7954d83c2..bb7feed4a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -56,16 +56,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public static final int INVENTORY_WIDTH = 4; public static final int INVENTORY_HEIGHT = 4; - public static final NamedTileEntityType FACTORY_NORMAL = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "turtle_normal" ), - type -> new TileTurtle( type, ComputerFamily.NORMAL ) - ); - - public static final NamedTileEntityType FACTORY_ADVANCED = NamedTileEntityType.create( - new ResourceLocation( ComputerCraft.MOD_ID, "turtle_advanced" ), - type -> new TileTurtle( type, ComputerFamily.ADVANCED ) - ); - enum MoveState { NOT_MOVED, @@ -266,7 +256,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - public void read( CompoundNBT nbt ) + public void read( @Nonnull CompoundNBT nbt ) { super.read( nbt ); @@ -291,7 +281,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Nonnull @Override - public CompoundNBT write( CompoundNBT nbt ) + public CompoundNBT write( @Nonnull CompoundNBT nbt ) { // Write inventory ListNBT nbttaglist = new ListNBT(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 082a5b1c0..a9480bc40 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -8,10 +8,14 @@ package dan200.computercraft.shared.turtle.core; import com.mojang.authlib.GameProfile; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.util.FakeNetHandler; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; -import net.minecraft.entity.*; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntitySize; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.Pose; import net.minecraft.entity.passive.horse.AbstractHorseEntity; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.INamedContainerProvider; @@ -37,12 +41,6 @@ public final class TurtlePlayer extends FakePlayer "[ComputerCraft]" ); - public static final EntityType TYPE = EntityType.Builder.create( EntityClassification.MISC ) - .disableSerialization() - .disableSummoning() - .size( 0, 0 ) - .build( ComputerCraft.MOD_ID + ":turtle_player" ); - private TurtlePlayer( ITurtleAccess turtle ) { super( (ServerWorld) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); @@ -129,7 +127,7 @@ public final class TurtlePlayer extends FakePlayer @Override public EntityType getType() { - return TYPE; + return Registry.ModEntities.TURTLE_PLAYER.get(); } @Override @@ -145,7 +143,7 @@ public final class TurtlePlayer extends FakePlayer } @Override - public float getStandingEyeHeight( Pose pose, EntitySize size ) + public float getStandingEyeHeight( @Nonnull Pose pose, @Nonnull EntitySize size ) { return 0; } @@ -180,17 +178,17 @@ public final class TurtlePlayer extends FakePlayer } @Override - public void openSignEditor( SignTileEntity signTile ) + public void openSignEditor( @Nonnull SignTileEntity signTile ) { } @Override - public void openHorseInventory( AbstractHorseEntity horse, IInventory inventory ) + public void openHorseInventory( @Nonnull AbstractHorseEntity horse, @Nonnull IInventory inventory ) { } @Override - public void openBook( ItemStack stack, @Nonnull Hand hand ) + public void openBook( @Nonnull ItemStack stack, @Nonnull Hand hand ) { } @@ -205,17 +203,17 @@ public final class TurtlePlayer extends FakePlayer } @Override - protected void onNewPotionEffect( EffectInstance id ) + protected void onNewPotionEffect( @Nonnull EffectInstance id ) { } @Override - protected void onChangedPotionEffect( EffectInstance id, boolean apply ) + protected void onChangedPotionEffect( @Nonnull EffectInstance id, boolean apply ) { } @Override - protected void onFinishedPotionEffect( EffectInstance effect ) + protected void onFinishedPotionEffect( @Nonnull EffectInstance effect ) { } //endregion diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index e33a59707..f5d2c7054 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -5,11 +5,11 @@ */ package dan200.computercraft.shared.turtle.inventory; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.network.container.ComputerContainerData; -import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.util.SingleIntArray; @@ -17,7 +17,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Inventory; -import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; import net.minecraft.util.IIntArray; @@ -28,8 +27,6 @@ import java.util.function.Predicate; public class ContainerTurtle extends ContainerComputerBase { - public static final ContainerType TYPE = ContainerData.toType( ComputerContainerData::new, ContainerTurtle::new ); - public static final int PLAYER_START_Y = 134; public static final int TURTLE_START_X = 175; @@ -40,7 +37,7 @@ public class ContainerTurtle extends ContainerComputerBase PlayerInventory playerInventory, IInventory inventory, IIntArray properties ) { - super( TYPE, id, canUse, computer, family ); + super( Registry.ModContainers.TURTLE.get(), id, canUse, computer, family ); this.properties = properties; trackIntArray( properties ); @@ -78,7 +75,7 @@ public class ContainerTurtle extends ContainerComputerBase ); } - private ContainerTurtle( int id, PlayerInventory player, ComputerContainerData data ) + public ContainerTurtle( int id, PlayerInventory player, ComputerContainerData data ) { this( id, x -> true, getComputer( player, data ), data.getFamily(), @@ -128,7 +125,7 @@ public class ContainerTurtle extends ContainerComputerBase @Nonnull @Override - public ItemStack transferStackInSlot( PlayerEntity player, int slotNum ) + public ItemStack transferStackInSlot( @Nonnull PlayerEntity player, int slotNum ) { if( slotNum >= 0 && slotNum < 16 ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index 8370e7066..cb472937e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -5,10 +5,10 @@ */ package dan200.computercraft.shared.turtle.items; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.ITurtleTile; import net.minecraft.item.ItemStack; @@ -38,9 +38,9 @@ public final class TurtleItemFactory switch( family ) { case NORMAL: - return ComputerCraft.Items.turtleNormal.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); + return Registry.ModItems.TURTLE_NORMAL.get().create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); case ADVANCED: - return ComputerCraft.Items.turtleAdvanced.create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); + return Registry.ModItems.TURTLE_ADVANCED.get().create( id, label, colour, leftUpgrade, rightUpgrade, fuelLevel, overlay ); default: return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 3acee621c..8e01c80b2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -206,7 +206,7 @@ public class TurtleInventoryCrafting extends CraftingInventory } @Override - public boolean isUsableByPlayer( PlayerEntity player ) + public boolean isUsableByPlayer( @Nonnull PlayerEntity player ) { return true; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 15aae7ceb..4632d5db9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -5,10 +5,10 @@ */ package dan200.computercraft.shared.turtle.upgrades; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.*; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; import net.minecraft.client.renderer.model.ModelResourceLocation; @@ -61,7 +61,7 @@ public class TurtleModem extends AbstractTurtleUpgrade } } - private boolean advanced; + private final boolean advanced; @OnlyIn( Dist.CLIENT ) private ModelResourceLocation m_leftOffModel; @@ -80,8 +80,8 @@ public class TurtleModem extends AbstractTurtleUpgrade super( id, TurtleUpgradeType.PERIPHERAL, advanced - ? ComputerCraft.Blocks.wirelessModemAdvanced - : ComputerCraft.Blocks.wirelessModemNormal + ? Registry.ModBlocks.WIRELESS_MODEM_ADVANCED + : Registry.ModBlocks.WIRELESS_MODEM_NORMAL ); this.advanced = advanced; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 35bd70886..0a605660e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -6,13 +6,13 @@ package dan200.computercraft.shared.turtle.upgrades; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.AbstractTurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleUpgradeType; +import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.util.ResourceLocation; @@ -63,7 +63,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade public TurtleSpeaker( ResourceLocation id ) { - super( id, TurtleUpgradeType.PERIPHERAL, ComputerCraft.Blocks.speaker ); + super( id, TurtleUpgradeType.PERIPHERAL, Registry.ModBlocks.SPEAKER ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java index c28a2d5ce..19da95ff5 100644 --- a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java +++ b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.Registry; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; @@ -25,6 +26,6 @@ public class CreativeTabMain extends ItemGroup @OnlyIn( Dist.CLIENT ) public ItemStack createIcon() { - return new ItemStack( ComputerCraft.Blocks.computerNormal ); + return new ItemStack( Registry.ModBlocks.COMPUTER_NORMAL.get() ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index 130152587..02fae31ab 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -36,7 +36,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void onDisconnect( ITextComponent reason ) + public void onDisconnect( @Nonnull ITextComponent reason ) { } @@ -51,32 +51,32 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processInput( CInputPacket packet ) + public void processInput( @Nonnull CInputPacket packet ) { } @Override - public void processVehicleMove( CMoveVehiclePacket packet ) + public void processVehicleMove( @Nonnull CMoveVehiclePacket packet ) { } @Override - public void processConfirmTeleport( CConfirmTeleportPacket packet ) + public void processConfirmTeleport( @Nonnull CConfirmTeleportPacket packet ) { } @Override - public void handleRecipeBookUpdate( CRecipeInfoPacket packet ) + public void handleRecipeBookUpdate( @Nonnull CRecipeInfoPacket packet ) { } @Override - public void handleSeenAdvancements( CSeenAdvancementsPacket packet ) + public void handleSeenAdvancements( @Nonnull CSeenAdvancementsPacket packet ) { } @Override - public void processTabComplete( CTabCompletePacket packet ) + public void processTabComplete( @Nonnull CTabCompletePacket packet ) { } @@ -91,7 +91,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processPickItem( CPickItemPacket packet ) + public void processPickItem( @Nonnull CPickItemPacket packet ) { } @@ -116,12 +116,12 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processSelectTrade( CSelectTradePacket packet ) + public void processSelectTrade( @Nonnull CSelectTradePacket packet ) { } @Override - public void processEditBook( CEditBookPacket packet ) + public void processEditBook( @Nonnull CEditBookPacket packet ) { } @@ -136,22 +136,22 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processPlayer( CPlayerPacket packet ) + public void processPlayer( @Nonnull CPlayerPacket packet ) { } @Override - public void processPlayerDigging( CPlayerDiggingPacket packet ) + public void processPlayerDigging( @Nonnull CPlayerDiggingPacket packet ) { } @Override - public void processTryUseItemOnBlock( CPlayerTryUseItemOnBlockPacket packet ) + public void processTryUseItemOnBlock( @Nonnull CPlayerTryUseItemOnBlockPacket packet ) { } @Override - public void processTryUseItem( CPlayerTryUseItemPacket packet ) + public void processTryUseItem( @Nonnull CPlayerTryUseItemPacket packet ) { } @@ -161,7 +161,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void handleResourcePackStatus( CResourcePackStatusPacket packet ) + public void handleResourcePackStatus( @Nonnull CResourcePackStatusPacket packet ) { } @@ -171,7 +171,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processHeldItemChange( CHeldItemChangePacket packet ) + public void processHeldItemChange( @Nonnull CHeldItemChangePacket packet ) { } @@ -181,22 +181,22 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void handleAnimation( CAnimateHandPacket packet ) + public void handleAnimation( @Nonnull CAnimateHandPacket packet ) { } @Override - public void processEntityAction( CEntityActionPacket packet ) + public void processEntityAction( @Nonnull CEntityActionPacket packet ) { } @Override - public void processUseEntity( CUseEntityPacket packet ) + public void processUseEntity( @Nonnull CUseEntityPacket packet ) { } @Override - public void processClientStatus( CClientStatusPacket packet ) + public void processClientStatus( @Nonnull CClientStatusPacket packet ) { } @@ -206,7 +206,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processClickWindow( CClickWindowPacket packet ) + public void processClickWindow( @Nonnull CClickWindowPacket packet ) { } @@ -216,7 +216,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processEnchantItem( CEnchantItemPacket packet ) + public void processEnchantItem( @Nonnull CEnchantItemPacket packet ) { } @@ -226,12 +226,12 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processConfirmTransaction( CConfirmTransactionPacket packet ) + public void processConfirmTransaction( @Nonnull CConfirmTransactionPacket packet ) { } @Override - public void processUpdateSign( CUpdateSignPacket packet ) + public void processUpdateSign( @Nonnull CUpdateSignPacket packet ) { } @@ -241,7 +241,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processPlayerAbilities( CPlayerAbilitiesPacket packet ) + public void processPlayerAbilities( @Nonnull CPlayerAbilitiesPacket packet ) { } @@ -251,7 +251,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void processCustomPayload( CCustomPayloadPacket packet ) + public void processCustomPayload( @Nonnull CCustomPayloadPacket packet ) { } @@ -276,7 +276,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void channelActive( ChannelHandlerContext context ) + public void channelActive( @Nonnull ChannelHandlerContext context ) { } @@ -286,22 +286,22 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void channelInactive( ChannelHandlerContext context ) + public void channelInactive( @Nonnull ChannelHandlerContext context ) { } @Override - public void exceptionCaught( ChannelHandlerContext context, @Nonnull Throwable err ) + public void exceptionCaught( @Nonnull ChannelHandlerContext context, @Nonnull Throwable err ) { } @Override - protected void channelRead0( ChannelHandlerContext context, @Nonnull IPacket packet ) + protected void channelRead0( @Nonnull ChannelHandlerContext context, @Nonnull IPacket packet ) { } @Override - public void setNetHandler( INetHandler handler ) + public void setNetHandler( @Nonnull INetHandler handler ) { this.handler = handler; } @@ -328,7 +328,7 @@ public class FakeNetHandler extends ServerPlayNetHandler } @Override - public void enableEncryption( SecretKey key ) + public void enableEncryption( @Nonnull SecretKey key ) { } diff --git a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java new file mode 100644 index 000000000..c711c256e --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java @@ -0,0 +1,60 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.util; + +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * A {@link TileEntityType} whose supplier uses itself as an argument. + * + * @param The type of the produced tile entity. + */ +public final class FixedPointTileEntityType extends TileEntityType +{ + private final Supplier block; + + private FixedPointTileEntityType( Supplier block, Supplier builder ) + { + super( builder, Collections.emptySet(), null ); + this.block = block; + } + + public static FixedPointTileEntityType create( Supplier block, Function, T> builder ) + { + return new FixedPointSupplier<>( block, builder ).factory; + } + + @Override + public boolean isValidBlock( @Nonnull Block block ) + { + return block == this.block.get(); + } + + private static final class FixedPointSupplier implements Supplier + { + final FixedPointTileEntityType factory; + private final Function, T> builder; + + private FixedPointSupplier( Supplier block, Function, T> builder ) + { + factory = new FixedPointTileEntityType<>( block, this ); + this.builder = builder; + } + + @Override + public T get() + { + return builder.apply( factory ); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index 9eea89d94..d5946f19b 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -38,7 +38,7 @@ public final class ImpostorRecipe extends ShapedRecipe } @Override - public boolean matches( @Nonnull CraftingInventory inv, World world ) + public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) { return false; } diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index 33598472e..5553ef484 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -40,14 +40,14 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe } @Override - public boolean matches( CraftingInventory inv, World world ) + public boolean matches( @Nonnull CraftingInventory inv, @Nonnull World world ) { return false; } @Nonnull @Override - public ItemStack getCraftingResult( CraftingInventory inventory ) + public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory ) { return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java index 98a2523ca..e00616f65 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -58,7 +58,7 @@ public interface InventoryDelegate extends IInventory } @Override - default void setInventorySlotContents( int slot, ItemStack stack ) + default void setInventorySlotContents( int slot, @Nonnull ItemStack stack ) { getInventory().setInventorySlotContents( slot, stack ); } diff --git a/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java deleted file mode 100644 index fed7ca91a..000000000 --- a/src/main/java/dan200/computercraft/shared/util/NamedTileEntityType.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.util; - -import net.minecraft.block.Block; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.ResourceLocation; - -import javax.annotation.Nonnull; -import java.util.Collections; -import java.util.Objects; -import java.util.function.Function; -import java.util.function.Supplier; - -public final class NamedTileEntityType extends TileEntityType -{ - private final ResourceLocation identifier; - private Block block; - - private NamedTileEntityType( ResourceLocation identifier, Supplier supplier ) - { - super( supplier, Collections.emptySet(), null ); - this.identifier = identifier; - setRegistryName( identifier ); - } - - public static NamedTileEntityType create( ResourceLocation identifier, Supplier supplier ) - { - return new NamedTileEntityType<>( identifier, supplier ); - } - - public static NamedTileEntityType create( ResourceLocation identifier, Function, ? extends T> builder ) - { - return new FixedPointSupplier<>( identifier, builder ).factory; - } - - public void setBlock( @Nonnull Block block ) - { - if( this.block != null ) throw new IllegalStateException( "Cannot change block once set" ); - this.block = Objects.requireNonNull( block, "block cannot be null" ); - } - - @Override - public boolean isValidBlock( @Nonnull Block block ) - { - return block == this.block; - } - - public ResourceLocation getId() - { - return identifier; - } - - private static final class FixedPointSupplier implements Supplier - { - final NamedTileEntityType factory; - private final Function, ? extends T> builder; - - private FixedPointSupplier( ResourceLocation identifier, Function, ? extends T> builder ) - { - factory = create( identifier, this ); - this.builder = builder; - } - - @Override - public T get() - { - return builder.apply( factory ); - } - } -} diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index f81cc079f..40772efcd 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -9,6 +9,8 @@ import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.Slot; import net.minecraft.item.ItemStack; +import javax.annotation.Nonnull; + public class ValidatingSlot extends Slot { public ValidatingSlot( IInventory inventoryIn, int index, int xPosition, int yPosition ) @@ -17,7 +19,7 @@ public class ValidatingSlot extends Slot } @Override - public boolean isItemValid( ItemStack stack ) + public boolean isItemValid( @Nonnull ItemStack stack ) { return true; // inventory.isItemValidForSlot( slotNumber, stack ); } diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index dbd74cd06..d483c7d74 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -38,7 +38,7 @@ public final class WorldUtil { @Nonnull @Override - public EntitySize getSize( Pose pose ) + public EntitySize getSize( @Nonnull Pose pose ) { return EntitySize.fixed( 0, 0 ); } From 08181f72d4a770deffed58d501a7877ab065091e Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 27 Jun 2020 10:47:31 +0100 Subject: [PATCH 266/711] Generic peripherals for any tile entities (#478) This exposes a basic peripheral for any tile entity which does not have methods already registered. We currently provide the following methods: - Inventories: size, list, getItemMeta, pushItems, pullItems. - Energy storage: getEnergy, getEnergyCapacity - Fluid tanks: tanks(), pushFluid, pullFluid. These methods are currently experimental - it must be enabled through `experimental.generic_peripherals`. While this is an initial step towards implementing #452, but is by no means complete. --- build.gradle | 3 + .../dan200/computercraft/ComputerCraft.java | 4 +- .../computercraft/core/asm/Generator.java | 94 +++++++--- .../computercraft/core/asm/GenericSource.java | 100 ++++++++++ .../computercraft/core/asm/LuaMethod.java | 6 +- .../computercraft/core/asm/NamedMethod.java | 2 +- .../core/asm/PeripheralMethod.java | 6 +- .../computercraft/core/asm/TaskCallback.java | 16 +- .../dan200/computercraft/shared/Config.java | 15 ++ .../computercraft/shared/Peripherals.java | 3 +- .../peripheral/generic/GenericPeripheral.java | 76 ++++++++ .../generic/GenericPeripheralProvider.java | 72 ++++++++ .../peripheral/generic/SaturatedMethod.java | 59 ++++++ .../peripheral/generic/meta/FluidMeta.java | 24 +++ .../peripheral/generic/meta/ItemMeta.java | 85 +++++++++ .../generic/methods/ArgumentHelpers.java | 66 +++++++ .../generic/methods/EnergyMethods.java | 39 ++++ .../generic/methods/FluidMethods.java | 173 ++++++++++++++++++ .../generic/methods/InventoryMethods.java | 161 ++++++++++++++++ 19 files changed, 960 insertions(+), 44 deletions(-) create mode 100644 src/main/java/dan200/computercraft/core/asm/GenericSource.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java diff --git a/build.gradle b/build.gradle index debd2965b..69b2cb01f 100644 --- a/build.gradle +++ b/build.gradle @@ -105,6 +105,9 @@ dependencies { runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") + compileOnly 'com.google.auto.service:auto-service:1.0-rc7' + annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' + shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index f5e540126..bcac1d468 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -38,8 +38,6 @@ public final class ComputerCraft { public static final String MOD_ID = "computercraft"; - public static final int DATAFIXER_VERSION = 0; - // Configuration options public static final String[] DEFAULT_HTTP_ALLOW = new String[] { "*" }; public static final String[] DEFAULT_HTTP_DENY = new String[] { @@ -93,6 +91,8 @@ public final class ComputerCraft public static boolean turtlesCanPush = true; public static EnumSet turtleDisabledActions = EnumSet.noneOf( TurtleAction.class ); + public static boolean genericPeripheral = false; + public static final int terminalWidth_computer = 51; public static final int terminalHeight_computer = 19; diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java index 801969d0c..0456cc51a 100644 --- a/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -34,7 +34,7 @@ import java.util.function.Function; import static org.objectweb.asm.Opcodes.*; -public class Generator +public final class Generator { private static final AtomicInteger METHOD_ID = new AtomicInteger(); @@ -99,26 +99,28 @@ public class Generator LuaFunction annotation = method.getAnnotation( LuaFunction.class ); if( annotation == null ) continue; + if( Modifier.isStatic( method.getModifiers() ) ) + { + ComputerCraft.log.warn( "LuaFunction method {}.{} should be an instance method.", method.getDeclaringClass(), method.getName() ); + continue; + } + T instance = methodCache.getUnchecked( method ).orElse( null ); if( instance == null ) continue; if( methods == null ) methods = new ArrayList<>(); + addMethod( methods, method, annotation, instance ); + } - if( annotation.mainThread() ) instance = wrap.apply( instance ); + for( GenericSource.GenericMethod method : GenericSource.GenericMethod.all() ) + { + if( !method.target.isAssignableFrom( klass ) ) continue; - String[] names = annotation.value(); - boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); - if( names.length == 0 ) - { - methods.add( new NamedMethod<>( method.getName(), instance, isSimple ) ); - } - else - { - for( String name : names ) - { - methods.add( new NamedMethod<>( name, instance, isSimple ) ); - } - } + T instance = methodCache.getUnchecked( method.method ).orElse( null ); + if( instance == null ) continue; + + if( methods == null ) methods = new ArrayList<>(); + addMethod( methods, method.method, method.annotation, instance ); } if( methods == null ) return Collections.emptyList(); @@ -126,19 +128,40 @@ public class Generator return Collections.unmodifiableList( methods ); } + private void addMethod( List> methods, Method method, LuaFunction annotation, T instance ) + { + if( annotation.mainThread() ) instance = wrap.apply( instance ); + + String[] names = annotation.value(); + boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); + if( names.length == 0 ) + { + methods.add( new NamedMethod<>( method.getName(), instance, isSimple ) ); + } + else + { + for( String name : names ) + { + methods.add( new NamedMethod<>( name, instance, isSimple ) ); + } + } + } + @Nonnull private Optional build( Method method ) { String name = method.getDeclaringClass().getName() + "." + method.getName(); int modifiers = method.getModifiers(); - if( !Modifier.isFinal( modifiers ) ) + + // Instance methods must be final - this prevents them being overridden and potentially exposed twice. + if( !Modifier.isStatic( modifiers ) && !Modifier.isFinal( modifiers ) ) { ComputerCraft.log.warn( "Lua Method {} should be final.", name ); } - if( Modifier.isStatic( modifiers ) || !Modifier.isPublic( modifiers ) ) + if( !Modifier.isPublic( modifiers ) ) { - ComputerCraft.log.error( "Lua Method {} should be a public instance method.", name ); + ComputerCraft.log.error( "Lua Method {} should be a public method.", name ); return Optional.empty(); } @@ -160,10 +183,14 @@ public class Generator } } + // We have some rather ugly handling of static methods in both here and the main generate function. Static methods + // only come from generic sources, so this should be safe. + Class target = Modifier.isStatic( modifiers ) ? method.getParameterTypes()[0] : method.getDeclaringClass(); + try { String className = method.getDeclaringClass().getName() + "$cc$" + method.getName() + METHOD_ID.getAndIncrement(); - byte[] bytes = generate( className, method ); + byte[] bytes = generate( className, target, method ); if( bytes == null ) return Optional.empty(); Class klass = DeclaringClassLoader.INSTANCE.define( className, bytes, method.getDeclaringClass().getProtectionDomain() ); @@ -178,7 +205,7 @@ public class Generator } @Nullable - private byte[] generate( String className, Method method ) + private byte[] generate( String className, Class target, Method method ) { String internalName = className.replace( ".", "/" ); @@ -200,19 +227,27 @@ public class Generator { MethodVisitor mw = cw.visitMethod( ACC_PUBLIC, METHOD_NAME, methodDesc, null, EXCEPTIONS ); mw.visitCode(); - mw.visitVarInsn( ALOAD, 1 ); - mw.visitTypeInsn( CHECKCAST, Type.getInternalName( method.getDeclaringClass() ) ); + + // If we're an instance method, load the this parameter. + if( !Modifier.isStatic( method.getModifiers() ) ) + { + mw.visitVarInsn( ALOAD, 1 ); + mw.visitTypeInsn( CHECKCAST, Type.getInternalName( target ) ); + } int argIndex = 0; for( java.lang.reflect.Type genericArg : method.getGenericParameterTypes() ) { - Boolean loadedArg = loadArg( mw, method, genericArg, argIndex ); + Boolean loadedArg = loadArg( mw, target, method, genericArg, argIndex ); if( loadedArg == null ) return null; if( loadedArg ) argIndex++; } - mw.visitMethodInsn( INVOKEVIRTUAL, Type.getInternalName( method.getDeclaringClass() ), method.getName(), - Type.getMethodDescriptor( method ), false ); + mw.visitMethodInsn( + Modifier.isStatic( method.getModifiers() ) ? INVOKESTATIC : INVOKEVIRTUAL, + Type.getInternalName( method.getDeclaringClass() ), method.getName(), + Type.getMethodDescriptor( method ), false + ); // We allow a reasonable amount of flexibility on the return value's type. Alongside the obvious MethodResult, // we convert basic types into an immediate result. @@ -250,8 +285,15 @@ public class Generator return cw.toByteArray(); } - private Boolean loadArg( MethodVisitor mw, Method method, java.lang.reflect.Type genericArg, int argIndex ) + private Boolean loadArg( MethodVisitor mw, Class target, Method method, java.lang.reflect.Type genericArg, int argIndex ) { + if( genericArg == target ) + { + mw.visitVarInsn( ALOAD, 1 ); + mw.visitTypeInsn( CHECKCAST, Type.getInternalName( target ) ); + return false; + } + Class arg = Reflect.getRawType( method, genericArg, true ); if( arg == null ) return null; diff --git a/src/main/java/dan200/computercraft/core/asm/GenericSource.java b/src/main/java/dan200/computercraft/core/asm/GenericSource.java new file mode 100644 index 000000000..77c4a0ca3 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/GenericSource.java @@ -0,0 +1,100 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.asm; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.ServiceLoader; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +/** + * A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own. + * + * Unlike conventional Lua objects, the annotated methods should be {@code static}, with their target as the first + * parameter. + * + * This is used by the generic peripheral system ({@link GenericPeripheralProvider}) to provide methods for arbitrary + * tile entities. Eventually this'll be be exposed in the public API. Until it is stabilised, it will remain in this + * package - do not use it in external mods! + */ +public interface GenericSource +{ + /** + * A unique identifier for this generic source. This may be used in the future to allow disabling specific sources. + * + * @return This source's identifier. + */ + @Nonnull + ResourceLocation id(); + + /** + * A generic method is a method belonging to a {@link GenericSource} with a known target. + */ + class GenericMethod + { + final Method method; + final LuaFunction annotation; + final Class target; + + private static List cache; + + GenericMethod( Method method, LuaFunction annotation, Class target ) + { + this.method = method; + this.annotation = annotation; + this.target = target; + } + + /** + * Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}. + * + * @return All available generic methods. + */ + static List all() + { + if( cache != null ) return cache; + return cache = StreamSupport + .stream( ServiceLoader.load( GenericSource.class, GenericSource.class.getClassLoader() ).spliterator(), false ) + .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) + .map( method -> { + LuaFunction annotation = method.getAnnotation( LuaFunction.class ); + if( annotation == null ) return null; + + if( !Modifier.isStatic( method.getModifiers() ) ) + { + ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() ); + return null; + } + + Type[] types = method.getGenericParameterTypes(); + if( types.length == 0 ) + { + ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() ); + return null; + } + + Class target = Reflect.getRawType( method, types[0], false ); + if( target == null ) return null; + + return new GenericMethod( method, annotation, target ); + } ) + .filter( Objects::nonNull ) + .collect( Collectors.toList() ); + } + } +} diff --git a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java index 35ad33b76..4bf142903 100644 --- a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java @@ -14,10 +14,8 @@ import java.util.Collections; public interface LuaMethod { Generator GENERATOR = new Generator<>( LuaMethod.class, Collections.singletonList( ILuaContext.class ), - m -> ( target, context, args ) -> { - long id = context.issueMainThreadTask( () -> TaskCallback.checkUnwrap( m.apply( target, context, args ) ) ); - return new TaskCallback( id ).pull; - } ); + m -> ( target, context, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, args ) ) ) + ); IntCache DYNAMIC = new IntCache<>( method -> ( instance, context, args ) -> ((IDynamicLuaObject) instance).callMethod( context, method, args ) diff --git a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java index d7525fc7f..f7d0ffef4 100644 --- a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java @@ -8,7 +8,7 @@ package dan200.computercraft.core.asm; import javax.annotation.Nonnull; -public class NamedMethod +public final class NamedMethod { private final String name; private final T method; diff --git a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java index 637cfb806..f92a988f0 100644 --- a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java @@ -19,10 +19,8 @@ import java.util.Arrays; public interface PeripheralMethod { Generator GENERATOR = new Generator<>( PeripheralMethod.class, Arrays.asList( ILuaContext.class, IComputerAccess.class ), - m -> ( target, context, computer, args ) -> { - long id = context.issueMainThreadTask( () -> TaskCallback.checkUnwrap( m.apply( target, context, computer, args ) ) ); - return new TaskCallback( id ).pull; - } ); + m -> ( target, context, computer, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, computer, args ) ) ) + ); IntCache DYNAMIC = new IntCache<>( method -> ( instance, context, computer, args ) -> ((IDynamicPeripheral) instance).callMethod( computer, context, method, args ) diff --git a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java index 9ea4e67ad..98ca25a88 100644 --- a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java +++ b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java @@ -6,19 +6,17 @@ package dan200.computercraft.core.asm; -import dan200.computercraft.api.lua.ILuaCallback; -import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.lua.*; import javax.annotation.Nonnull; import java.util.Arrays; -class TaskCallback implements ILuaCallback +public final class TaskCallback implements ILuaCallback { - final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); + private final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); private final long task; - TaskCallback( long task ) + private TaskCallback( long task ) { this.task = task; } @@ -55,4 +53,10 @@ class TaskCallback implements ILuaCallback if( result.getCallback() != null ) throw new IllegalStateException( "Cannot return MethodResult currently" ); return result.getResult(); } + + public static MethodResult make( ILuaContext context, ILuaTask func ) throws LuaException + { + long task = context.issueMainThreadTask( func ); + return new TaskCallback( task ).pull; + } } diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 7ccb2b99d..bfa177156 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -73,6 +73,8 @@ public final class Config private static final ConfigValue turtlesCanPush; private static final ConfigValue> turtleDisabledActions; + private static final ConfigValue genericPeripheral; + private static final ConfigValue monitorRenderer; private static final ForgeConfigSpec serverSpec; @@ -260,6 +262,17 @@ public final class Config builder.pop(); } + { + builder.comment( "Options for various experimental features. These are not guaranteed to be stable, and may change or be removed across versions." ); + builder.push( "experimental" ); + + genericPeripheral = builder + .comment( "Attempt to make any existing block (or tile entity) a peripheral.\n" + + "This provides peripheral methods for any inventory, fluid tank or energy storage block. It will" + + "_not_ provide methods which have an existing peripheral provider." ) + .define( "generic_peripherals", false ); + } + serverSpec = builder.build(); Builder clientBuilder = new Builder(); @@ -322,6 +335,8 @@ public final class Config ComputerCraft.turtleDisabledActions.clear(); for( String value : turtleDisabledActions.get() ) ComputerCraft.turtleDisabledActions.add( getAction( value ) ); + ComputerCraft.genericPeripheral = genericPeripheral.get(); + // Client ComputerCraft.monitorRenderer = monitorRenderer.get(); } diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index aae2b9d6d..cc61e4451 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; import dan200.computercraft.shared.util.CapabilityUtil; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; @@ -66,7 +67,7 @@ public final class Peripherals } } - return null; + return CapabilityUtil.unwrap( GenericPeripheralProvider.getPeripheral( world, pos, side ), invalidate ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java new file mode 100644 index 000000000..9970d66cb --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java @@ -0,0 +1,76 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IDynamicPeripheral; +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.List; + +class GenericPeripheral implements IDynamicPeripheral +{ + private final String type; + private final TileEntity tile; + private final List methods; + + GenericPeripheral( TileEntity tile, List methods ) + { + ResourceLocation type = tile.getType().getRegistryName(); + this.tile = tile; + this.type = type == null ? "unknown" : type.toString(); + this.methods = methods; + } + + @Nonnull + @Override + public String[] getMethodNames() + { + String[] names = new String[methods.size()]; + for( int i = 0; i < methods.size(); i++ ) names[i] = methods.get( i ).getName(); + return names; + } + + @Nonnull + @Override + public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) throws LuaException + { + return methods.get( method ).apply( context, computer, arguments ); + } + + @Nonnull + @Override + public String getType() + { + return type; + } + + @Nullable + @Override + public Object getTarget() + { + return tile; + } + + @Override + public boolean equals( @Nullable IPeripheral other ) + { + if( other == this ) return true; + if( !(other instanceof GenericPeripheral) ) return false; + + GenericPeripheral generic = (GenericPeripheral) other; + return tile == generic.tile && methods.equals( generic.methods ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java new file mode 100644 index 000000000..09041c4f8 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -0,0 +1,72 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.asm.NamedMethod; +import dan200.computercraft.core.asm.PeripheralMethod; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.energy.CapabilityEnergy; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.items.CapabilityItemHandler; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.List; + +public class GenericPeripheralProvider +{ + private static final Capability[] CAPABILITIES = new Capability[] { + CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, + CapabilityEnergy.ENERGY, + CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, + }; + + @Nonnull + public static LazyOptional getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + { + if( !ComputerCraft.genericPeripheral ) return LazyOptional.empty(); + + TileEntity tile = world.getTileEntity( pos ); + if( tile == null ) return LazyOptional.empty(); + + ArrayList saturated = new ArrayList<>( 0 ); + LazyOptional peripheral = LazyOptional.of( () -> new GenericPeripheral( tile, saturated ) ); + + List> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() ); + if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods ); + + for( Capability capability : CAPABILITIES ) + { + LazyOptional wrapper = tile.getCapability( capability ); + wrapper.ifPresent( contents -> { + List> capabilityMethods = PeripheralMethod.GENERATOR.getMethods( contents.getClass() ); + if( capabilityMethods.isEmpty() ) return; + + addSaturated( saturated, contents, capabilityMethods ); + wrapper.addListener( x -> peripheral.invalidate() ); + } ); + } + + return saturated.isEmpty() ? LazyOptional.empty() : peripheral; + } + + private static void addSaturated( ArrayList saturated, Object target, List> methods ) + { + saturated.ensureCapacity( saturated.size() + methods.size() ); + for( NamedMethod method : methods ) + { + saturated.add( new SaturatedMethod( target, method ) ); + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java new file mode 100644 index 000000000..6db3f6aa4 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java @@ -0,0 +1,59 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic; + +import dan200.computercraft.api.lua.IArguments; +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.MethodResult; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.core.asm.NamedMethod; +import dan200.computercraft.core.asm.PeripheralMethod; + +import javax.annotation.Nonnull; + +final class SaturatedMethod +{ + private final Object target; + private final String name; + private final PeripheralMethod method; + + SaturatedMethod( Object target, NamedMethod method ) + { + this.target = target; + this.name = method.getName(); + this.method = method.getMethod(); + } + + @Nonnull + MethodResult apply( @Nonnull ILuaContext context, @Nonnull IComputerAccess computer, @Nonnull IArguments args ) throws LuaException + { + return method.apply( target, context, computer, args ); + } + + @Nonnull + String getName() + { + return name; + } + + @Override + public boolean equals( Object obj ) + { + if( obj == this ) return true; + if( !(obj instanceof SaturatedMethod) ) return false; + + SaturatedMethod other = (SaturatedMethod) obj; + return method == other.method && target.equals( other.target ); + } + + @Override + public int hashCode() + { + return 31 * target.hashCode() + method.hashCode(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java new file mode 100644 index 000000000..88c1b50ab --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java @@ -0,0 +1,24 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.meta; + +import net.minecraftforge.fluids.FluidStack; + +import javax.annotation.Nonnull; +import java.util.Map; +import java.util.Objects; + +public class FluidMeta +{ + @Nonnull + public static > T fillBasicMeta( @Nonnull T data, @Nonnull FluidStack stack ) + { + data.put( "name", Objects.toString( stack.getFluid().getRegistryName() ) ); + data.put( "amount", stack.getAmount() ); + return data; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java new file mode 100644 index 000000000..d61a5b21f --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java @@ -0,0 +1,85 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.meta; + +import com.google.gson.JsonParseException; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.common.util.Constants; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +public class ItemMeta +{ + @Nonnull + public static > T fillBasicMeta( @Nonnull T data, @Nonnull ItemStack stack ) + { + data.put( "name", Objects.toString( stack.getItem().getRegistryName() ) ); + data.put( "count", stack.getCount() ); + return data; + } + + @Nonnull + public static > T fillMeta( @Nonnull T data, @Nonnull ItemStack stack ) + { + if( stack.isEmpty() ) return data; + + fillBasicMeta( data, stack ); + + data.put( "displayName", stack.getDisplayName().getString() ); + data.put( "rawName", stack.getTranslationKey() ); + data.put( "maxCount", stack.getMaxStackSize() ); + + if( stack.isDamageable() ) + { + data.put( "damage", stack.getDamage() ); + data.put( "maxDamage", stack.getMaxDamage() ); + } + + if( stack.getItem().showDurabilityBar( stack ) ) + { + data.put( "durability", stack.getItem().getDurabilityForDisplay( stack ) ); + } + + CompoundNBT tag = stack.getTag(); + if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) ) + { + CompoundNBT displayTag = tag.getCompound( "display" ); + if( displayTag.contains( "Lore", Constants.NBT.TAG_LIST ) ) + { + ListNBT loreTag = displayTag.getList( "Lore", Constants.NBT.TAG_STRING ); + data.put( "lore", loreTag.stream() + .map( ItemMeta::parseTextComponent ) + .filter( Objects::nonNull ) + .map( ITextComponent::getString ) + .collect( Collectors.toList() ) ); + } + } + + return data; + } + + @Nullable + private static ITextComponent parseTextComponent( @Nonnull INBT x ) + { + try + { + return ITextComponent.Serializer.fromJson( x.getString() ); + } + catch( JsonParseException e ) + { + return null; + } + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java new file mode 100644 index 000000000..d27865ee5 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java @@ -0,0 +1,66 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.methods; + +import dan200.computercraft.api.lua.LuaException; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.ResourceLocationException; +import net.minecraftforge.registries.IForgeRegistry; +import net.minecraftforge.registries.IForgeRegistryEntry; + +import javax.annotation.Nonnull; + +/** + * A few helpers for working with arguments. + * + * This should really be moved into the public API. However, until I have settled on a suitable format, we'll keep it + * where it is used. + */ +final class ArgumentHelpers +{ + private ArgumentHelpers() + { + } + + public static void assertBetween( double value, double min, double max, String message ) throws LuaException + { + if( value < min || value > max || Double.isNaN( value ) ) + { + throw new LuaException( String.format( message, "between " + min + " and " + max ) ); + } + } + + public static void assertBetween( int value, int min, int max, String message ) throws LuaException + { + if( value < min || value > max ) + { + throw new LuaException( String.format( message, "between " + min + " and " + max ) ); + } + } + + @Nonnull + public static > T getRegistryEntry( String name, String typeName, IForgeRegistry registry ) throws LuaException + { + ResourceLocation id; + try + { + id = new ResourceLocation( name ); + } + catch( ResourceLocationException e ) + { + id = null; + } + + T value; + if( id == null || !registry.containsKey( id ) || (value = registry.getValue( id )) == null ) + { + throw new LuaException( String.format( "Unknown %s '%s'", typeName, name ) ); + } + + return value; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java new file mode 100644 index 000000000..1123318d3 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java @@ -0,0 +1,39 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.methods; + +import com.google.auto.service.AutoService; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.core.asm.GenericSource; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.energy.IEnergyStorage; +import net.minecraftforge.versions.forge.ForgeVersion; + +import javax.annotation.Nonnull; + +@AutoService( GenericSource.class ) +public class EnergyMethods implements GenericSource +{ + @Nonnull + @Override + public ResourceLocation id() + { + return new ResourceLocation( ForgeVersion.MOD_ID, "energy" ); + } + + @LuaFunction( mainThread = true ) + public static int getEnergy( IEnergyStorage energy ) + { + return energy.getEnergyStored(); + } + + @LuaFunction( mainThread = true ) + public static int getEnergyCapacity( IEnergyStorage energy ) + { + return energy.getMaxEnergyStored(); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java new file mode 100644 index 000000000..a6918dbc6 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -0,0 +1,173 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.methods; + +import com.google.auto.service.AutoService; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.asm.GenericSource; +import dan200.computercraft.shared.peripheral.generic.meta.FluidMeta; +import net.minecraft.fluid.Fluid; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; +import net.minecraftforge.fluids.capability.IFluidHandler; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.versions.forge.ForgeVersion; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHelpers.getRegistryEntry; + +@AutoService( GenericSource.class ) +public class FluidMethods implements GenericSource +{ + @Nonnull + @Override + public ResourceLocation id() + { + return new ResourceLocation( ForgeVersion.MOD_ID, "fluid" ); + } + + @LuaFunction( mainThread = true ) + public static Map> tanks( IFluidHandler fluids ) + { + Map> result = new HashMap<>(); + int size = fluids.getTanks(); + for( int i = 0; i < size; i++ ) + { + FluidStack stack = fluids.getFluidInTank( i ); + if( !stack.isEmpty() ) result.put( i + 1, FluidMeta.fillBasicMeta( new HashMap<>( 4 ), stack ) ); + } + + return result; + } + + @LuaFunction( mainThread = true ) + public static int pushFluid( + IFluidHandler from, IComputerAccess computer, + String toName, Optional limit, Optional fluidName + ) throws LuaException + { + Fluid fluid = fluidName.isPresent() + ? getRegistryEntry( fluidName.get(), "fluid", ForgeRegistries.FLUIDS ) + : null; + + // Find location to transfer to + IPeripheral location = computer.getAvailablePeripheral( toName ); + if( location == null ) throw new LuaException( "Target '" + toName + "' does not exist" ); + + IFluidHandler to = extractHandler( location.getTarget() ); + if( to == null ) throw new LuaException( "Target '" + toName + "' is not an tank" ); + + int actualLimit = limit.orElse( Integer.MAX_VALUE ); + if( actualLimit <= 0 ) throw new LuaException( "Limit must be > 0" ); + + return fluid == null + ? moveFluid( from, actualLimit, to ) + : moveFluid( from, new FluidStack( fluid, actualLimit ), to ); + } + + @LuaFunction( mainThread = true ) + public static int pullFluid( + IFluidHandler to, IComputerAccess computer, + String fromName, Optional limit, Optional fluidName + ) throws LuaException + { + Fluid fluid = fluidName.isPresent() + ? getRegistryEntry( fluidName.get(), "fluid", ForgeRegistries.FLUIDS ) + : null; + + // Find location to transfer to + IPeripheral location = computer.getAvailablePeripheral( fromName ); + if( location == null ) throw new LuaException( "Target '" + fromName + "' does not exist" ); + + IFluidHandler from = extractHandler( location.getTarget() ); + if( from == null ) throw new LuaException( "Target '" + fromName + "' is not an tank" ); + + int actualLimit = limit.orElse( Integer.MAX_VALUE ); + if( actualLimit <= 0 ) throw new LuaException( "Limit must be > 0" ); + + return fluid == null + ? moveFluid( from, actualLimit, to ) + : moveFluid( from, new FluidStack( fluid, actualLimit ), to ); + } + + @Nullable + private static IFluidHandler extractHandler( @Nullable Object object ) + { + if( object instanceof ICapabilityProvider ) + { + LazyOptional cap = ((ICapabilityProvider) object).getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY ); + if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new ); + } + + if( object instanceof IFluidHandler ) return (IFluidHandler) object; + return null; + } + + /** + * Move fluid from one handler to another. + * + * @param from The handler to move from. + * @param limit The maximum amount of fluid to move. + * @param to The handler to move to. + * @return The amount of fluid moved. + */ + private static int moveFluid( IFluidHandler from, int limit, IFluidHandler to ) + { + return moveFluid( from, from.drain( limit, IFluidHandler.FluidAction.SIMULATE ), limit, to ); + } + + /** + * Move fluid from one handler to another. + * + * @param from The handler to move from. + * @param fluid The fluid and limit to move. + * @param to The handler to move to. + * @return The amount of fluid moved. + */ + private static int moveFluid( IFluidHandler from, FluidStack fluid, IFluidHandler to ) + { + return moveFluid( from, from.drain( fluid, IFluidHandler.FluidAction.SIMULATE ), fluid.getAmount(), to ); + } + + /** + * Move fluid from one handler to another. + * + * @param from The handler to move from. + * @param extracted The fluid which is extracted from {@code from}. + * @param limit The maximum amount of fluid to move. + * @param to The handler to move to. + * @return The amount of fluid moved. + */ + private static int moveFluid( IFluidHandler from, FluidStack extracted, int limit, IFluidHandler to ) + { + if( extracted == null || extracted.getAmount() <= 0 ) return 0; + + // Limit the amount to extract. + extracted = extracted.copy(); + extracted.setAmount( Math.min( extracted.getAmount(), limit ) ); + + int inserted = to.fill( extracted.copy(), IFluidHandler.FluidAction.EXECUTE ); + if( inserted <= 0 ) return 0; + + // Remove the item from the original inventory. Technically this could fail, but there's little we can do + // about that. + extracted.setAmount( inserted ); + from.drain( extracted, IFluidHandler.FluidAction.EXECUTE ); + return inserted; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java new file mode 100644 index 000000000..cc1c37d0b --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -0,0 +1,161 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.methods; + +import com.google.auto.service.AutoService; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.asm.GenericSource; +import dan200.computercraft.shared.peripheral.generic.meta.ItemMeta; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.capabilities.ICapabilityProvider; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; +import net.minecraftforge.items.ItemHandlerHelper; +import net.minecraftforge.items.wrapper.InvWrapper; +import net.minecraftforge.versions.forge.ForgeVersion; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHelpers.assertBetween; + +@AutoService( GenericSource.class ) +public class InventoryMethods implements GenericSource +{ + @Nonnull + @Override + public ResourceLocation id() + { + return new ResourceLocation( ForgeVersion.MOD_ID, "inventory" ); + } + + @LuaFunction( mainThread = true ) + public static int size( IItemHandler inventory ) + { + return inventory.getSlots(); + } + + @LuaFunction( mainThread = true ) + public static Map> list( IItemHandler inventory ) + { + Map> result = new HashMap<>(); + int size = inventory.getSlots(); + for( int i = 0; i < size; i++ ) + { + ItemStack stack = inventory.getStackInSlot( i ); + if( !stack.isEmpty() ) result.put( i + 1, ItemMeta.fillBasicMeta( new HashMap<>( 4 ), stack ) ); + } + + return result; + } + + @LuaFunction( mainThread = true ) + public static Map getItemMeta( IItemHandler inventory, int slot ) throws LuaException + { + assertBetween( slot, 1, inventory.getSlots(), "Slot out of range (%s)" ); + + ItemStack stack = inventory.getStackInSlot( slot - 1 ); + return stack.isEmpty() ? null : ItemMeta.fillMeta( new HashMap<>(), stack ); + } + + @LuaFunction( mainThread = true ) + public static int pushItems( + IItemHandler from, IComputerAccess computer, + String toName, int fromSlot, Optional limit, Optional toSlot + ) throws LuaException + { + // Find location to transfer to + IPeripheral location = computer.getAvailablePeripheral( toName ); + if( location == null ) throw new LuaException( "Target '" + toName + "' does not exist" ); + + IItemHandler to = extractHandler( location.getTarget() ); + if( to == null ) throw new LuaException( "Target '" + toName + "' is not an inventory" ); + + // Validate slots + int actualLimit = limit.orElse( Integer.MAX_VALUE ); + if( actualLimit <= 0 ) throw new LuaException( "Limit must be > 0" ); + assertBetween( fromSlot, 1, from.getSlots(), "From slot out of range (%s)" ); + if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.getSlots(), "To slot out of range (%s)" ); + + return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit ); + } + + @LuaFunction( mainThread = true ) + public static int pullItems( + IItemHandler to, IComputerAccess computer, + String fromName, int fromSlot, Optional limit, Optional toSlot + ) throws LuaException + { + // Find location to transfer to + IPeripheral location = computer.getAvailablePeripheral( fromName ); + if( location == null ) throw new LuaException( "Source '" + fromName + "' does not exist" ); + + IItemHandler from = extractHandler( location.getTarget() ); + if( from == null ) throw new LuaException( "Source '" + fromName + "' is not an inventory" ); + + // Validate slots + int actualLimit = limit.orElse( Integer.MAX_VALUE ); + if( actualLimit <= 0 ) throw new LuaException( "Limit must be > 0" ); + assertBetween( fromSlot, 1, from.getSlots(), "From slot out of range (%s)" ); + if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.getSlots(), "To slot out of range (%s)" ); + + return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit ); + } + + @Nullable + private static IItemHandler extractHandler( @Nullable Object object ) + { + if( object instanceof ICapabilityProvider ) + { + LazyOptional cap = ((ICapabilityProvider) object).getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ); + if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new ); + } + + if( object instanceof IItemHandler ) return (IItemHandler) object; + if( object instanceof IInventory ) return new InvWrapper( (IInventory) object ); + return null; + } + + /** + * Move an item from one handler to another. + * + * @param from The handler to move from. + * @param fromSlot The slot to move from. + * @param to The handler to move to. + * @param toSlot The slot to move to. Use any number < 0 to represent any slot. + * @param limit The max number to move. {@link Integer#MAX_VALUE} for no limit. + * @return The number of items moved. + */ + private static int moveItem( IItemHandler from, int fromSlot, IItemHandler to, int toSlot, final int limit ) + { + // See how much we can get out of this slot + ItemStack extracted = from.extractItem( fromSlot, limit, true ); + if( extracted.isEmpty() ) return 0; + + // Limit the amount to extract + int extractCount = Math.min( extracted.getCount(), limit ); + extracted.setCount( extractCount ); + + ItemStack remainder = toSlot < 0 ? ItemHandlerHelper.insertItem( to, extracted, false ) : to.insertItem( toSlot, extracted, false ); + int inserted = remainder.isEmpty() ? extractCount : extractCount - remainder.getCount(); + if( inserted <= 0 ) return 0; + + // Remove the item from the original inventory. Technically this could fail, but there's little we can do + // about that. + from.extractItem( fromSlot, inserted, false ); + return inserted; + } +} From 514db30fb1d40c5a73e70c191120513166f356ea Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 28 Jun 2020 16:33:03 +0100 Subject: [PATCH 267/711] Add configuration options to control terminal sizes (#475) This allows for configuring the size of computers and pocket computers, as well as the max size of monitors. There's several limitations with the current implementation, but it's still "good enough" for an initial release: - Turtles cannot be resized. - GUIs do not scale themselves, so "large" sizes will not render within the default resolution. --- build.gradle | 2 +- .../dan200/computercraft/ComputerCraft.java | 15 +- .../computercraft/client/gui/GuiComputer.java | 79 +++----- .../computercraft/client/gui/GuiTurtle.java | 8 +- .../client/render/ComputerBorderRenderer.java | 175 ++++++++++++++++++ .../client/render/ItemPocketRenderer.java | 63 ++----- .../client/render/TurtlePlayerRenderer.java | 3 +- .../dan200/computercraft/shared/Config.java | 40 ++++ .../shared/computer/blocks/TileComputer.java | 4 +- .../peripheral/monitor/TileMonitor.java | 11 +- .../pocket/core/PocketServerComputer.java | 2 +- .../shared/turtle/blocks/TileTurtle.java | 2 +- .../core/computer/ComputerBootstrap.java | 2 +- 13 files changed, 277 insertions(+), 129 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java diff --git a/build.gradle b/build.gradle index 69b2cb01f..bd89387a1 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.169' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.179' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index bcac1d468..d712dc914 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -93,14 +93,17 @@ public final class ComputerCraft public static boolean genericPeripheral = false; - public static final int terminalWidth_computer = 51; - public static final int terminalHeight_computer = 19; + public static int computerTermWidth = 51; + public static int computerTermHeight = 19; - public static final int terminalWidth_turtle = 39; - public static final int terminalHeight_turtle = 13; + public static final int turtleTermWidth = 39; + public static final int turtleTermHeight = 13; - public static final int terminalWidth_pocketComputer = 26; - public static final int terminalHeight_pocketComputer = 20; + public static int pocketTermWidth = 26; + public static int pocketTermHeight = 20; + + public static int monitorWidth = 8; + public static int monitorHeight = 6; public static final class TurtleUpgrades { diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index b61cb24ff..3008c9386 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -9,6 +9,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.gui.widgets.WidgetWrapper; +import dan200.computercraft.client.render.ComputerBorderRenderer; import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.inventory.ContainerComputer; @@ -17,21 +18,18 @@ import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; +import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; +import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; + public final class GuiComputer extends ContainerScreen { - public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); - public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); - public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" ); - public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" ); - - private final ComputerFamily m_family; - private final ClientComputer m_computer; - private final int m_termWidth; - private final int m_termHeight; + private final ComputerFamily family; + private final ClientComputer computer; + private final int termWidth; + private final int termHeight; private WidgetTerminal terminal; private WidgetWrapper terminalWrapper; @@ -41,10 +39,10 @@ public final class GuiComputer extends Containe ) { super( container, player, title ); - m_family = container.getFamily(); - m_computer = (ClientComputer) container.getComputer(); - m_termWidth = termWidth; - m_termHeight = termHeight; + family = container.getFamily(); + computer = (ClientComputer) container.getComputer(); + this.termWidth = termWidth; + this.termHeight = termHeight; terminal = null; } @@ -52,7 +50,7 @@ public final class GuiComputer extends Containe { return new GuiComputer<>( container, inventory, component, - ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer + ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); } @@ -60,7 +58,7 @@ public final class GuiComputer extends Containe { return new GuiComputer<>( container, inventory, component, - ComputerCraft.terminalWidth_pocketComputer, ComputerCraft.terminalHeight_pocketComputer + ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); } @@ -78,16 +76,16 @@ public final class GuiComputer extends Containe { minecraft.keyboardListener.enableRepeatEvents( true ); - int termPxWidth = m_termWidth * FixedWidthFontRenderer.FONT_WIDTH; - int termPxHeight = m_termHeight * FixedWidthFontRenderer.FONT_HEIGHT; + int termPxWidth = termWidth * FixedWidthFontRenderer.FONT_WIDTH; + int termPxHeight = termHeight * FixedWidthFontRenderer.FONT_HEIGHT; - xSize = termPxWidth + 4 + 24; - ySize = termPxHeight + 4 + 24; + xSize = termPxWidth + MARGIN * 2 + BORDER * 2; + ySize = termPxHeight + MARGIN * 2 + BORDER * 2; super.init(); - terminal = new WidgetTerminal( minecraft, () -> m_computer, m_termWidth, m_termHeight, 2, 2, 2, 2 ); - terminalWrapper = new WidgetWrapper( terminal, 2 + 12 + guiLeft, 2 + 12 + guiTop, termPxWidth, termPxHeight ); + terminal = new WidgetTerminal( minecraft, () -> computer, termWidth, termHeight, MARGIN, MARGIN, MARGIN, MARGIN ); + terminalWrapper = new WidgetWrapper( terminal, MARGIN + BORDER + guiLeft, MARGIN + BORDER + guiTop, termPxWidth, termPxHeight ); children.add( terminalWrapper ); setFocused( terminalWrapper ); @@ -124,41 +122,16 @@ public final class GuiComputer extends Containe @Override public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) { - // Work out where to draw - int startX = terminalWrapper.getX() - 2; - int startY = terminalWrapper.getY() - 2; - int endX = startX + terminalWrapper.getWidth() + 4; - int endY = startY + terminalWrapper.getHeight() + 4; - // Draw terminal terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw a border around the terminal - RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); - switch( m_family ) - { - case NORMAL: - default: - minecraft.getTextureManager().bindTexture( BACKGROUND_NORMAL ); - break; - case ADVANCED: - minecraft.getTextureManager().bindTexture( BACKGROUND_ADVANCED ); - break; - case COMMAND: - minecraft.getTextureManager().bindTexture( BACKGROUND_COMMAND ); - break; - } - - blit( startX - 12, startY - 12, 12, 28, 12, 12 ); - blit( startX - 12, endY, 12, 40, 12, 12 ); - blit( endX, startY - 12, 24, 28, 12, 12 ); - blit( endX, endY, 24, 40, 12, 12 ); - - blit( startX, startY - 12, 0, 0, endX - startX, 12 ); - blit( startX, endY, 0, 12, endX - startX, 12 ); - - blit( startX - 12, startY, 0, 28, 12, endY - startY ); - blit( endX, startY, 36, 28, 12, endY - startY ); + RenderSystem.color4f( 1, 1, 1, 1 ); + minecraft.getTextureManager().bindTexture( ComputerBorderRenderer.getTexture( family ) ); + ComputerBorderRenderer.render( + terminalWrapper.getX() - MARGIN, terminalWrapper.getY() - MARGIN, getBlitOffset(), + terminalWrapper.getWidth() + MARGIN * 2, terminalWrapper.getHeight() + MARGIN * 2 + ); } @Override diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 7a43c7702..517cf140f 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -49,13 +49,13 @@ public class GuiTurtle extends ContainerScreen super.init(); minecraft.keyboardListener.enableRepeatEvents( true ); - int termPxWidth = ComputerCraft.terminalWidth_turtle * FixedWidthFontRenderer.FONT_WIDTH; - int termPxHeight = ComputerCraft.terminalHeight_turtle * FixedWidthFontRenderer.FONT_HEIGHT; + int termPxWidth = ComputerCraft.turtleTermWidth * FixedWidthFontRenderer.FONT_WIDTH; + int termPxHeight = ComputerCraft.turtleTermHeight * FixedWidthFontRenderer.FONT_HEIGHT; terminal = new WidgetTerminal( minecraft, () -> m_computer, - ComputerCraft.terminalWidth_turtle, - ComputerCraft.terminalHeight_turtle, + ComputerCraft.turtleTermWidth, + ComputerCraft.turtleTermHeight, 2, 2, 2, 2 ); terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + guiLeft, 2 + 8 + guiTop, termPxWidth, termPxHeight ); diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java new file mode 100644 index 000000000..9c784d7fc --- /dev/null +++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java @@ -0,0 +1,175 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.client.render; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.Matrix4f; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nonnull; + +public class ComputerBorderRenderer +{ + public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_normal.png" ); + public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" ); + public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" ); + public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" ); + + private static final Matrix4f IDENTITY = new Matrix4f(); + + static + { + IDENTITY.setIdentity(); + } + + /** + * The margin between the terminal and its border. + */ + public static final int MARGIN = 2; + + /** + * The width of the terminal border. + */ + public static final int BORDER = 12; + + private static final int CORNER_TOP_Y = 28; + private static final int CORNER_BOTTOM_Y = CORNER_TOP_Y + BORDER; + private static final int CORNER_LEFT_X = BORDER; + private static final int CORNER_RIGHT_X = CORNER_LEFT_X + BORDER; + private static final int BORDER_RIGHT_X = 36; + private static final int GAP = 4; + + private static final float TEX_SCALE = 1 / 256.0f; + + private final Matrix4f transform; + private final IVertexBuilder builder; + private final int z; + private final float r, g, b; + + public ComputerBorderRenderer( Matrix4f transform, IVertexBuilder builder, int z, float r, float g, float b ) + { + this.transform = transform; + this.builder = builder; + this.z = z; + this.r = r; + this.g = g; + this.b = b; + } + + + @Nonnull + public static ResourceLocation getTexture( @Nonnull ComputerFamily family ) + { + switch( family ) + { + case NORMAL: + default: + return BACKGROUND_NORMAL; + case ADVANCED: + return BACKGROUND_ADVANCED; + case COMMAND: + return BACKGROUND_COMMAND; + } + } + + public static void render( int x, int y, int z, int width, int height ) + { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder buffer = tessellator.getBuffer(); + buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX ); + + render( IDENTITY, buffer, x, y, z, width, height ); + + RenderSystem.enableAlphaTest(); + tessellator.draw(); + } + + public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height ) + { + render( transform, buffer, x, y, z, width, height, 1, 1, 1 ); + } + + public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, float r, float g, float b ) + { + render( transform, buffer, x, y, z, width, height, 0, r, g, b ); + } + + public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, int borderHeight, float r, float g, float b ) + { + new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, borderHeight ); + } + + public void doRender( int x, int y, int width, int height, int bottomHeight ) + { + int endX = x + width; + int endY = y + height; + + // Vertical bars + renderLine( x - BORDER, y, 0, CORNER_TOP_Y, BORDER, endY - y ); + renderLine( endX, y, BORDER_RIGHT_X, CORNER_TOP_Y, BORDER, endY - y ); + + // Top bar + renderLine( x, y - BORDER, 0, 0, endX - x, BORDER ); + renderCorner( x - BORDER, y - BORDER, CORNER_LEFT_X, CORNER_TOP_Y ); + renderCorner( endX, y - BORDER, CORNER_RIGHT_X, CORNER_TOP_Y ); + + // Bottom bar. We allow for drawing a stretched version, which allows for additional elements (such as the + // pocket computer's lights). + if( bottomHeight <= 0 ) + { + renderLine( x, endY, 0, BORDER, endX - x, BORDER ); + renderCorner( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y ); + renderCorner( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y ); + } + else + { + // Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for + // lights, and then the bottom outer corners. + renderTexture( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2 ); + renderTexture( x, endY, 0, BORDER, width, BORDER / 2, BORDER, BORDER / 2 ); + renderTexture( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2 ); + + renderTexture( x - BORDER, endY + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP ); + renderTexture( x, endY + BORDER / 2, 0, BORDER + GAP, width, bottomHeight, BORDER, GAP ); + renderTexture( endX, endY + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP ); + + renderTexture( x - BORDER, endY + bottomHeight + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2 ); + renderTexture( x, endY + bottomHeight + BORDER / 2, 0, BORDER + BORDER / 2, width, BORDER / 2 ); + renderTexture( endX, endY + bottomHeight + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2 ); + } + } + + private void renderCorner( int x, int y, int u, int v ) + { + renderTexture( x, y, u, v, BORDER, BORDER, BORDER, BORDER ); + } + + private void renderLine( int x, int y, int u, int v, int width, int height ) + { + renderTexture( x, y, u, v, width, height, BORDER, BORDER ); + } + + private void renderTexture( int x, int y, int u, int v, int width, int height ) + { + renderTexture( x, y, u, v, width, height, width, height ); + } + + private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight ) + { + builder.pos( transform, x, y + height, z ).color( r, g, b, 1.0f ).tex( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex(); + builder.pos( transform, x + width, y + height, z ).color( r, g, b, 1.0f ).tex( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex(); + builder.pos( transform, x + width, y, z ).color( r, g, b, 1.0f ).tex( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).endVertex(); + builder.pos( transform, x, y, z ).color( r, g, b, 1.0f ).tex( u * TEX_SCALE, v * TEX_SCALE ).endVertex(); + } +} diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 9e87d4e35..157250d56 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -7,7 +7,6 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; @@ -27,7 +26,8 @@ import org.lwjgl.opengl.GL11; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH; -import static dan200.computercraft.client.gui.GuiComputer.*; +import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; +import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; /** * Emulates map rendering for pocket computers. @@ -35,8 +35,6 @@ import static dan200.computercraft.client.gui.GuiComputer.*; @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT ) public final class ItemPocketRenderer extends ItemMapLikeRenderer { - private static final int MARGIN = 2; - private static final int FRAME = 12; private static final int LIGHT_HEIGHT = 8; private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer(); @@ -67,8 +65,8 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer int termWidth, termHeight; if( terminal == null ) { - termWidth = ComputerCraft.terminalWidth_pocketComputer; - termHeight = ComputerCraft.terminalHeight_pocketComputer; + termWidth = ComputerCraft.pocketTermWidth; + termHeight = ComputerCraft.pocketTermHeight; } else { @@ -86,7 +84,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) ); transform.scale( 0.5f, 0.5f, 0.5f ); - float scale = 0.75f / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT ); + float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT ); transform.scale( scale, scale, 0 ); transform.translate( -0.5 * width, -0.5 * height, 0 ); @@ -117,10 +115,8 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height ) { - Minecraft.getInstance().getTextureManager().bindTexture( colour != -1 - ? BACKGROUND_COLOUR - : family == ComputerFamily.NORMAL ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED - ); + Minecraft.getInstance().getTextureManager() + .bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) ); float r = ((colour >>> 16) & 0xFF) / 255.0f; float g = ((colour >>> 8) & 0xFF) / 255.0f; @@ -130,28 +126,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer BufferBuilder buffer = tessellator.getBuffer(); buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX ); - // Top left, middle, right - renderTexture( transform, buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b ); - renderTexture( transform, buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b ); - renderTexture( transform, buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b ); - - // Left and bright border - renderTexture( transform, buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b ); - renderTexture( transform, buffer, width, 0, 36, 28, FRAME, height, r, g, b ); - - // Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for - // lights, and then the bottom outer corners. - renderTexture( transform, buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b ); - renderTexture( transform, buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b ); - renderTexture( transform, buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b ); - - renderTexture( transform, buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); - renderTexture( transform, buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b ); - renderTexture( transform, buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b ); - - renderTexture( transform, buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); - renderTexture( transform, buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b ); - renderTexture( transform, buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b ); + ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, LIGHT_HEIGHT, r, g, b ); tessellator.draw(); } @@ -168,26 +143,12 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR ); - buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); - buffer.pos( transform, width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); - buffer.pos( transform, width, height + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); - buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); + buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex(); tessellator.draw(); RenderSystem.enableTexture(); } - - private static void renderTexture( Matrix4f transform, IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b ) - { - renderTexture( transform, builder, x, y, textureX, textureY, width, height, width, height, r, g, b ); - } - - private static void renderTexture( Matrix4f transform, IVertexBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b ) - { - float scale = 1 / 255.0f; - builder.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( textureX * scale, (textureY + textureHeight) * scale ).endVertex(); - builder.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).endVertex(); - builder.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( (textureX + textureWidth) * scale, textureY * scale ).endVertex(); - builder.pos( transform, x, y, 0 ).color( r, g, b, 1.0f ).tex( textureX * scale, textureY * scale ).endVertex(); - } } diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java index 4c00145f9..4e7cb8e70 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -7,7 +7,6 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.matrix.MatrixStack; -import dan200.computercraft.client.gui.GuiComputer; import dan200.computercraft.shared.turtle.core.TurtlePlayer; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.entity.EntityRenderer; @@ -27,7 +26,7 @@ public class TurtlePlayerRenderer extends EntityRenderer @Override public ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity ) { - return GuiComputer.BACKGROUND_NORMAL; + return ComputerBorderRenderer.BACKGROUND_NORMAL; } @Override diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index bfa177156..812ef4c9c 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -73,6 +73,15 @@ public final class Config private static final ConfigValue turtlesCanPush; private static final ConfigValue> turtleDisabledActions; + private static final ConfigValue computerTermWidth; + private static final ConfigValue computerTermHeight; + + private static final ConfigValue pocketTermWidth; + private static final ConfigValue pocketTermHeight; + + private static final ConfigValue monitorWidth; + private static final ConfigValue monitorHeight; + private static final ConfigValue genericPeripheral; private static final ConfigValue monitorRenderer; @@ -262,6 +271,28 @@ public final class Config builder.pop(); } + { + builder.comment( "Configure the size of various computer's terminals.\n" + + "Larger terminals require more bandwidth, so use with care." ).push( "term_sizes" ); + + builder.comment( "Terminal size of computers" ).push( "computer" ); + computerTermWidth = builder.defineInRange( "width", ComputerCraft.computerTermWidth, 1, 255 ); + computerTermHeight = builder.defineInRange( "height", ComputerCraft.computerTermHeight, 1, 255 ); + builder.pop(); + + builder.comment( "Terminal size of pocket computers" ).push( "pocket_computer" ); + pocketTermWidth = builder.defineInRange( "width", ComputerCraft.pocketTermWidth, 1, 255 ); + pocketTermHeight = builder.defineInRange( "height", ComputerCraft.pocketTermHeight, 1, 255 ); + builder.pop(); + + builder.comment( "Maximum size of monitors (in blocks)" ).push( "monitor" ); + monitorWidth = builder.defineInRange( "width", ComputerCraft.monitorWidth, 1, 32 ); + monitorHeight = builder.defineInRange( "height", ComputerCraft.monitorHeight, 1, 32 ); + builder.pop(); + + builder.pop(); + } + { builder.comment( "Options for various experimental features. These are not guaranteed to be stable, and may change or be removed across versions." ); builder.push( "experimental" ); @@ -335,6 +366,15 @@ public final class Config ComputerCraft.turtleDisabledActions.clear(); for( String value : turtleDisabledActions.get() ) ComputerCraft.turtleDisabledActions.add( getAction( value ) ); + // Terminal size + ComputerCraft.computerTermWidth = computerTermWidth.get(); + ComputerCraft.computerTermHeight = computerTermHeight.get(); + ComputerCraft.pocketTermWidth = pocketTermWidth.get(); + ComputerCraft.pocketTermHeight = pocketTermHeight.get(); + ComputerCraft.monitorWidth = monitorWidth.get(); + ComputerCraft.monitorHeight = monitorHeight.get(); + + // Experimental ComputerCraft.genericPeripheral = genericPeripheral.get(); // Client diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 82d10dea2..e03862b3f 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -43,8 +43,8 @@ public class TileComputer extends TileComputerBase ComputerFamily family = getFamily(); ServerComputer computer = new ServerComputer( getWorld(), id, label, instanceID, family, - ComputerCraft.terminalWidth_computer, - ComputerCraft.terminalHeight_computer + ComputerCraft.computerTermWidth, + ComputerCraft.computerTermHeight ); computer.setPosition( getPos() ); return computer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 92603cae8..129f5f783 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -41,9 +41,6 @@ public class TileMonitor extends TileGeneric public static final double RENDER_MARGIN = 0.5 / 16.0; public static final double RENDER_PIXEL_SCALE = 1.0 / 64.0; - private static final int MAX_WIDTH = 8; - private static final int MAX_HEIGHT = 6; - private static final String NBT_X = "XIndex"; private static final String NBT_Y = "YIndex"; private static final String NBT_WIDTH = "Width"; @@ -473,7 +470,7 @@ public class TileMonitor extends TileGeneric if( left == null || left.m_yIndex != 0 || left.m_height != m_height ) return false; int width = left.m_width + m_width; - if( width > MAX_WIDTH ) return false; + if( width > ComputerCraft.monitorWidth ) return false; TileMonitor origin = left.getOrigin(); if( origin != null ) origin.resize( width, m_height ); @@ -487,7 +484,7 @@ public class TileMonitor extends TileGeneric if( right == null || right.m_yIndex != 0 || right.m_height != m_height ) return false; int width = m_width + right.m_width; - if( width > MAX_WIDTH ) return false; + if( width > ComputerCraft.monitorWidth ) return false; TileMonitor origin = getOrigin(); if( origin != null ) origin.resize( width, m_height ); @@ -501,7 +498,7 @@ public class TileMonitor extends TileGeneric if( above == null || above.m_xIndex != 0 || above.m_width != m_width ) return false; int height = above.m_height + m_height; - if( height > MAX_HEIGHT ) return false; + if( height > ComputerCraft.monitorHeight ) return false; TileMonitor origin = getOrigin(); if( origin != null ) origin.resize( m_width, height ); @@ -515,7 +512,7 @@ public class TileMonitor extends TileGeneric if( below == null || below.m_xIndex != 0 || below.m_width != m_width ) return false; int height = m_height + below.m_height; - if( height > MAX_HEIGHT ) return false; + if( height > ComputerCraft.monitorHeight ) return false; TileMonitor origin = below.getOrigin(); if( origin != null ) origin.resize( m_width, height ); diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index df671793b..e165daf95 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -41,7 +41,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces public PocketServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family ) { - super( world, computerID, label, instanceID, family, ComputerCraft.terminalWidth_pocketComputer, ComputerCraft.terminalHeight_pocketComputer ); + super( world, computerID, label, instanceID, family, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index bb7feed4a..2d52d0ef9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -87,7 +87,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default { ServerComputer computer = new ServerComputer( getWorld(), id, label, instanceID, getFamily(), - ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle + ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight ); computer.setPosition( getPos() ); computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) ); diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 21b55613b..3675c14d2 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -45,7 +45,7 @@ public class ComputerBootstrap ComputerCraft.logComputerErrors = true; ComputerCraft.maxMainComputerTime = ComputerCraft.maxMainGlobalTime = Integer.MAX_VALUE; - Terminal term = new Terminal( ComputerCraft.terminalWidth_computer, ComputerCraft.terminalHeight_computer ); + Terminal term = new Terminal( ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); final Computer computer = new Computer( new BasicEnvironment( mount ), term, 0 ); AssertApi api = new AssertApi(); From 9e2232d24045af46b57162f3c3213e622e67bfe9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 30 Jun 2020 11:10:24 +0100 Subject: [PATCH 268/711] Clean up entity drop code We were incorrectly using captureDrops directly - it's more reasonable to listen to the drop event. Fixes #486 --- .../shared/util/DropConsumer.java | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 47a6915e9..23e40a9d6 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -13,11 +13,11 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.event.entity.living.LivingDropsEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.function.Function; @@ -31,16 +31,16 @@ public final class DropConsumer private static Function dropConsumer; private static List remainingDrops; - private static WeakReference dropWorld; + private static World dropWorld; private static AxisAlignedBB dropBounds; - private static WeakReference dropEntity; + private static Entity dropEntity; public static void set( Entity entity, Function consumer ) { dropConsumer = consumer; remainingDrops = new ArrayList<>(); - dropEntity = new WeakReference<>( entity ); - dropWorld = new WeakReference<>( entity.world ); + dropEntity = entity; + dropWorld = entity.world; dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); entity.captureDrops = true; @@ -51,26 +51,12 @@ public final class DropConsumer dropConsumer = consumer; remainingDrops = new ArrayList<>( 2 ); dropEntity = null; - dropWorld = new WeakReference<>( world ); + dropWorld = world; dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 ); } public static List clear() { - if( dropEntity != null ) - { - Entity entity = dropEntity.get(); - if( entity != null ) - { - entity.captureDrops = false; - if( entity.capturedDrops != null ) - { - for( EntityItem entityItem : entity.capturedDrops ) handleDrops( entityItem.getItem() ); - entity.capturedDrops.clear(); - } - } - } - List remainingStacks = remainingDrops; dropConsumer = null; @@ -92,11 +78,20 @@ public final class DropConsumer public static void onEntitySpawn( EntityJoinWorldEvent event ) { // Capture any nearby item spawns - if( dropWorld != null && dropWorld.get() == event.getWorld() && event.getEntity() instanceof EntityItem + if( dropWorld == event.getWorld() && event.getEntity() instanceof EntityItem && dropBounds.contains( event.getEntity().getPositionVector() ) ) { handleDrops( ((EntityItem) event.getEntity()).getItem() ); event.setCanceled( true ); } } + + @SubscribeEvent + public static void onLivingDrops( LivingDropsEvent drops ) + { + if( dropEntity == null || drops.getEntity() != dropEntity ) return; + + for( EntityItem drop : drops.getDrops() ) handleDrops( drop.getItem() ); + drops.setCanceled( true ); + } } From 37a447e745a27b66b670c756e8209d3127fce556 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 30 Jun 2020 11:10:26 +0100 Subject: [PATCH 269/711] Bump version to 1.89.2 Somewhat reluctant to do this, but it's a pretty major bug. --- gradle.properties | 2 +- .../resources/assets/computercraft/lua/rom/help/changelog.txt | 4 ++++ .../resources/assets/computercraft/lua/rom/help/whatsnew.txt | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index f71c4f6e1..9bf4d7b26 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.89.1 +mod_version=1.89.2 # Minecraft properties mc_version=1.12.2 diff --git a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt index 97d223b6b..14e625377 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.89.2 + +* Fix dupe bug when killing an entity with a turtle. + # New features in CC: Tweaked 1.89.1 * Fix crashes when rendering monitors of varying sizes. diff --git a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt index ddb0a9fe9..d6718d6b8 100644 --- a/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt @@ -1,5 +1,5 @@ -New features in CC: Tweaked 1.89.1 +New features in CC: Tweaked 1.89.2 -* Fix crashes when rendering monitors of varying sizes. +* Fix dupe bug when killing an entity with a turtle. Type "help changelog" to see the full version history. From 36bb8b67c927084c68d04823e91d98d95426af7e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 30 Jun 2020 12:35:39 +0100 Subject: [PATCH 270/711] Clean up data-gathering code - Refer to this as "data" rather than "metadata". I'm still not sure where the meta came from - blame OpenPeripheral I guess. - Likewise, use getItemDetail within inventory methods, rather than getItemMeta. - Refactor common data-getting code into one class. This means that turtle.getItemDetail, turtle.inspect and commands.getBlockInfo all use the same code. - turtle.getItemDetail now accepts a second "detailed" parameter which will include the full metadata (#471, #452). - Tags are now only included in the detailed list. This is a breaking change, however should only affect one version (1.89.x) and I'm not convinced that the previous behaviour was safe. --- doc/stub/turtle.lua | 5 ++- .../turtle/event/TurtleInspectItemEvent.java | 23 +++++++++- .../computercraft/core/asm/TaskCallback.java | 10 ++++- .../shared/computer/apis/CommandAPI.java | 25 +---------- .../peripheral/generic/data/BlockData.java | 43 +++++++++++++++++++ .../peripheral/generic/data/DataHelpers.java | 23 ++++++++++ .../FluidMeta.java => data/FluidData.java} | 14 ++++-- .../ItemMeta.java => data/ItemData.java} | 15 ++++--- .../generic/methods/FluidMethods.java | 4 +- .../generic/methods/InventoryMethods.java | 8 ++-- .../shared/turtle/apis/TurtleAPI.java | 35 +++++++-------- .../turtle/core/TurtleInspectCommand.java | 31 +------------ 12 files changed, 143 insertions(+), 93 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java create mode 100644 src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java rename src/main/java/dan200/computercraft/shared/peripheral/generic/{meta/FluidMeta.java => data/FluidData.java} (58%) rename src/main/java/dan200/computercraft/shared/peripheral/generic/{meta/ItemMeta.java => data/ItemData.java} (87%) diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua index 7fabd2a8a..2c3619469 100644 --- a/doc/stub/turtle.lua +++ b/doc/stub/turtle.lua @@ -206,16 +206,17 @@ function getItemSpace(slot) end --- Get detailed information about the items in the given slot. -- -- @tparam[opt] number slot The slot to get information about. Defaults to the @{turtle.select|selected slot}. +-- @tparam[opt] boolean detailed Whether to include "detailed" information. When @{true} the method will contain +-- much more information about the item at the cost of taking longer to run. -- @treturn nil|table Information about the given slot, or @{nil} if it is empty. -- @usage Print the current slot, assuming it contains 13 dirt. -- -- print(textutils.serialize(turtle.getItemDetail())) -- -- => { -- -- name = "minecraft:dirt", --- -- damage = 0, -- -- count = 13, -- -- } -function getItemDetail(slot) end +function getItemDetail(slot, detailed) end function getFuelLevel() end diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index f21756a1a..e4eb517e3 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -16,8 +16,8 @@ import java.util.Objects; /** * Fired when a turtle gathers data on an item in its inventory. * - * You may prevent items being inspected, or add additional information to the result. Be aware that this is fired on - * the computer thread, and so any operations on it must be thread safe. + * You may prevent items being inspected, or add additional information to the result. Be aware that this may be fired + * on the computer thread, and so any operations on it must be thread safe. * * @see TurtleAction#INSPECT_ITEM */ @@ -25,8 +25,15 @@ public class TurtleInspectItemEvent extends TurtleActionEvent { private final ItemStack stack; private final Map data; + private final boolean mainThread; + @Deprecated public TurtleInspectItemEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map data ) + { + this( turtle, stack, data, false ); + } + + public TurtleInspectItemEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, @Nonnull Map data, boolean mainThread ) { super( turtle, TurtleAction.INSPECT_ITEM ); @@ -34,6 +41,7 @@ public class TurtleInspectItemEvent extends TurtleActionEvent Objects.requireNonNull( data, "data cannot be null" ); this.stack = stack; this.data = data; + this.mainThread = mainThread; } /** @@ -58,6 +66,17 @@ public class TurtleInspectItemEvent extends TurtleActionEvent return data; } + /** + * If this event is being fired on the server thread. When true, information which relies on server state may be + * exposed. + * + * @return If this is run on the main thread. + */ + public boolean onMainThread() + { + return mainThread; + } + /** * Add new information to the inspection result. Note this will override fields with the same name. * diff --git a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java index 98ca25a88..af8d8814d 100644 --- a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java +++ b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java @@ -48,9 +48,15 @@ public final class TaskCallback implements ILuaCallback } } - public static Object[] checkUnwrap( MethodResult result ) + static Object[] checkUnwrap( MethodResult result ) { - if( result.getCallback() != null ) throw new IllegalStateException( "Cannot return MethodResult currently" ); + if( result.getCallback() != null ) + { + // Due to how tasks are implemented, we can't currently return a MethodResult. This is an + // entirely artificial limitation - we can remove it if it ever becomes an issue. + throw new IllegalStateException( "Cannot return MethodResult for mainThread task." ); + } + return result.getResult(); } diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 7354853ef..53e8fbc21 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -5,24 +5,21 @@ */ package dan200.computercraft.shared.computer.apis; -import com.google.common.collect.ImmutableMap; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.*; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; +import dan200.computercraft.shared.peripheral.generic.data.BlockData; import dan200.computercraft.shared.util.NBTUtil; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.command.CommandSource; import net.minecraft.command.Commands; import net.minecraft.nbt.CompoundNBT; import net.minecraft.server.MinecraftServer; -import net.minecraft.state.IProperty; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -import net.minecraftforge.registries.ForgeRegistries; import java.util.*; @@ -73,18 +70,7 @@ public class CommandAPI implements ILuaAPI { // Get the details of the block BlockState state = world.getBlockState( pos ); - Block block = state.getBlock(); - - Map table = new HashMap<>(); - table.put( "name", ForgeRegistries.BLOCKS.getKey( block ).toString() ); - - Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, Comparable> entry : state.getValues().entrySet() ) - { - IProperty property = entry.getKey(); - stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); - } - table.put( "state", stateTable ); + Map table = BlockData.fill( new HashMap<>(), state ); TileEntity tile = world.getTileEntity( pos ); if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.write( new CompoundNBT() ) ) ); @@ -92,13 +78,6 @@ public class CommandAPI implements ILuaAPI return table; } - @SuppressWarnings( { "unchecked", "rawtypes" } ) - private static Object getPropertyValue( IProperty property, Comparable value ) - { - if( value instanceof String || value instanceof Number || value instanceof Boolean ) return value; - return property.getName( value ); - } - @LuaFunction( mainThread = true ) public final Object[] exec( String command ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java new file mode 100644 index 000000000..d037be6af --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -0,0 +1,43 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.data; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.block.BlockState; +import net.minecraft.state.IProperty; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class BlockData +{ + @Nonnull + public static > T fill( @Nonnull T data, @Nonnull BlockState state ) + { + data.put( "name", Objects.toString( state.getBlock().getRegistryName() ) ); + + Map stateTable = new HashMap<>(); + for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) + { + IProperty property = entry.getKey(); + stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); + } + data.put( "state", stateTable ); + data.put( "tags", DataHelpers.getTags( state.getBlock().getTags() ) ); + + return data; + } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + private static Object getPropertyValue( IProperty property, Comparable value ) + { + if( value instanceof String || value instanceof Number || value instanceof Boolean ) return value; + return property.getName( value ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java new file mode 100644 index 000000000..8ed831dd0 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java @@ -0,0 +1,23 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.peripheral.generic.data; + +import net.minecraft.util.ResourceLocation; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class DataHelpers +{ + public static Map getTags( Collection tags ) + { + Map result = new HashMap<>( tags.size() ); + for( ResourceLocation location : tags ) result.put( location.toString(), true ); + return result; + } +} diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java similarity index 58% rename from src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java rename to src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java index 88c1b50ab..d4249d733 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/FluidMeta.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java @@ -4,7 +4,7 @@ * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.peripheral.generic.meta; +package dan200.computercraft.shared.peripheral.generic.data; import net.minecraftforge.fluids.FluidStack; @@ -12,13 +12,21 @@ import javax.annotation.Nonnull; import java.util.Map; import java.util.Objects; -public class FluidMeta +public class FluidData { @Nonnull - public static > T fillBasicMeta( @Nonnull T data, @Nonnull FluidStack stack ) + public static > T fillBasic( @Nonnull T data, @Nonnull FluidStack stack ) { data.put( "name", Objects.toString( stack.getFluid().getRegistryName() ) ); data.put( "amount", stack.getAmount() ); return data; } + + @Nonnull + public static > T fill( @Nonnull T data, @Nonnull FluidStack stack ) + { + fillBasic( data, stack ); + data.put( "tags", DataHelpers.getTags( stack.getFluid().getTags() ) ); + return data; + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java similarity index 87% rename from src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java rename to src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index d61a5b21f..534a10182 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/meta/ItemMeta.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -4,7 +4,7 @@ * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.peripheral.generic.meta; +package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; import net.minecraft.item.ItemStack; @@ -20,10 +20,10 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; -public class ItemMeta +public class ItemData { @Nonnull - public static > T fillBasicMeta( @Nonnull T data, @Nonnull ItemStack stack ) + public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) { data.put( "name", Objects.toString( stack.getItem().getRegistryName() ) ); data.put( "count", stack.getCount() ); @@ -31,14 +31,13 @@ public class ItemMeta } @Nonnull - public static > T fillMeta( @Nonnull T data, @Nonnull ItemStack stack ) + public static > T fill( @Nonnull T data, @Nonnull ItemStack stack ) { if( stack.isEmpty() ) return data; - fillBasicMeta( data, stack ); + fillBasic( data, stack ); data.put( "displayName", stack.getDisplayName().getString() ); - data.put( "rawName", stack.getTranslationKey() ); data.put( "maxCount", stack.getMaxStackSize() ); if( stack.isDamageable() ) @@ -52,6 +51,8 @@ public class ItemMeta data.put( "durability", stack.getItem().getDurabilityForDisplay( stack ) ); } + data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) ); + CompoundNBT tag = stack.getTag(); if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) ) { @@ -60,7 +61,7 @@ public class ItemMeta { ListNBT loreTag = displayTag.getList( "Lore", Constants.NBT.TAG_STRING ); data.put( "lore", loreTag.stream() - .map( ItemMeta::parseTextComponent ) + .map( ItemData::parseTextComponent ) .filter( Objects::nonNull ) .map( ITextComponent::getString ) .collect( Collectors.toList() ) ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java index a6918dbc6..26b631f68 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -12,7 +12,7 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.asm.GenericSource; -import dan200.computercraft.shared.peripheral.generic.meta.FluidMeta; +import dan200.computercraft.shared.peripheral.generic.data.FluidData; import net.minecraft.fluid.Fluid; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.capabilities.ICapabilityProvider; @@ -49,7 +49,7 @@ public class FluidMethods implements GenericSource for( int i = 0; i < size; i++ ) { FluidStack stack = fluids.getFluidInTank( i ); - if( !stack.isEmpty() ) result.put( i + 1, FluidMeta.fillBasicMeta( new HashMap<>( 4 ), stack ) ); + if( !stack.isEmpty() ) result.put( i + 1, FluidData.fillBasic( new HashMap<>( 4 ), stack ) ); } return result; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index cc1c37d0b..405532b0b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -12,7 +12,7 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.asm.GenericSource; -import dan200.computercraft.shared.peripheral.generic.meta.ItemMeta; +import dan200.computercraft.shared.peripheral.generic.data.ItemData; import net.minecraft.inventory.IInventory; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; @@ -56,19 +56,19 @@ public class InventoryMethods implements GenericSource for( int i = 0; i < size; i++ ) { ItemStack stack = inventory.getStackInSlot( i ); - if( !stack.isEmpty() ) result.put( i + 1, ItemMeta.fillBasicMeta( new HashMap<>( 4 ), stack ) ); + if( !stack.isEmpty() ) result.put( i + 1, ItemData.fillBasic( new HashMap<>( 4 ), stack ) ); } return result; } @LuaFunction( mainThread = true ) - public static Map getItemMeta( IItemHandler inventory, int slot ) throws LuaException + public static Map getItemDetail( IItemHandler inventory, int slot ) throws LuaException { assertBetween( slot, 1, inventory.getSlots(), "Slot out of range (%s)" ); ItemStack stack = inventory.getStackInSlot( slot - 1 ); - return stack.isEmpty() ? null : ItemMeta.fillMeta( new HashMap<>(), stack ); + return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack ); } @LuaFunction( mainThread = true ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 8283c7fbb..66753f3be 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -13,13 +13,12 @@ import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.event.TurtleActionEvent; import dan200.computercraft.api.turtle.event.TurtleInspectItemEvent; import dan200.computercraft.core.apis.IAPIEnvironment; +import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.tracking.TrackingField; +import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.turtle.core.*; -import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.registries.ForgeRegistries; import java.util.HashMap; import java.util.Map; @@ -309,28 +308,26 @@ public class TurtleAPI implements ILuaAPI } @LuaFunction - public final Object[] getItemDetail( Optional slotArg ) throws LuaException + public final MethodResult getItemDetail( ILuaContext context, Optional slotArg, Optional detailedArg ) throws LuaException { - // FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...) - // on another thread. The obvious solution is to move this into a command, but some programs rely - // on this having a 0-tick delay. int slot = checkSlot( slotArg ).orElse( turtle.getSelectedSlot() ); + boolean detailed = detailedArg.orElse( false ); + + return detailed + ? TaskCallback.make( context, () -> getItemDetail( slot, true ) ) + : MethodResult.of( getItemDetail( slot, false ) ); + } + + private Object[] getItemDetail( int slot, boolean detailed ) + { ItemStack stack = turtle.getInventory().getStackInSlot( slot ); if( stack.isEmpty() ) return new Object[] { null }; - Item item = stack.getItem(); - String name = ForgeRegistries.ITEMS.getKey( item ).toString(); - int count = stack.getCount(); + Map table = detailed + ? ItemData.fill( new HashMap<>(), stack ) + : ItemData.fillBasic( new HashMap<>(), stack ); - Map table = new HashMap<>(); - table.put( "name", name ); - table.put( "count", count ); - - Map tags = new HashMap<>(); - for( ResourceLocation location : item.getTags() ) tags.put( location.toString(), true ); - table.put( "tags", tags ); - - TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table ); + TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table, detailed ); if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() }; return new Object[] { table }; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index baa1ea966..d5f1d2499 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -5,20 +5,16 @@ */ package dan200.computercraft.shared.turtle.core; -import com.google.common.collect.ImmutableMap; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import net.minecraft.block.Block; +import dan200.computercraft.shared.peripheral.generic.data.BlockData; import net.minecraft.block.BlockState; -import net.minecraft.state.IProperty; import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; import java.util.HashMap; @@ -51,23 +47,7 @@ public class TurtleInspectCommand implements ITurtleCommand return TurtleCommandResult.failure( "No block to inspect" ); } - Block block = state.getBlock(); - String name = ForgeRegistries.BLOCKS.getKey( block ).toString(); - - Map table = new HashMap<>(); - table.put( "name", name ); - - Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) - { - IProperty property = entry.getKey(); - stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); - } - table.put( "state", stateTable ); - - Map tags = new HashMap<>(); - for( ResourceLocation location : block.getTags() ) tags.put( location.toString(), true ); - table.put( "tags", tags ); + Map table = BlockData.fill( new HashMap<>(), state ); // Fire the event, exiting if it is cancelled TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); @@ -77,11 +57,4 @@ public class TurtleInspectCommand implements ITurtleCommand return TurtleCommandResult.success( new Object[] { table } ); } - - @SuppressWarnings( { "unchecked", "rawtypes" } ) - private static Object getPropertyValue( IProperty property, Comparable value ) - { - if( value instanceof String || value instanceof Number || value instanceof Boolean ) return value; - return property.getName( value ); - } } From 9f8774960fe01f673fc9eae48a2dbfff100fb770 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 3 Jul 2020 13:31:26 +0100 Subject: [PATCH 271/711] Generate documentation stubs from Javadocs illuaminate does not handle Java files, for obvious reasons. In order to get around that, we have a series of stub files within /doc/stub which mirrored the Java ones. While this works, it has a few problems: - The link to source code does not work - it just links to the stub file. - There's no guarantee that documentation remains consistent with the Java code. This change found several methods which were incorrectly documented beforehand. We now replace this with a custom Java doclet[1], which extracts doc comments from @LuaFunction annotated methods and generates stub-files from them. These also contain a @source annotation, which allows us to correctly link them back to the original Java code. There's some issues with this which have yet to be fixed. However, I don't think any of them are major blockers right now: - The custom doclet relies on Java 9 - I think it's /technically/ possible to do this on Java 8, but the API is significantly uglier. This means that we need to run javadoc on a separate JVM. This is possible, and it works locally and on CI, but is definitely not a nice approach. - illuaminate now requires the doc stubs to be generated in order for the linter to pass, which does make running the linter locally much harder (especially given the above bullet point). We could notionally include the generated stubs (or at least a cut down version of them) in the repo, but I'm not 100% sure about that. [1]: https://docs.oracle.com/javase/9/docs/api/jdk/javadoc/doclet/package-summary.html --- .github/workflows/main-ci.yml | 12 +- .github/workflows/make-doc.yml | 19 ++ .gitignore | 1 + build.gradle | 32 ++- config/checkstyle/suppressions.xml | 3 + doc/stub/commands.lua | 77 ----- doc/stub/computer.lua | 27 -- doc/stub/drive.lua | 12 - doc/stub/fs.lua | 44 --- doc/stub/http.lua | 29 -- doc/stub/modem.lua | 73 ----- doc/stub/monitor.lua | 32 --- doc/stub/os.lua | 18 -- doc/stub/pocket.lua | 28 -- doc/stub/printer.lua | 11 - doc/stub/redstone.lua | 120 -------- doc/stub/term.lua | 2 - doc/stub/turtle.lua | 230 --------------- illuaminate.sexp | 17 +- .../dan200/computercraft/core/apis/FSAPI.java | 34 +++ .../computercraft/core/apis/HTTPAPI.java | 6 + .../dan200/computercraft/core/apis/OSAPI.java | 10 + .../core/apis/PeripheralAPI.java | 6 + .../computercraft/core/apis/RedstoneAPI.java | 130 ++++++++- .../computercraft/core/apis/TermAPI.java | 21 +- .../computercraft/core/apis/TermMethods.java | 3 + .../apis/http/websocket/WebsocketHandle.java | 37 ++- .../computercraft/core/asm/Generator.java | 4 +- .../shared/computer/apis/CommandAPI.java | 88 ++++++ .../computer/blocks/ComputerPeripheral.java | 37 +++ .../commandblock/CommandBlockPeripheral.java | 30 +- .../diskdrive/DiskDrivePeripheral.java | 13 + .../peripheral/modem/ModemPeripheral.java | 48 ++++ .../modem/wired/WiredModemPeripheral.java | 75 +++++ .../peripheral/monitor/MonitorPeripheral.java | 32 +++ .../peripheral/printer/PrinterPeripheral.java | 5 + .../peripheral/speaker/SpeakerPeripheral.java | 5 + .../shared/pocket/apis/PocketAPI.java | 32 +++ .../shared/turtle/apis/TurtleAPI.java | 268 +++++++++++++++++- .../upgrades/CraftingTablePeripheral.java | 7 + 40 files changed, 935 insertions(+), 743 deletions(-) delete mode 100644 doc/stub/commands.lua delete mode 100644 doc/stub/computer.lua delete mode 100644 doc/stub/drive.lua delete mode 100644 doc/stub/modem.lua delete mode 100644 doc/stub/monitor.lua delete mode 100644 doc/stub/pocket.lua delete mode 100644 doc/stub/printer.lua delete mode 100644 doc/stub/redstone.lua diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 1d947e320..a24e965bf 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -10,10 +10,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Set up JDK 1.8 + - name: Set up Java 8 uses: actions/setup-java@v1 with: - java-version: 1.8 + java-version: 8 - name: Cache gradle dependencies uses: actions/cache@v1 @@ -35,12 +35,8 @@ jobs: - name: Upload Coverage run: bash <(curl -s https://codecov.io/bash) - lint-lua: - name: Lint Lua - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 + - name: Generate Java documentation stubs + run: ./gradlew luaJavadoc --no-daemon - name: Lint Lua code run: | diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index 16a905dae..3abf5d265 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -17,6 +17,25 @@ jobs: steps: - uses: actions/checkout@v1 + - name: Set up Java 8 + uses: actions/setup-java@v1 + with: + java-version: 8 + + - name: Cache gradle dependencies + uses: actions/cache@v1 + with: + path: ~/.gradle/caches + key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Build with Gradle + run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon + + - name: Generate Java documentation stubs + run: ./gradlew luaJavadoc --no-daemon + - name: Build documentation run: | test -d bin || mkdir bin diff --git a/.gitignore b/.gitignore index 42f6759db..63cc1d148 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /build /out /doc/**/*.html +/doc/javadoc/ /doc/index.json # Runtime directories diff --git a/build.gradle b/build.gradle index bd89387a1..590c6a713 100644 --- a/build.gradle +++ b/build.gradle @@ -33,6 +33,8 @@ version = mod_version group = "org.squiddev" archivesBaseName = "cc-tweaked-${mc_version}" +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' + minecraft { runs { client { @@ -78,11 +80,14 @@ minecraft { accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') } -sourceSets.main.resources { - srcDir 'src/generated/resources' +sourceSets { + main.resources { + srcDir 'src/generated/resources' + } } repositories { + mavenCentral() maven { name "SquidDev" url "https://squiddev.cc/maven" @@ -93,6 +98,7 @@ configurations { shade compile.extendsFrom shade deployerJars + cctJavadoc } dependencies { @@ -115,6 +121,8 @@ dependencies { testImplementation 'org.hamcrest:hamcrest:2.2' deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" + + cctJavadoc 'cc.tweaked:cct-javadoc:1.0.0' } // Compile tasks @@ -123,6 +131,24 @@ javadoc { include "dan200/computercraft/api/**/*.java" } +task luaJavadoc(type: Javadoc) { + description "Generates documentation for Java-side Lua functions." + group "documentation" + + source = sourceSets.main.allJava + destinationDir = file("doc/javadoc") + classpath = sourceSets.main.compileClasspath + + options.docletpath = configurations.cctJavadoc.files as List + options.doclet = "cc.tweaked.javadoc.LuaDoclet" + + // Attempt to run under Java 11 (any Java >= 9 will work though). + if(System.getProperty("java.version").startsWith("1.") + && (System.getenv("JAVA_HOME_11_X64") != null || project.hasProperty("java11Home"))) { + executable = "${System.getenv("JAVA_HOME_11_X64") ?: project.property("java11Home")}/bin/javadoc" + } +} + jar { dependsOn javadoc @@ -149,8 +175,6 @@ jar { } } - - import java.nio.charset.StandardCharsets import java.nio.file.* import java.util.zip.* diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml index 2de81460e..ede3f3dea 100644 --- a/config/checkstyle/suppressions.xml +++ b/config/checkstyle/suppressions.xml @@ -9,4 +9,7 @@ + + + diff --git a/doc/stub/commands.lua b/doc/stub/commands.lua deleted file mode 100644 index e1001230e..000000000 --- a/doc/stub/commands.lua +++ /dev/null @@ -1,77 +0,0 @@ ---- Execute a specific command. --- --- @tparam string command The command to execute. --- @treturn boolean Whether the command executed successfully. --- @treturn { string... } The output of this command, as a list of lines. --- @treturn number|nil The number of "affected" objects, or `nil` if the command --- failed. The definition of this varies from command to command. --- @usage Set the block above the command computer to stone. --- --- commands.exec("setblock ~ ~1 ~ minecraft:stone") -function exec(command) end - ---- Asynchronously execute a command. --- --- Unlike @{exec}, this will immediately return, instead of waiting for the --- command to execute. This allows you to run multiple commands at the same --- time. --- --- When this command has finished executing, it will queue a `task_complete` --- event containing the result of executing this command (what @{exec} would --- return). --- --- @tparam string command The command to execute. --- @treturn number The "task id". When this command has been executed, it will --- queue a `task_complete` event with a matching id. --- @usage Asynchronously sets the block above the computer to stone. --- --- commands.execAsync("~ ~1 ~ minecraft:stone") --- @see parallel One may also use the parallel API to run multiple commands at --- once. -function execAsync(commad) end - ---- List all available commands which the computer has permission to execute. --- --- @treturn { string... } A list of all available commands -function list() end - ---- Get the position of the current command computer. --- --- @treturn number This computer's x position. --- @treturn number This computer's y position. --- @treturn number This computer's z position. --- @see gps.locate To get the position of a non-command computer. -function getBlockPosition() end - ---- Get some basic information about a block. --- --- The returned table contains the current name, metadata and block state (as --- with @{turtle.inspect}). If there is a tile entity for that block, its NBT --- will also be returned. --- --- @tparam number x The x position of the block to query. --- @tparam number y The y position of the block to query. --- @tparam number z The z position of the block to query. --- @treturn table The given block's information. --- @throws If the coordinates are not within the world, or are not currently --- loaded. -function getBlockInfo(x, y, z) end - ---- Get information about a range of blocks. --- --- This returns the same information as @{getBlockInfo}, just for multiple --- blocks at once. --- --- Blocks are traversed by ascending y level, followed by z and x - the returned --- table may be indexed using `x + z*width + y*depth*depth`. --- --- @tparam number min_x The start x coordinate of the range to query. --- @tparam number min_y The start y coordinate of the range to query. --- @tparam number min_z The start z coordinate of the range to query. --- @tparam number max_x The end x coordinate of the range to query. --- @tparam number max_y The end y coordinate of the range to query. --- @tparam number max_z The end z coordinate of the range to query. --- @treturn { table... } A list of information about each block. --- @throws If the coordinates are not within the world. --- @throws If trying to get information about more than 4096 blocks. -function getBlockInfos(min_x, min_y, min_z, max_x, max_y, max_z) end diff --git a/doc/stub/computer.lua b/doc/stub/computer.lua deleted file mode 100644 index 421fae547..000000000 --- a/doc/stub/computer.lua +++ /dev/null @@ -1,27 +0,0 @@ ---- A computer or turtle wrapped as a peripheral. --- --- This allows for basic interaction with adjacent computers. Computers wrapped --- as peripherals will have the type `computer` while turtles will be `turtle`. --- --- @module[kind=peripheral] computer - -function turnOn() end --- Turn the other computer on. -function shutdown() end --- Shutdown the other computer. -function reboot() end --- Reboot or turn on the other computer. - ---- Get the other computer's ID. --- --- @treturn number The computer's ID. --- @see os.getComputerID To get your computer ID. -function getID() end - ---- Determine if the other computer is on. --- --- @treturn boolean If the computer is on. -function isOn() end - ---- Get the other computer's label. --- --- @treturn string|nil The computer's label. --- @see os.getComputerLabel To get your label. -function getLabel() end diff --git a/doc/stub/drive.lua b/doc/stub/drive.lua deleted file mode 100644 index f9c5ac469..000000000 --- a/doc/stub/drive.lua +++ /dev/null @@ -1,12 +0,0 @@ ---- @module[kind=peripheral] drive - -function isDiskPresent() end -function getDiskLabel() end -function setDiskLabel(label) end -function hasData() end -function getMountPath() end -function hasAudio() end -function getAudioTitle() end -function playAudio() end -function ejectDisk() end -function getDiskID() end diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua index 41e1db8e1..4b20a96ed 100644 --- a/doc/stub/fs.lua +++ b/doc/stub/fs.lua @@ -2,23 +2,6 @@ -- -- @module fs -function list(path) end -function combine(base, child) end -function getName(path) end -function getSize(path) end -function exists(path) end -function isDir(path) end -function isReadOnly(path) end -function makeDir(path) end -function move(from, to) end -function copy(from, to) end -function delete(path) end -function open(path, mode) end -function getDrive(path) end -function getFreeSpace(path) end -function find(pattern) end -function getDir(path) end - --- Returns true if a path is mounted to the parent filesystem. -- -- The root filesystem "/" is considered a mount, along with disk folders and @@ -31,33 +14,6 @@ function getDir(path) end -- @see getDrive function isDriveRoot(path) end ---- Get the capacity of the drive at the given path. --- --- This may be used in conjunction with @{getFreeSpace} to determine what --- percentage of this drive has been used. --- --- @tparam string path The path of the drive to get. --- @treturn number This drive's capacity. This will be 0 for "read-only" drives, --- such as the ROM or treasure disks. -function getCapacity(path) end - ---- Get attributes about a specific file or folder. --- --- The returned attributes table contains information about the size of the --- file, whether it is a directory, and when it was created and last modified. --- --- The creation and modification times are given as the number of milliseconds --- since the UNIX epoch. This may be given to @{os.date} in order to convert it --- to more usable form. --- --- @tparam string path The path to get attributes for. --- @treturn { size = number, isDir = boolean, created = number, modified = number } --- The resulting attributes. --- @throws If the path does not exist. --- @see getSize If you only care about the file's size. --- @see isDir If you only care whether a path is a directory or not. -function attributes(path) end - -- Defined in bios.lua function complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) end diff --git a/doc/stub/http.lua b/doc/stub/http.lua index 8e8a24c08..7f9b51296 100644 --- a/doc/stub/http.lua +++ b/doc/stub/http.lua @@ -198,32 +198,3 @@ function websocket(url, headers) end -- @tparam[opt] { [string] = string } headers Additional headers to send as part -- of the initial websocket connection. function websocketAsync(url, headers) end - ---- A websocket, which can be used to send an receive messages with a web --- server. --- --- @type Websocket --- @see http.websocket On how to open a websocket. -local Websocket = {} - ---- Send a websocket message to the connected server. --- --- @tparam string message The message to send. --- @tparam[opt] boolean binary Whether this message should be treated as a --- binary string, rather than encoded text. --- @throws If the websocket has been closed. -function Websocket.send(message, binary) end - ---- Wait for a message from the server. --- --- @tparam[opt] number timeout The number of seconds to wait if no message is --- received. --- @treturn[1] string The received message. --- @treturn boolean If this was a binary message. --- @treturn[2] nil If the websocket was closed while waiting, or if we timed out. --- @throws If the websocket has been closed. -function Websocket.receive(timeout) end - ---- Close this websocket. This will terminate the connection, meaning messages --- can no longer be sent or received along it. -function Websocket.close() end diff --git a/doc/stub/modem.lua b/doc/stub/modem.lua deleted file mode 100644 index 874568c51..000000000 --- a/doc/stub/modem.lua +++ /dev/null @@ -1,73 +0,0 @@ ---- @module[kind=peripheral] modem - -function open(channel) end -function isOpen(channel) end -function close(channel) end - ---- Close all open channels. -function closeAll() end - -function transmit(channel, replyChannel, payload) end - ---- Determine if this is a wired or wireless modem. --- --- Some methods (namely those dealing with wired networks and remote --- peripherals) are only available on wired modems. --- --- @treturn boolean @{true} if this is a wireless modem. -function isWireless() end - --- Wired modem only - ---- List all remote peripherals on the wired network. --- --- If this computer is attached to the network, it _will not_ be included in --- this list. --- --- > **Important:** This function only appears on wired modems. Check --- > @{isWireless} returns false before calling it. --- --- @treturn { string... } Remote peripheral names on the network. -function getNamesRemote(name) end - ---- Determine if a peripheral is available on this wired network. --- --- > **Important:** This function only appears on wired modems. Check --- > @{isWireless} returns false before calling it. --- --- @tparam string name The peripheral's name. --- @treturn boolean If a peripheral is present with the given name. --- @see peripheral.isPresent -function isPresentRemote(name) end - ---- Get the type of a peripheral is available on this wired network. --- --- > **Important:** This function only appears on wired modems. Check --- > @{isWireless} returns false before calling it. --- --- @tparam string name The peripheral's name. --- @treturn string|nil The peripheral's type, or `nil` if it is not present. --- @see peripheral.getType -function getTypeRemote(name) end - ---- Call a method on a peripheral on this wired network. --- --- > **Important:** This function only appears on wired modems. Check --- > @{isWireless} returns false before calling it. --- --- @tparam string remoteName The name of the peripheral to invoke the method on. --- @tparam string method The name of the method --- @param ... Additional arguments to pass to the method --- @return The return values of the peripheral method. --- @see peripheral.call -function callRemote(remoteName, method, ...) end - ---- Returns the network name of the current computer, if the modem is on. This --- may be used by other computers on the network to wrap this computer as a --- peripheral. --- --- > **Important:** This function only appears on wired modems. Check --- > @{isWireless} returns false before calling it. --- --- @treturn string|nil The current computer's name on the wired network. -function getNameLocal() end diff --git a/doc/stub/monitor.lua b/doc/stub/monitor.lua deleted file mode 100644 index cea79560d..000000000 --- a/doc/stub/monitor.lua +++ /dev/null @@ -1,32 +0,0 @@ ---[[- Monitors are a block which act as a terminal, displaying information on -one side. This allows them to be read and interacted with in-world without -opening a GUI. - -Monitors act as @{term.Redirect|terminal redirects} and so expose the same -methods, as well as several additional ones, which are documented below. - -Like computers, monitors come in both normal (no colour) and advanced (colour) -varieties. - -@module[kind=peripheral] monitor -@usage Write "Hello, world!" to an adjacent monitor: - - local monitor = peripheral.find("monitor") - monitor.setCursorPos(1, 1) - monitor.write("Hello, world!") -]] - - ---- Set the scale of this monitor. A larger scale will result in the monitor --- having a lower resolution, but display text much larger. --- --- @tparam number scale The monitor's scale. This must be a multiple of 0.5 --- between 0.5 and 5. --- @throws If the scale is out of range. --- @see getTextScale -function setTextScale(scale) end - ---- Get the monitor's current text scale. --- --- @treturn number The monitor's current scale. -function getTextScale() end diff --git a/doc/stub/os.lua b/doc/stub/os.lua index 2703b4d42..2c9f730f4 100644 --- a/doc/stub/os.lua +++ b/doc/stub/os.lua @@ -1,21 +1,3 @@ -function queueEvent(event, ...) end -function startTimer(delay) end -function setAlarm(time) end -function shutdown() end -function reboot() end -function getComputerID() end -computerID = getComputerID -function setComputerLabel(label) end -function getComputerLabel() end -computerLabel = getComputerLabel -function clock() end -function time(timezone) end -function day(timezone) end -function cancelTimer(id) end -function cancelAlarm(id) end -function epoch(timezone) end -function date(format, time) end - -- Defined in bios.lua function loadAPI(path) end function pullEvent(filter) end diff --git a/doc/stub/pocket.lua b/doc/stub/pocket.lua deleted file mode 100644 index c37da798f..000000000 --- a/doc/stub/pocket.lua +++ /dev/null @@ -1,28 +0,0 @@ ---[[- -Control the current pocket computer, adding or removing upgrades. - -This API is only available on pocket computers. As such, you may use its -presence to determine what kind of computer you are using: - -```lua -if pocket then - print("On a pocket computer") -else - print("On something else") -end -``` -]] - ---- Search the player's inventory for another upgrade, replacing the existing --- one with that item if found. --- --- This inventory search starts from the player's currently selected slot, --- allowing you to prioritise upgrades. --- --- @throws If an upgrade cannot be found. -function equipBack() end - ---- Remove the pocket computer's current upgrade. --- --- @throws If this pocket computer does not currently have an upgrade. -function unequipBack() end diff --git a/doc/stub/printer.lua b/doc/stub/printer.lua deleted file mode 100644 index 674aab13a..000000000 --- a/doc/stub/printer.lua +++ /dev/null @@ -1,11 +0,0 @@ ---- @module[kind=peripheral] printer - -function write(text) end -function getCursorPos() end -function setCursorPos(x, y) end -function getPageSize() end -function newPage() end -function endPage() end -function setPageTitle(title) end -function getInkLevel() end -function getPaperLevel() end diff --git a/doc/stub/redstone.lua b/doc/stub/redstone.lua deleted file mode 100644 index d19a80487..000000000 --- a/doc/stub/redstone.lua +++ /dev/null @@ -1,120 +0,0 @@ ---[[- Interact with redstone attached to this computer. - -The @{redstone} library exposes three "types" of redstone control: - - Binary input/output (@{setOutput}/@{getInput}): These simply check if a - redstone wire has any input or output. A signal strength of 1 and 15 are - treated the same. - - Analogue input/output (@{setAnalogueOutput}/@{getAnalogueInput}): These - work with the actual signal strength of the redstone wired, from 0 to 15. - - Bundled cables (@{setBundledOutput}/@{getBundledInput}): These interact with - "bundled" cables, such as those from Project:Red. These allow you to send - 16 separate on/off signals. Each channel corresponds to a colour, with the - first being @{colors.white} and the last @{colors.black}. - -Whenever a redstone input changes, a `redstone` event will be fired. This may -be used in or - -This module may also be referred to as `rs`. For example, one may call -`rs.getSides()` instead of @{redstone.getSides}. - -@module redstone -@usage Toggle the redstone signal above the computer every 0.5 seconds. - - while true do - redstone.setOutput("top", not redstone.getOutput("top")) - sleep(0.5) - end -@usage Mimic a redstone comparator in [subtraction mode][comparator]. - - while true do - local rear = rs.getAnalogueInput("back") - local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right")) - rs.setAnalogueOutput("front", math.max(rear - sides, 0)) - - os.pullEvent("redstone") -- Wait for a change to inputs. - end - -[comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on the Minecraft wiki." -]] - ---- Returns a table containing the six sides of the computer. Namely, "top", --- "bottom", "left", "right", "front" and "back". --- --- @treturn { string... } A table of valid sides. -function getSides() end - ---- Turn the redstone signal of a specific side on or off. --- --- @tparam string side The side to set. --- @tparam boolean on Whether the redstone signal should be on or off. When on, --- a signal strength of 15 is emitted. -function setOutput(side, on) end - ---- Get the current redstone output of a specific side. --- --- @tparam string side The side to get. --- @treturn boolean Whether the redstone output is on or off. --- @see setOutput -function getOutput(side) end - ---- Get the current redstone input of a specific side. --- --- @tparam string side The side to get. --- @treturn boolean Whether the redstone input is on or off. -function getInput(side) end - ---- Set the redstone signal strength for a specific side. --- --- @tparam string side The side to set. --- @tparam number value The signal strength, between 0 and 15. --- @throws If `value` is not between 0 and 15. -function setAnalogOutput(side, value) end -setAnalogueOutput = setAnalogOutput - ---- Get the redstone output signal strength for a specific side. --- --- @tparam string side The side to get. --- @treturn number The output signal strength, between 0 and 15. --- @see setAnalogueOutput -function getAnalogOutput(sid) end -getAnalogueOutput = getAnalogOutput - ---- Get the redstone input signal strength for a specific side. --- --- @tparam string side The side to get. --- @treturn number The input signal strength, between 0 and 15. -function getAnalogInput(side) end -getAnalogueInput = getAnalogInput - ---- Set the bundled cable output for a specific side. --- --- @tparam string side The side to set. --- @tparam number The colour bitmask to set. --- @see colors.subtract For removing a colour from the bitmask. --- @see colors.combine For adding a colour to the bitmask. -function setBundledOutput(side, output) end - ---- Get the bundled cable output for a specific side. --- --- @tparam string side The side to get. --- @treturn number The bundled cable's output. -function getBundledOutput(side) end - ---- Get the bundled cable input for a specific side. --- --- @tparam string side The side to get. --- @treturn number The bundled cable's input. --- @see testBundledInput To determine if a specific colour is set. -function getBundledInput(side) end - ---- Determine if a specific combination of colours are on for the given side. --- --- @tparam string side The side to test. --- @tparam number mask The mask to test. --- @see getBundledInput --- @see colors.combine For adding a colour to the bitmask. --- @usage Check if @{colors.white} and @{colors.black} are on for above the --- computer. --- --- print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black))) -function testBundledInput(side, mask) end diff --git a/doc/stub/term.lua b/doc/stub/term.lua index fb30c5c36..a9ea4e058 100644 --- a/doc/stub/term.lua +++ b/doc/stub/term.lua @@ -21,8 +21,6 @@ function setPaletteColour(colour, ...) end setPaletteColor = setPaletteColour function getPaletteColour(colour, ...) end getPaletteColor = getPaletteColour -function nativePaletteColour(colour) end -nativePaletteColor = nativePaletteColour --- @type Redirect local Redirect = {} diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua index 2c3619469..f5668f1ae 100644 --- a/doc/stub/turtle.lua +++ b/doc/stub/turtle.lua @@ -1,231 +1 @@ ---- Move the turtle forward one block. --- @treturn boolean Whether the turtle could successfully move. --- @treturn string|nil The reason the turtle could not move. -function forward() end - ---- Move the turtle backwards one block. --- @treturn boolean Whether the turtle could successfully move. --- @treturn string|nil The reason the turtle could not move. -function back() end - ---- Move the turtle up one block. --- @treturn boolean Whether the turtle could successfully move. --- @treturn string|nil The reason the turtle could not move. -function up() end - ---- Move the turtle down one block. --- @treturn boolean Whether the turtle could successfully move. --- @treturn string|nil The reason the turtle could not move. -function down() end - ---- Rotate the turtle 90 degress to the left. -function turnLeft() end - ---- Rotate the turtle 90 degress to the right. -function turnRight() end - ---- Attempt to break the block in front of the turtle. --- --- This requires a turtle tool capable of breaking the block. Diamond pickaxes --- (mining turtles) can break any vanilla block, but other tools (such as axes) --- are more limited. --- --- @tparam[opt] "left"|"right" side The specific tool to use. --- @treturn boolean Whether a block was broken. --- @treturn string|nil The reason no block was broken. -function dig(side) end - ---- Attempt to break the block above the turtle. See @{dig} for full details. --- --- @tparam[opt] "left"|"right" side The specific tool to use. --- @treturn boolean Whether a block was broken. --- @treturn string|nil The reason no block was broken. -function digUp(side) end - ---- Attempt to break the block below the turtle. See @{dig} for full details. --- --- @tparam[opt] "left"|"right" side The specific tool to use. --- @treturn boolean Whether a block was broken. --- @treturn string|nil The reason no block was broken. -function digDown(side) end - ---- Attack the entity in front of the turtle. --- --- @tparam[opt] "left"|"right" side The specific tool to use. --- @treturn boolean Whether an entity was attacked. --- @treturn string|nil The reason nothing was attacked. -function attack(side) end - ---- Attack the entity above the turtle. --- --- @tparam[opt] "left"|"right" side The specific tool to use. --- @treturn boolean Whether an entity was attacked. --- @treturn string|nil The reason nothing was attacked. -function attackUp(side) end - ---- Attack the entity below the turtle. --- --- @tparam[opt] "left"|"right" side The specific tool to use. --- @treturn boolean Whether an entity was attacked. --- @treturn string|nil The reason nothing was attacked. -function attackDown(side) end - ---- Place a block or item into the world in front of the turtle. --- --- @treturn boolean Whether the block could be placed. --- @treturn string|nil The reason the block was not placed. -function place() end - ---- Place a block or item into the world above the turtle. --- --- @treturn boolean Whether the block could be placed. --- @treturn string|nil The reason the block was not placed. -function placeUp() end - ---- Place a block or item into the world below the turtle. --- --- @treturn boolean Whether the block could be placed. --- @treturn string|nil The reason the block was not placed. -function placeDown() end - ---- Drop the currently selected stack into the inventory in front of the turtle, --- or as an item into the world if there is no inventory. --- --- @tparam[opt] number count The number of items to drop. If not given, the --- entire stack will be dropped. --- @treturn boolean Whether items were dropped. --- @treturn string|nil The reason the no items were dropped. --- @see select -function drop(count) end - ---- Drop the currently selected stack into the inventory above the turtle, or as --- an item into the world if there is no inventory. --- --- @tparam[opt] number count The number of items to drop. If not given, the --- entire stack will be dropped. --- @treturn boolean Whether items were dropped. --- @treturn string|nil The reason the no items were dropped. --- @see select -function dropUp(count) end - ---- Drop the currently selected stack into the inventory below the turtle, or as --- an item into the world if there is no inventory. --- --- @tparam[opt] number count The number of items to drop. If not given, the --- entire stack will be dropped. --- @treturn boolean Whether items were dropped. --- @treturn string|nil The reason the no items were dropped. --- @see select -function dropDown(count) end - ---- Suck an item from the inventory in front of the turtle, or from an item --- floating in the world. --- --- This will pull items into the first acceptable slot, starting at the --- @{select|currently selected} one. --- --- @tparam[opt] number count The number of items to suck. If not given, up to a --- stack of items will be picked up. --- @treturn boolean Whether items were picked up. --- @treturn string|nil The reason the no items were picked up. -function suck(count) end - ---- Suck an item from the inventory above the turtle, or from an item floating --- in the world. --- --- @tparam[opt] number count The number of items to suck. If not given, up to a --- stack of items will be picked up. --- @treturn boolean Whether items were picked up. --- @treturn string|nil The reason the no items were picked up. -function suckUp(count) end - ---- Suck an item from the inventory below the turtle, or from an item floating --- in the world. --- --- @tparam[opt] number count The number of items to suck. If not given, up to a --- stack of items will be picked up. --- @treturn boolean Whether items were picked up. --- @treturn string|nil The reason the no items were picked up. -function suckDown(count) end - ---- Check if there is a solid block in front of the turtle. In this case, solid --- refers to any non-air or liquid block. --- --- @treturn boolean If there is a solid block in front. -function detect() end - ---- Check if there is a solid block above the turtle. --- --- @treturn boolean If there is a solid block above. -function detectUp() end - ---- Check if there is a solid block below the turtle. --- --- @treturn boolean If there is a solid block below. -function detectDown() end - -function compare() end -function compareUp() end -function compareDown() end - -function inspect() end -function inspectUp() end -function inspectDown() end - - ---- Change the currently selected slot. --- --- The selected slot is determines what slot actions like @{drop} or --- @{getItemCount} act on. --- --- @tparam number slot The slot to select. --- @see getSelectedSlot -function select(slot) end - ---- Get the currently selected slot. --- --- @treturn number The current slot. --- @see select -function getSelectedSlot() end - ---- Get the number of items in the given slot. --- --- @tparam[opt] number slot The slot we wish to check. Defaults to the @{turtle.select|selected slot}. --- @treturn number The number of items in this slot. -function getItemCount(slot) end - ---- Get the remaining number of items which may be stored in this stack. --- --- For instance, if a slot contains 13 blocks of dirt, it has room for another 51. --- --- @tparam[opt] number slot The slot we wish to check. Defaults to the @{turtle.select|selected slot}. --- @treturn number The space left in this slot. -function getItemSpace(slot) end - - ---- Get detailed information about the items in the given slot. --- --- @tparam[opt] number slot The slot to get information about. Defaults to the @{turtle.select|selected slot}. --- @tparam[opt] boolean detailed Whether to include "detailed" information. When @{true} the method will contain --- much more information about the item at the cost of taking longer to run. --- @treturn nil|table Information about the given slot, or @{nil} if it is empty. --- @usage Print the current slot, assuming it contains 13 dirt. --- --- print(textutils.serialize(turtle.getItemDetail())) --- -- => { --- -- name = "minecraft:dirt", --- -- count = 13, --- -- } -function getItemDetail(slot, detailed) end - -function getFuelLevel() end - -function refuel(count) end -function compareTo(slot) end -function transferTo(slot, count) end - -function getFuelLimit() end -function equipLeft() end -function equipRight() end - function craft(limit) end diff --git a/illuaminate.sexp b/illuaminate.sexp index 75e011de6..80276a487 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -2,6 +2,7 @@ (sources /doc/stub/ + /doc/javadoc/ /src/main/resources/*/computercraft/lua/bios.lua /src/main/resources/*/computercraft/lua/rom/ /src/test/resources/test-rom) @@ -17,6 +18,7 @@ (library-path /doc/stub/ + /doc/javadoc/ /src/main/resources/*/computercraft/lua/rom/apis /src/main/resources/*/computercraft/lua/rom/apis/command @@ -67,7 +69,7 @@ (lint (allow-toplevel-global true))) ;; Silence some variable warnings in documentation stubs. -(at /doc/stub +(at (/doc/stub/ /doc/javadoc/) (linters -var:unused-global) (lint (allow-toplevel-global true))) @@ -79,15 +81,20 @@ /doc/stub/os.lua /doc/stub/term.lua /doc/stub/turtle.lua + ; Java generated APIs + /doc/javadoc/fs.lua + /doc/javadoc/http.lua + /doc/javadoc/os.lua + /doc/javadoc/turtle.lua ; Peripherals - /doc/stub/drive.lua - /doc/stub/modem.lua - /doc/stub/printer.lua + /doc/javadoc/drive.lua + /doc/javadoc/speaker.lua + /doc/javadoc/printer.lua ; Lua APIs /src/main/resources/*/computercraft/lua/rom/apis/io.lua /src/main/resources/*/computercraft/lua/rom/apis/window.lua) - (linters -doc:undocumented -doc:undocumented-arg)) + (linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return)) ;; These currently rely on unknown references. (at diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index f9f45a243..288f93636 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -28,6 +28,11 @@ import java.util.Map; import java.util.OptionalLong; import java.util.function.Function; +/** + * The FS API allows you to manipulate files and the filesystem. + * + * @cc.module fs + */ public class FSAPI implements ILuaAPI { private final IAPIEnvironment environment; @@ -291,6 +296,19 @@ public class FSAPI implements ILuaAPI } } + /** + * Returns true if a path is mounted to the parent filesystem. + * + * The root filesystem "/" is considered a mount, along with disk folders and the rom folder. Other programs + * (such as network shares) can extend this to make other mount types by correctly assigning their return value for + * getDrive. + * + * @param path The path of the drive to get. + * @return The drive's capacity. + * @throws LuaException If the capacity cannot be determined. + * @cc.treturn number|nil This drive's capacity. This will be nil for "read-only" drives, such as the ROM or + * treasure disks. + */ @LuaFunction public final Object getCapacity( String path ) throws LuaException { @@ -305,6 +323,22 @@ public class FSAPI implements ILuaAPI } } + /** + * Get attributes about a specific file or folder. + * + * The returned attributes table contains information about the size of the file, whether it is a directory, and + * when it was created and last modified. + * + * The creation and modification times are given as the number of milliseconds since the UNIX epoch. This may be + * given to {@link OSAPI#date} in order to convert it to more usable form. + * + * @param path The path to get attributes for. + * @return The resulting attributes. + * @throws LuaException If the path does not exist. + * @cc.treturn { size = number, isDir = boolean, created = number, modified = number } The resulting attributes. + * @see #getSize If you only care about the file's size. + * @see #isDir If you only care whether a path is a directory or not. + */ @LuaFunction public final Map attributes( String path ) throws LuaException { diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index fa0af20ea..71163f064 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -26,6 +26,12 @@ import java.util.Optional; import static dan200.computercraft.core.apis.TableHelper.*; +/** + * The http library allows communicating with web servers, sending and receiving data from them. + * + * @cc.module http + * @hidden + */ public class HTTPAPI implements ILuaAPI { private final IAPIEnvironment m_apiEnvironment; diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 1b63323ea..34ee37853 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -23,6 +23,11 @@ import java.util.*; import static dan200.computercraft.api.lua.LuaValues.checkFinite; +/** + * The {@link OSAPI} API allows interacting with the current computer. + * + * @cc.module os + */ public class OSAPI implements ILuaAPI { private final IAPIEnvironment apiEnvironment; @@ -213,6 +218,11 @@ public class OSAPI implements ILuaAPI return label == null ? null : new Object[] { label }; } + /** + * Set the label of this computer. + * + * @param label The new label. May be {@code nil} in order to clear it. + */ @LuaFunction public final void setComputerLabel( Optional label ) { diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index ee37d3ba4..b132ad48c 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -22,6 +22,12 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; +/** + * CC's "native" peripheral API. This is wrapped within CraftOS to provide a version which works with modems. + * + * @cc.module peripheral + * @hidden + */ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener { private class PeripheralWrapper extends ComputerAccess diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index ce70fc5d2..ab096fd08 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -10,6 +10,48 @@ import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.core.computer.ComputerSide; +/** + * Interact with redstone attached to this computer. + * + * The {@link RedstoneAPI} library exposes three "types" of redstone control: + * - Binary input/output ({@link #setOutput}/{@link #getInput}): These simply check if a redstone wire has any input or + * output. A signal strength of 1 and 15 are treated the same. + * - Analogue input/output ({@link #setAnalogOutput}/{@link #getAnalogInput}): These work with the actual signal + * strength of the redstone wired, from 0 to 15. + * - Bundled cables ({@link #setBundledOutput}/{@link #getBundledInput}): These interact with "bundled" cables, such + * as those from Project:Red. These allow you to send 16 separate on/off signals. Each channel corresponds to a + * colour, with the first being @{colors.white} and the last @{colors.black}. + * + * Whenever a redstone input changes, a {@code redstone} event will be fired. This may be used instead of repeativly + * polling. + * + * This module may also be referred to as {@code rs}. For example, one may call {@code rs.getSides()} instead of + * {@link #getSides}. + * + * @cc.usage Toggle the redstone signal above the computer every 0.5 seconds. + * + *
+ * while true do
+ *   redstone.setOutput("top", not redstone.getOutput("top"))
+ *   sleep(0.5)
+ * end
+ * 
+ * @cc.usage Mimic a redstone comparator in [subtraction mode][comparator]. + * + *
+ * while true do
+ *   local rear = rs.getAnalogueInput("back")
+ *   local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right"))
+ *   rs.setAnalogueOutput("front", math.max(rear - sides, 0))
+ *
+ *   os.pullEvent("redstone") -- Wait for a change to inputs.
+ * end
+ * 
+ * + * [comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on + * the Minecraft wiki." + * @cc.module redstone + */ public class RedstoneAPI implements ILuaAPI { private final IAPIEnvironment environment; @@ -25,67 +67,145 @@ public class RedstoneAPI implements ILuaAPI return new String[] { "rs", "redstone" }; } + /** + * Returns a table containing the six sides of the computer. Namely, "top", "bottom", "left", "right", "front" and + * "back". + * + * @return A table of valid sides. + */ @LuaFunction public final String[] getSides() { return ComputerSide.NAMES; } + /** + * Turn the redstone signal of a specific side on or off. + * + * @param side The side to set. + * @param on Whether the redstone signal should be on or off. When on, a signal strength of 15 is emitted. + */ @LuaFunction - public final void setOutput( ComputerSide side, boolean output ) + public final void setOutput( ComputerSide side, boolean on ) { - environment.setOutput( side, output ? 15 : 0 ); + environment.setOutput( side, on ? 15 : 0 ); } + /** + * Get the current redstone output of a specific side. + * + * @param side The side to get. + * @return Whether the redstone output is on or off. + * @see #setOutput + */ @LuaFunction public final boolean getOutput( ComputerSide side ) { return environment.getOutput( side ) > 0; } + /** + * Get the current redstone input of a specific side. + * + * @param side The side to get. + * @return Whether the redstone input is on or off. + */ @LuaFunction public final boolean getInput( ComputerSide side ) { return environment.getInput( side ) > 0; } + /** + * Set the redstone signal strength for a specific side. + * + * @param side The side to set. + * @param value The signal strength between 0 and 15. + * @throws LuaException If {@code value} is not betwene 0 and 15. + */ @LuaFunction( { "setAnalogOutput", "setAnalogueOutput" } ) - public final void setAnalogOutput( ComputerSide side, int output ) throws LuaException + public final void setAnalogOutput( ComputerSide side, int value ) throws LuaException { - if( output < 0 || output > 15 ) throw new LuaException( "Expected number in range 0-15" ); - environment.setOutput( side, output ); + if( value < 0 || value > 15 ) throw new LuaException( "Expected number in range 0-15" ); + environment.setOutput( side, value ); } + /** + * Get the redstone output signal strength for a specific side. + * + * @param side The side to get. + * @return The output signal strength, between 0 and 15. + * @see #setAnalogOutput + */ @LuaFunction( { "getAnalogOutput", "getAnalogueOutput" } ) public final int getAnalogOutput( ComputerSide side ) { return environment.getOutput( side ); } + /** + * Get the redstone input signal strength for a specific side. + * + * @param side The side to get. + * @return The input signal strength, between 0 and 15. + */ @LuaFunction( { "getAnalogInput", "getAnalogueInput" } ) public final int getAnalogInput( ComputerSide side ) { return environment.getInput( side ); } + /** + * Set the bundled cable output for a specific side. + * + * @param side The side to set. + * @param output The colour bitmask to set. + * @cc.see colors.subtract For removing a colour from the bitmask. + * @cc.see colors.combine For adding a color to the bitmask. + */ @LuaFunction public final void setBundledOutput( ComputerSide side, int output ) { environment.setBundledOutput( side, output ); } + /** + * Get the bundled cable output for a specific side. + * + * @param side The side to get. + * @return The bundle cable's output. + */ @LuaFunction public final int getBundledOutput( ComputerSide side ) { return environment.getBundledOutput( side ); } + /** + * Get the bundled cable input for a specific side. + * + * @param side The side to get. + * @return The bundle cable's input. + * @see #testBundledInput To determine if a specific colour is set. + */ @LuaFunction public final int getBundledInput( ComputerSide side ) { return environment.getBundledOutput( side ); } + /** + * Determine if a specific combination of colours are on for the given side. + * + * @param side The side to test. + * @param mask The mask to test. + * @return If the colours are on. + * @cc.usage Check if @{colors.white} and @{colors.black} are on above the computer. + *
+     * print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
+     * 
+ * @see #getBundledInput + */ @LuaFunction public final boolean testBundledInput( ComputerSide side, int mask ) { diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 195085331..ed05df142 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -14,6 +14,11 @@ import dan200.computercraft.shared.util.Colour; import javax.annotation.Nonnull; +/** + * The Terminal API provides functions for writing text to the terminal and monitors, and drawing ASCII graphics. + * + * @cc.module term + */ public class TermAPI extends TermMethods implements ILuaAPI { private final Terminal terminal; @@ -31,11 +36,21 @@ public class TermAPI extends TermMethods implements ILuaAPI return new String[] { "term" }; } + /** + * Get the default palette value for a colour. + * + * @param colour The colour whose palette should be fetched. + * @return The RGB values. + * @throws LuaException When given an invalid colour. + * @cc.treturn number The red channel, will be between 0 and 1. + * @cc.treturn number The green channel, will be between 0 and 1. + * @cc.treturn number The blue channel, will be between 0 and 1. + */ @LuaFunction( { "nativePaletteColour", "nativePaletteColor" } ) - public final Object[] nativePaletteColour( int colourArg ) throws LuaException + public final Object[] nativePaletteColour( int colour ) throws LuaException { - int colour = 15 - parseColour( colourArg ); - Colour c = Colour.fromInt( colour ); + int actualColour = 15 - parseColour( colour ); + Colour c = Colour.fromInt( actualColour ); float[] rgb = c.getRGB(); diff --git a/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/src/main/java/dan200/computercraft/core/apis/TermMethods.java index d7674ef3f..c55c59f7a 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermMethods.java +++ b/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -18,6 +18,9 @@ import javax.annotation.Nonnull; /** * A base class for all objects which interact with a terminal. Namely the {@link TermAPI} and monitors. + * + * @cc.module term.Redirect + * @hidden */ public abstract class TermMethods { diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index a6436a785..ce8684002 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -25,6 +25,12 @@ import static dan200.computercraft.core.apis.IAPIEnvironment.TIMER_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT; import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT; +/** + * A websocket, which can be used to send an receive messages with a web server. + * + * @cc.module http.Websocket + * @see dan200.computercraft.core.apis.HTTPAPI#websocket On how to open a websocket. + */ public class WebsocketHandle implements Closeable { private final Websocket websocket; @@ -40,8 +46,18 @@ public class WebsocketHandle implements Closeable this.channel = channel; } + /** + * Wait for a message from the server. + * + * @param timeout The number of seconds to wait if no message is received. + * @return The result of receiving. + * @throws LuaException If the websocket has been closed. + * @cc.treturn [1] string The received message. + * @cc.treturn boolean If this was a binary message. + * @cc.treturn [2] nil If the websocket was closed while waiting, or if we timed out. + */ @LuaFunction - public final MethodResult result( Optional timeout ) throws LuaException + public final MethodResult receive( Optional timeout ) throws LuaException { checkOpen(); int timeoutId = timeout.isPresent() @@ -51,29 +67,40 @@ public class WebsocketHandle implements Closeable return new ReceiveCallback( timeoutId ).pull; } + /** + * Send a websocket message to the connected server. + * + * @param message The message to send. + * @param binary Whether this message should be treated as a + * @throws LuaException If the message is too large. + * @throws LuaException If the websocket has been closed. + */ @LuaFunction - public final void send( IArguments args ) throws LuaException + public final void send( Object message, Optional binary ) throws LuaException { checkOpen(); - String text = StringUtil.toString( args.get( 0 ) ); + String text = StringUtil.toString( message ); if( options.websocketMessage != 0 && text.length() > options.websocketMessage ) { throw new LuaException( "Message is too large" ); } - boolean binary = args.optBoolean( 1, false ); websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_OUTGOING, text.length() ); Channel channel = this.channel; if( channel != null ) { - channel.writeAndFlush( binary + channel.writeAndFlush( binary.orElse( false ) ? new BinaryWebSocketFrame( Unpooled.wrappedBuffer( LuaValues.encode( text ) ) ) : new TextWebSocketFrame( text ) ); } } + /** + * Close this websocket. This will terminate the connection, meaning messages can no longer be sent or received + * along it. + */ @LuaFunction( "close" ) public final void doClose() { diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java index 0456cc51a..2e80cd86c 100644 --- a/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -194,9 +194,9 @@ public final class Generator if( bytes == null ) return Optional.empty(); Class klass = DeclaringClassLoader.INSTANCE.define( className, bytes, method.getDeclaringClass().getProtectionDomain() ); - return Optional.of( klass.asSubclass( base ).newInstance() ); + return Optional.of( klass.asSubclass( base ).getDeclaredConstructor().newInstance() ); } - catch( InstantiationException | IllegalAccessException | ClassFormatError | RuntimeException e ) + catch( ReflectiveOperationException | ClassFormatError | RuntimeException e ) { ComputerCraft.log.error( "Error generating wrapper for {}.", name, e ); return Optional.empty(); diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 53e8fbc21..fd310da23 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -23,6 +23,9 @@ import net.minecraft.world.World; import java.util.*; +/** + * @cc.module commands + */ public class CommandAPI implements ILuaAPI { private final TileCommandComputer computer; @@ -78,18 +81,62 @@ public class CommandAPI implements ILuaAPI return table; } + /** + * Execute a specific command. + * + * @param command The command to execute. + * @return See {@code cc.treturn}. + * @cc.treturn boolean Whether the command executed successfully. + * @cc.treturn { string... } The output of this command, as a list of lines. + * @cc.treturn number|nil The number of "affected" objects, or `nil` if the command failed. The definition of this + * varies from command to command. + * @cc.usage Set the block above the command computer to stone. + *
+     * commands.exec("setblock ~ ~1 ~ minecraft:stone")
+     * 
+ */ @LuaFunction( mainThread = true ) public final Object[] exec( String command ) { return doCommand( command ); } + /** + * Asynchronously execute a command. + * + * Unlike {@link #exec}, this will immediately return, instead of waiting for the + * command to execute. This allows you to run multiple commands at the same + * time. + * + * When this command has finished executing, it will queue a `task_complete` + * event containing the result of executing this command (what {@link #exec} would + * return). + * + * @param context The context this command executes under. + * @param command The command to execute. + * @return The "task id". When this command has been executed, it will queue a `task_complete` event with a matching id. + * @throws LuaException (hidden) If the task cannot be created. + * @cc.tparam string command The command to execute. + * @cc.usage Asynchronously sets the block above the computer to stone. + *
+     * commands.execAsync("~ ~1 ~ minecraft:stone")
+     * 
+ * @cc.see parallel One may also use the parallel API to run multiple commands at once. + */ @LuaFunction public final long execAsync( ILuaContext context, String command ) throws LuaException { return context.issueMainThreadTask( () -> doCommand( command ) ); } + /** + * List all available commands which the computer has permission to execute. + * + * @param args Arguments to this function. + * @return A list of all available commands + * @throws LuaException (hidden) On non-string arguments. + * @cc.tparam string ... The sub-command to complete. + */ @LuaFunction( mainThread = true ) public final List list( IArguments args ) throws LuaException { @@ -112,6 +159,15 @@ public class CommandAPI implements ILuaAPI return result; } + /** + * Get the position of the current command computer. + * + * @return The block's position. + * @cc.treturn number This computer's x position. + * @cc.treturn number This computer's y position. + * @cc.treturn number This computer's z position. + * @cc.see gps.locate To get the position of a non-command computer. + */ @LuaFunction public final Object[] getBlockPosition() { @@ -120,6 +176,25 @@ public class CommandAPI implements ILuaAPI return new Object[] { pos.getX(), pos.getY(), pos.getZ() }; } + /** + * Get information about a range of blocks. + * + * This returns the same information as @{getBlockInfo}, just for multiple + * blocks at once. + * + * Blocks are traversed by ascending y level, followed by z and x - the returned + * table may be indexed using `x + z*width + y*depth*depth`. + * + * @param minX The start x coordinate of the range to query. + * @param minY The start y coordinate of the range to query. + * @param minZ The start z coordinate of the range to query. + * @param maxX The end x coordinate of the range to query. + * @param maxY The end y coordinate of the range to query. + * @param maxZ The end z coordinate of the range to query. + * @return A list of information about each block. + * @throws LuaException If the coordinates are not within the world. + * @throws LuaException If trying to get information about more than 4096 blocks. + */ @LuaFunction( mainThread = true ) public final List> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException { @@ -159,6 +234,19 @@ public class CommandAPI implements ILuaAPI return results; } + /** + * Get some basic information about a block. + * + * The returned table contains the current name, metadata and block state (as + * with @{turtle.inspect}). If there is a tile entity for that block, its NBT + * will also be returned. + * + * @param x The x position of the block to query. + * @param y The y position of the block to query. + * @param z The z position of the block to query. + * @return The given block's information. + * @throws LuaException If the coordinates are not within the world, or are not currently loaded. + */ @LuaFunction( mainThread = true ) public final Map getBlockInfo( int x, int y, int z ) throws LuaException { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java index 15c3395b9..8e527be7d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java @@ -7,9 +7,19 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.core.apis.OSAPI; import javax.annotation.Nonnull; +import javax.annotation.Nullable; +/** + * A computer or turtle wrapped as a peripheral. + * + * This allows for basic interaction with adjacent computers. Computers wrapped as peripherals will have the type + * {@code computer} while turtles will be {@code turtle}. + * + * @cc.module computer + */ public class ComputerPeripheral implements IPeripheral { private final String type; @@ -28,36 +38,63 @@ public class ComputerPeripheral implements IPeripheral return type; } + /** + * Turn the other computer on. + */ @LuaFunction public final void turnOn() { computer.turnOn(); } + /** + * Shutdown the other computer. + */ @LuaFunction public final void shutdown() { computer.shutdown(); } + /** + * Reboot or turn on the other computer. + */ @LuaFunction public final void reboot() { computer.reboot(); } + /** + * Get the other computer's ID. + * + * @return The computer's ID. + * @see OSAPI#getComputerID() To get your computer's ID. + */ @LuaFunction public final int getID() { return computer.assignID(); } + /** + * Determine if the other computer is on. + * + * @return If the computer is on. + */ @LuaFunction public final boolean isOn() { return computer.isOn(); } + /** + * Get the other computer's label. + * + * @return The computer's label. + * @see OSAPI#getComputerLabel() To get your label. + */ + @Nullable @LuaFunction public final String getLabel() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index a5d2a2041..ff0881f29 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared.peripheral.commandblock; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.shared.computer.apis.CommandAPI; import dan200.computercraft.shared.util.CapabilityUtil; import net.minecraft.tileentity.CommandBlockTileEntity; import net.minecraft.tileentity.TileEntity; @@ -25,6 +26,16 @@ import javax.annotation.Nullable; import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL; +/** + * This peripheral allows you to interact with command blocks. + * + * Command blocks are only wrapped as peripherals if the {@literal enable_command_block} option is true within the + * config. + * + * This API is not the same as the {@link CommandAPI} API, which is exposed on command computers. + * + * @cc.module command + */ @Mod.EventBusSubscriber public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider { @@ -45,12 +56,22 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider return "command"; } + /** + * Get the command this command block will run. + * + * @return The current command. + */ @LuaFunction( mainThread = true ) public final String getCommand() { return commandBlock.getCommandBlockLogic().getCommand(); } + /** + * Set the command block's command. + * + * @param command The new command. + */ @LuaFunction( mainThread = true ) public final void setCommand( String command ) { @@ -58,8 +79,15 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider commandBlock.getCommandBlockLogic().updateCommand(); } + /** + * Execute the command block once. + * + * @return The result of executing. + * @cc.treturn boolean If the command completed successfully. + * @cc.treturn string|nil A failure message. + */ @LuaFunction( mainThread = true ) - public final Object runCommand() + public final Object[] runCommand() { commandBlock.getCommandBlockLogic().trigger( commandBlock.getWorld() ); int result = commandBlock.getCommandBlockLogic().getSuccessCount(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index ee0001a38..8367e1f8b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -18,6 +18,19 @@ import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; import java.util.Optional; +/** + * Disk drives are a peripheral which allow you to read and write to floppy disks and other "mountable media" (such as + * computers or turtles). They also allow you to {@link #playAudio play records}. + * + * When a disk drive attaches some mount (such as a floppy disk or computer), it attaches a folder called {@code disk}, + * {@code disk2}, etc... to the root directory of the computer. This folder can be used to interact with the files on + * that disk. + * + * When a disk is inserted, a {@code disk} event is fired, with the side peripheral is on. Likewise, when the disk is + * detached, a {@code disk_eject} event is fired. + * + * @cc.module drive + */ public class DiskDrivePeripheral implements IPeripheral { private final TileDiskDrive diskDrive; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 32df37b98..0805406a9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -20,6 +20,11 @@ import javax.annotation.Nonnull; import java.util.HashSet; import java.util.Set; +/** + * The modem peripheral allows you to send messages between computers. + * + * @cc.module modem + */ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver { private IPacketNetwork m_network; @@ -100,30 +105,65 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return channel; } + /** + * Open a channel on a modem. A channel must be open in order to receive messages. Modems can have up to 128 + * channels open at one time. + * + * @param channel The channel to open. This must be a number between 0 and 65535. + * @throws LuaException If the channel is out of range. + * @throws LuaException If there are too many open channels. + */ @LuaFunction public final void open( int channel ) throws LuaException { m_state.open( parseChannel( channel ) ); } + /** + * Check if a channel is open. + * + * @param channel The channel to check. + * @return Whether the channel is open. + * @throws LuaException If the channel is out of range. + */ @LuaFunction public final boolean isOpen( int channel ) throws LuaException { return m_state.isOpen( parseChannel( channel ) ); } + /** + * Close an open channel, meaning it will no longer receive messages. + * + * @param channel The channel to close. + * @throws LuaException If the channel is out of range. + */ @LuaFunction public final void close( int channel ) throws LuaException { m_state.close( parseChannel( channel ) ); } + /** + * Close all open channels. + */ @LuaFunction public final void closeAll() { m_state.closeAll(); } + /** + * Sends a modem message on a certain channel. Modems listening on the channel will queue a {@code modem_message} + * event on adjacent computers. + * + *
Note: The channel does not need be open to send a message.
+ * + * @param channel The channel to send messages on. + * @param replyChannel The channel that responses to this message should be sent on. + * @param payload The object to send. This can be a string, number, or table. + * @throws LuaException If the channel is out of range. + */ @LuaFunction public final void transmit( int channel, int replyChannel, Object payload ) throws LuaException { @@ -147,6 +187,14 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa } } + /** + * Determine if this is a wired or wireless modem. + * + * Some methods (namely those dealing with wired networks and remote peripherals) are only available on wired + * modems. + * + * @return {@code true} if this is a wireless modem. + */ @LuaFunction public final boolean isWireless() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index 620f02cbd..b4472f377 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -73,18 +73,54 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW //endregion //region Peripheral methods + + /** + * List all remote peripherals on the wired network. + * + * If this computer is attached to the network, it _will not_ be included in + * this list. + * + *
Important: This function only appears on wired modems. Check {@link #isWireless} + * returns false before calling it.
+ * + * @param computer The calling computer. + * @return Remote peripheral names on the network. + */ @LuaFunction public final Collection getNamesRemote( IComputerAccess computer ) { return getWrappers( computer ).keySet(); } + /** + * Determine if a peripheral is available on this wired network. + * + *
Important: This function only appears on wired modems. Check {@link #isWireless} + * returns false before calling it.
+ * + * @param computer The calling computer. + * @param name The peripheral's name. + * @return boolean If a peripheral is present with the given name. + * @see PeripheralAPI#isPresent + */ @LuaFunction public final boolean isPresentRemote( IComputerAccess computer, String name ) { return getWrapper( computer, name ) != null; } + /** + * Get the type of a peripheral is available on this wired network. + * + *
Important: This function only appears on wired modems. Check {@link #isWireless} + * returns false before calling it.
+ * + * @param computer The calling computer. + * @param name The peripheral's name. + * @return The peripheral's name. + * @cc.treturn string|nil The peripheral's type, or {@code nil} if it is not present. + * @see PeripheralAPI#getType + */ @LuaFunction public final Object[] getTypeRemote( IComputerAccess computer, String name ) { @@ -92,6 +128,17 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW return wrapper != null ? new Object[] { wrapper.getType() } : null; } + /** + * Get all available methods for the remote peripheral with the given name. + * + *
Important: This function only appears on wired modems. Check {@link #isWireless} + * returns false before calling it.
+ * + * @param computer The calling computer. + * @param name The peripheral's name. + * @return A list of methods provided by this peripheral, or {@code nil} if it is not present. + * @see PeripheralAPI#getMethods + */ @LuaFunction public final Object[] getMethodsRemote( IComputerAccess computer, String name ) { @@ -101,6 +148,23 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW return new Object[] { wrapper.getMethodNames() }; } + /** + * Call a method on a peripheral on this wired network. + * + *
Important: This function only appears on wired modems. Check {@link #isWireless} + * returns false before calling it.
+ * + * @param computer The calling computer. + * @param context The Lua context we're executing in. + * @param arguments Arguments to this computer. + * @return The peripheral's result. + * @throws LuaException (hidden) If the method throws an error. + * @cc.tparam string remoteName The name of the peripheral to invoke the method on. + * @cc.tparam string method The name of the method + * @cc.param ... Additional arguments to pass to the method + * @cc.treturn string The return values of the peripheral method. + * @see PeripheralAPI#call + */ @LuaFunction public final MethodResult callRemote( IComputerAccess computer, ILuaContext context, IArguments arguments ) throws LuaException { @@ -112,6 +176,17 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW return wrapper.callMethod( context, methodName, arguments.drop( 2 ) ); } + /** + * Returns the network name of the current computer, if the modem is on. This + * may be used by other computers on the network to wrap this computer as a + * peripheral. + * + *
Important: This function only appears on wired modems. Check {@link #isWireless} + * returns false before calling it.
+ * + * @return The current computer's name. + * @cc.treturn string|nil The current computer's name on the wired network. + */ @LuaFunction public final Object[] getNameLocal() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java index 9551a3773..c2e8cb050 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java @@ -16,6 +16,24 @@ import dan200.computercraft.core.terminal.Terminal; import javax.annotation.Nonnull; import javax.annotation.Nullable; +/** + * Monitors are a block which act as a terminal, displaying information on one side. This allows them to be read and + * interacted with in-world without opening a GUI. + * + * Monitors act as @{term.Redirect|terminal redirects} and so expose the same methods, as well as several additional + * ones, which are documented below. + * + * Like computers, monitors come in both normal (no colour) and advanced (colour) varieties. + * + * @cc.module monitor + * @cc.usage Write "Hello, world!" to an adjacent monitor: + * + *
+ * local monitor = peripheral.find("monitor")
+ * monitor.setCursorPos(1, 1)
+ * monitor.write("Hello, world!")
+ * 
+ */ public class MonitorPeripheral extends TermMethods implements IPeripheral { private final TileMonitor monitor; @@ -32,6 +50,14 @@ public class MonitorPeripheral extends TermMethods implements IPeripheral return "monitor"; } + /** + * Set the scale of this monitor. A larger scale will result in the monitor having a lower resolution, but display + * text much larger. + * + * @param scaleArg The monitor's scale. This must be a multiple of 0.5 between 0.5 and 5. + * @throws LuaException If the scale is out of range. + * @see #getTextScale() + */ @LuaFunction public final void setTextScale( double scaleArg ) throws LuaException { @@ -40,6 +66,12 @@ public class MonitorPeripheral extends TermMethods implements IPeripheral getMonitor().setTextScale( scale ); } + /** + * Get the monitor's current text scale. + * + * @return The monitor's current scale. + * @throws LuaException If the monitor cannot be found. + */ @LuaFunction public final double getTextScale() throws LuaException { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index cada0513d..5235e127c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -15,6 +15,11 @@ import dan200.computercraft.shared.util.StringUtil; import javax.annotation.Nonnull; import java.util.Optional; +/** + * The printer peripheral allows pages and books to be printed. + * + * @cc.module printer + */ public class PrinterPeripheral implements IPeripheral { private final TilePrinter printer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 4920e7260..c1c5527e7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -25,6 +25,11 @@ import java.util.concurrent.atomic.AtomicInteger; import static dan200.computercraft.api.lua.LuaValues.checkFinite; +/** + * Speakers allow playing notes and other sounds. + * + * @cc.module speaker + */ public abstract class SpeakerPeripheral implements IPeripheral { private long m_clock = 0; diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 15f8df2c0..25734108a 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -19,6 +19,22 @@ import net.minecraft.item.ItemStack; import net.minecraft.util.NonNullList; import net.minecraftforge.items.wrapper.PlayerMainInvWrapper; +/** + * Control the current pocket computer, adding or removing upgrades. + * + * This API is only available on pocket computers. As such, you may use its presence to determine what kind of computer + * you are using: + * + *
+ * if pocket then
+ *   print("On a pocket computer")
+ * else
+ *   print("On something else")
+ * end
+ * 
+ * + * @cc.module pocket + */ public class PocketAPI implements ILuaAPI { private final PocketServerComputer computer; @@ -34,6 +50,15 @@ public class PocketAPI implements ILuaAPI return new String[] { "pocket" }; } + /** + * Search the player's inventory for another upgrade, replacing the existing one with that item if found. + * + * This inventory search starts from the player's currently selected slot, allowing you to prioritise upgrades. + * + * @return The result of equipping. + * @cc.treturn boolean If an item was equipped. + * @cc.treturn string|nil The reason an item was not equipped. + */ @LuaFunction( mainThread = true ) public final Object[] equipBack() { @@ -72,6 +97,13 @@ public class PocketAPI implements ILuaAPI return new Object[] { true }; } + /** + * Remove the pocket computer's current upgrade. + * + * @return The result of unequipping. + * @cc.treturn boolean If the upgrade was unequipped. + * @cc.treturn string|nil The reason an upgrade was not unequipped. + */ @LuaFunction( mainThread = true ) public final Object[] unequipBack() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 66753f3be..3abcef060 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -24,6 +24,11 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +/** + * The turtle API allows you to control your turtle. + * + * @cc.module turtle + */ public class TurtleAPI implements ILuaAPI { private final IAPIEnvironment environment; @@ -47,42 +52,92 @@ public class TurtleAPI implements ILuaAPI return turtle.executeCommand( command ); } + /** + * Move the turtle forward one block. + * + * @return The turtle command result. + * @cc.treturn boolean Whether the turtle could successfully move. + * @cc.treturn string|nil The reason the turtle could not move. + */ @LuaFunction public final MethodResult forward() { return trackCommand( new TurtleMoveCommand( MoveDirection.FORWARD ) ); } + /** + * Move the turtle backwards one block. + * + * @return The turtle command result. + * @cc.treturn boolean Whether the turtle could successfully move. + * @cc.treturn string|nil The reason the turtle could not move. + */ @LuaFunction public final MethodResult back() { return trackCommand( new TurtleMoveCommand( MoveDirection.BACK ) ); } + /** + * Move the turtle up one block. + * + * @return The turtle command result. + * @cc.treturn boolean Whether the turtle could successfully move. + * @cc.treturn string|nil The reason the turtle could not move. + */ @LuaFunction public final MethodResult up() { return trackCommand( new TurtleMoveCommand( MoveDirection.UP ) ); } + /** + * Move the turtle down one block. + * + * @return The turtle command result. + * @cc.treturn boolean Whether the turtle could successfully move. + * @cc.treturn string|nil The reason the turtle could not move. + */ @LuaFunction public final MethodResult down() { return trackCommand( new TurtleMoveCommand( MoveDirection.DOWN ) ); } + /** + * Rotate the turtle 90 degress to the left. + * + * @return The turtle command result. + */ @LuaFunction public final MethodResult turnLeft() { return trackCommand( new TurtleTurnCommand( TurnDirection.LEFT ) ); } + /** + * Rotate the turtle 90 degress to the right. + * + * @return The turtle command result. + */ @LuaFunction public final MethodResult turnRight() { return trackCommand( new TurtleTurnCommand( TurnDirection.RIGHT ) ); } + /** + * Attempt to break the block in front of the turtle. + * + * This requires a turtle tool capable of breaking the block. Diamond pickaxes + * (mining turtles) can break any vanilla block, but other tools (such as axes) + * are more limited. + * + * @param side The specific tool to use. Should be "left" or "right". + * @return The turtle command result. + * @cc.treturn boolean Whether a block was broken. + * @cc.treturn string|nil The reason no block was broken. + */ @LuaFunction public final MethodResult dig( Optional side ) { @@ -90,6 +145,14 @@ public class TurtleAPI implements ILuaAPI return trackCommand( TurtleToolCommand.dig( InteractDirection.FORWARD, side.orElse( null ) ) ); } + /** + * Attempt to break the block above the turtle. See {@link #dig} for full details. + * + * @param side The specific tool to use. + * @return The turtle command result. + * @cc.treturn boolean Whether a block was broken. + * @cc.treturn string|nil The reason no block was broken. + */ @LuaFunction public final MethodResult digUp( Optional side ) { @@ -97,6 +160,14 @@ public class TurtleAPI implements ILuaAPI return trackCommand( TurtleToolCommand.dig( InteractDirection.UP, side.orElse( null ) ) ); } + /** + * Attempt to break the block below the turtle. See {@link #dig} for full details. + * + * @param side The specific tool to use. + * @return The turtle command result. + * @cc.treturn boolean Whether a block was broken. + * @cc.treturn string|nil The reason no block was broken. + */ @LuaFunction public final MethodResult digDown( Optional side ) { @@ -104,42 +175,113 @@ public class TurtleAPI implements ILuaAPI return trackCommand( TurtleToolCommand.dig( InteractDirection.DOWN, side.orElse( null ) ) ); } + /** + * Place a block or item into the world in front of the turtle. + * + * @param args Arguments to place. + * @return The turtle command result. + * @cc.tparam [opt] string text When placing a sign, set its contents to this text. + * @cc.treturn boolean Whether the block could be placed. + * @cc.treturn string|nil The reason the block was not placed. + */ @LuaFunction public final MethodResult place( IArguments args ) { return trackCommand( new TurtlePlaceCommand( InteractDirection.FORWARD, args.getAll() ) ); } + /** + * Place a block or item into the world above the turtle. + * + * @param args Arguments to place. + * @return The turtle command result. + * @cc.tparam [opt] string text When placing a sign, set its contents to this text. + * @cc.treturn boolean Whether the block could be placed. + * @cc.treturn string|nil The reason the block was not placed. + */ @LuaFunction public final MethodResult placeUp( IArguments args ) { return trackCommand( new TurtlePlaceCommand( InteractDirection.UP, args.getAll() ) ); } + /** + * Place a block or item into the world below the turtle. + * + * @param args Arguments to place. + * @return The turtle command result. + * @cc.tparam [opt] string text When placing a sign, set its contents to this text. + * @cc.treturn boolean Whether the block could be placed. + * @cc.treturn string|nil The reason the block was not placed. + */ @LuaFunction public final MethodResult placeDown( IArguments args ) { return trackCommand( new TurtlePlaceCommand( InteractDirection.DOWN, args.getAll() ) ); } + /** + * Drop the currently selected stack into the inventory in front of the turtle, or as an item into the world if + * there is no inventory. + * + * @param count The number of items to drop. If not given, the entire stack will be dropped. + * @return The turtle command result. + * @throws LuaException If dropping an invalid number of items. + * @cc.treturn boolean Whether items were dropped. + * @cc.treturn string|nil The reason the no items were dropped. + * @see #select + */ @LuaFunction public final MethodResult drop( Optional count ) throws LuaException { return trackCommand( new TurtleDropCommand( InteractDirection.FORWARD, checkCount( count ) ) ); } + /** + * Drop the currently selected stack into the inventory above the turtle, or as an item into the world if there is + * no inventory. + * + * @param count The number of items to drop. If not given, the entire stack will be dropped. + * @return The turtle command result. + * @throws LuaException If dropping an invalid number of items. + * @cc.treturn boolean Whether items were dropped. + * @cc.treturn string|nil The reason the no items were dropped. + * @see #select + */ @LuaFunction public final MethodResult dropUp( Optional count ) throws LuaException { return trackCommand( new TurtleDropCommand( InteractDirection.UP, checkCount( count ) ) ); } + /** + * Drop the currently selected stack into the inventory in front of the turtle, or as an item into the world if + * there is no inventory. + * + * @param count The number of items to drop. If not given, the entire stack will be dropped. + * @return The turtle command result. + * @throws LuaException If dropping an invalid number of items. + * @cc.treturn boolean Whether items were dropped. + * @cc.treturn string|nil The reason the no items were dropped. + * @see #select + */ @LuaFunction public final MethodResult dropDown( Optional count ) throws LuaException { return trackCommand( new TurtleDropCommand( InteractDirection.DOWN, checkCount( count ) ) ); } + /** + * Change the currently selected slot. + * + * The selected slot is determines what slot actions like {@link #drop} or {@link #getItemCount} act on. + * + * @param slot The slot to select. + * @return The turtle command result. + * @throws LuaException If the slot is out of range. + * @see #getSelectedSlot + */ + @LuaFunction public final MethodResult select( int slot ) throws LuaException { @@ -150,6 +292,13 @@ public class TurtleAPI implements ILuaAPI } ); } + /** + * Get the number of items in the given slot. + * + * @param slot The slot we wish to check. Defaults to the {@link #select selected slot}. + * @return The number of items in this slot. + * @throws LuaException If the slot is out of range. + */ @LuaFunction public final int getItemCount( Optional slot ) throws LuaException { @@ -157,6 +306,15 @@ public class TurtleAPI implements ILuaAPI return turtle.getInventory().getStackInSlot( actualSlot ).getCount(); } + /** + * Get the remaining number of items which may be stored in this stack. + * + * For instance, if a slot contains 13 blocks of dirt, it has room for another 51. + * + * @param slot The slot we wish to check. Defaults to the {@link #select selected slot}. + * @return The space left in in this slot. + * @throws LuaException If the slot is out of range. + */ @LuaFunction public final int getItemSpace( Optional slot ) throws LuaException { @@ -165,18 +323,37 @@ public class TurtleAPI implements ILuaAPI return stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount(); } + /** + * Check if there is a solid block in front of the turtle. In this case, solid refers to any non-air or liquid + * block. + * + * @return The turtle command result. + * @cc.treturn boolean If there is a solid block in front. + */ @LuaFunction public final MethodResult detect() { return trackCommand( new TurtleDetectCommand( InteractDirection.FORWARD ) ); } + /** + * Check if there is a solid block above the turtle. In this case, solid refers to any non-air or liquid block. + * + * @return The turtle command result. + * @cc.treturn boolean If there is a solid block in front. + */ @LuaFunction public final MethodResult detectUp() { return trackCommand( new TurtleDetectCommand( InteractDirection.UP ) ); } + /** + * Check if there is a solid block below the turtle. In this case, solid refers to any non-air or liquid block. + * + * @return The turtle command result. + * @cc.treturn boolean If there is a solid block in front. + */ @LuaFunction public final MethodResult detectDown() { @@ -201,36 +378,89 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleCompareCommand( InteractDirection.DOWN ) ); } + /** + * Attack the entity in front of the turtle. + * + * @param side The specific tool to use. + * @return The turtle command result. + * @cc.treturn boolean Whether an entity was attacked. + * @cc.treturn string|nil The reason nothing was attacked. + */ @LuaFunction public final MethodResult attack( Optional side ) { return trackCommand( TurtleToolCommand.attack( InteractDirection.FORWARD, side.orElse( null ) ) ); } + /** + * Attack the entity above the turtle. + * + * @param side The specific tool to use. + * @return The turtle command result. + * @cc.treturn boolean Whether an entity was attacked. + * @cc.treturn string|nil The reason nothing was attacked. + */ @LuaFunction public final MethodResult attackUp( Optional side ) { return trackCommand( TurtleToolCommand.attack( InteractDirection.UP, side.orElse( null ) ) ); } + /** + * Attack the entity below the turtle. + * + * @param side The specific tool to use. + * @return The turtle command result. + * @cc.treturn boolean Whether an entity was attacked. + * @cc.treturn string|nil The reason nothing was attacked. + */ @LuaFunction public final MethodResult attackDown( Optional side ) { return trackCommand( TurtleToolCommand.attack( InteractDirection.DOWN, side.orElse( null ) ) ); } + /** + * Suck an item from the inventory in front of the turtle, or from an item floating in the world. + * + * This will pull items into the first acceptable slot, starting at the {@link #select currently selected} one. + * + * @param count The number of items to suck. If not given, up to a stack of items will be picked up. + * @return The turtle command result. + * @throws LuaException If given an invalid number of items. + * @cc.treturn boolean Whether items were picked up. + * @cc.treturn string|nil The reason the no items were picked up. + */ @LuaFunction public final MethodResult suck( Optional count ) throws LuaException { return trackCommand( new TurtleSuckCommand( InteractDirection.FORWARD, checkCount( count ) ) ); } + /** + * Suck an item from the inventory above the turtle, or from an item floating in the world. + * + * @param count The number of items to suck. If not given, up to a stack of items will be picked up. + * @return The turtle command result. + * @throws LuaException If given an invalid number of items. + * @cc.treturn boolean Whether items were picked up. + * @cc.treturn string|nil The reason the no items were picked up. + */ @LuaFunction public final MethodResult suckUp( Optional count ) throws LuaException { return trackCommand( new TurtleSuckCommand( InteractDirection.UP, checkCount( count ) ) ); } + /** + * Suck an item from the inventory below the turtle, or from an item floating in the world. + * + * @param count The number of items to suck. If not given, up to a stack of items will be picked up. + * @return The turtle command result. + * @throws LuaException If given an invalid number of items. + * @cc.treturn boolean Whether items were picked up. + * @cc.treturn string|nil The reason the no items were picked up. + */ @LuaFunction public final MethodResult suckDown( Optional count ) throws LuaException { @@ -265,6 +495,12 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleTransferToCommand( slot, count ) ); } + /** + * Get the currently sleected slot. + * + * @return The current slot. + * @see #select + */ @LuaFunction public final int getSelectedSlot() { @@ -307,15 +543,33 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleInspectCommand( InteractDirection.DOWN ) ); } + /** + * Get detailed information about the items in the given slot. + * + * @param context The Lua context + * @param slot The slot to get information about. Defaults to the {@link #select selected slot}. + * @param detailed Whether to include "detailed" information. When {@code true} the method will contain much + * more information about the item at the cost of taking longer to run. + * @return The command result. + * @throws LuaException If the slot is out of range. + * @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty. + * @cc.usage Print the current slot, assuming it contains 13 dirt. + * + *
{@code
+     * print(textutils.serialize(turtle.getItemDetail()))
+     * -- => {
+     * --  name = "minecraft:dirt",
+     * --  count = 13,
+     * -- }
+     * }
+ */ @LuaFunction - public final MethodResult getItemDetail( ILuaContext context, Optional slotArg, Optional detailedArg ) throws LuaException + public final MethodResult getItemDetail( ILuaContext context, Optional slot, Optional detailed ) throws LuaException { - int slot = checkSlot( slotArg ).orElse( turtle.getSelectedSlot() ); - boolean detailed = detailedArg.orElse( false ); - - return detailed - ? TaskCallback.make( context, () -> getItemDetail( slot, true ) ) - : MethodResult.of( getItemDetail( slot, false ) ); + int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() ); + return detailed.orElse( false ) + ? TaskCallback.make( context, () -> getItemDetail( actualSlot, true ) ) + : MethodResult.of( getItemDetail( actualSlot, false ) ); } private Object[] getItemDetail( int slot, boolean detailed ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index 530937992..8aa220a35 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -15,6 +15,13 @@ import dan200.computercraft.shared.turtle.core.TurtleCraftCommand; import javax.annotation.Nonnull; import java.util.Optional; +/** + * The workbench peripheral allows you to craft items within the turtle's inventory. + * + * @cc.module workbench + * @hidden + * @cc.see turtle.craft This uses the {@link CraftingTablePeripheral} peripheral to craft items. + */ public class CraftingTablePeripheral implements IPeripheral { private final ITurtleAccess turtle; From d2a52a8b5d0d5d70144a1e6282b774bbc40c9fc0 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 3 Jul 2020 21:37:14 +0100 Subject: [PATCH 272/711] Fix turtle.craft failing when missing an argument. Stupid typo, stupid squid. --- .../shared/turtle/upgrades/CraftingTablePeripheral.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index 8aa220a35..ebec3f562 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -41,7 +41,7 @@ public class CraftingTablePeripheral implements IPeripheral @LuaFunction public final MethodResult craft( Optional count ) throws LuaException { - int limit = count.orElse( 65 ); + int limit = count.orElse( 64 ); if( limit < 0 || limit > 64 ) throw new LuaException( "Crafting count " + limit + " out of range" ); return turtle.executeCommand( new TurtleCraftCommand( limit ) ); } From 6020adef6b0df5e0e03cc84a15c7a1e96bf7bd10 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 4 Jul 2020 10:17:40 +0100 Subject: [PATCH 273/711] Link to Weblate in CONTRIBUTING Let's make it at least a little bit discoverable! --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2475ac724..b9146d2e3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,8 +29,13 @@ are run whenever you submit a PR, it's often useful to run this before committin - **[illuaminate]:** Checks Lua code for semantic and styleistic issues. See [the usage section][illuaminate-usage] for how to download and run it. +## Translations +Translations are managed through [Weblate], an online interface for managing language strings. This is synced +automatically with GitHub, so please don't submit PRs adding/changing translations! + [new-issue]: https://github.com/SquidDev-CC/CC-Tweaked/issues/new/choose "Create a new issue" [community]: README.md#Community "Get in touch with the community." [checkstyle]: https://checkstyle.org/ [illuaminate]: https://github.com/SquidDev/illuaminate/ [illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage +[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ From d5f1a2c817cbbe3b42d87f66a1ad518d516bf649 Mon Sep 17 00:00:00 2001 From: neumond Date: Sat, 4 Jul 2020 20:00:09 +0300 Subject: [PATCH 274/711] Add port to Host http header if necessary --- .../core/apis/http/request/HttpRequestHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index fac72ecfa..fbd102be6 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -86,7 +86,7 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler Date: Sat, 4 Jul 2020 20:41:15 +0000 Subject: [PATCH 275/711] Added translation for Russian Co-authored-by: neumond --- src/main/resources/assets/computercraft/lang/ru.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/main/resources/assets/computercraft/lang/ru.json diff --git a/src/main/resources/assets/computercraft/lang/ru.json b/src/main/resources/assets/computercraft/lang/ru.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/ru.json @@ -0,0 +1 @@ +{} From 45297665c6193f92ed92269e57a6127200a29454 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sun, 5 Jul 2020 03:41:59 +0000 Subject: [PATCH 276/711] Translations for Russian Translations for French Co-authored-by: neumond Co-authored-by: Naheulf --- .../assets/computercraft/lang/fr_fr.json | 22 ++-- .../assets/computercraft/lang/ru.json | 114 +++++++++++++++++- 2 files changed, 124 insertions(+), 12 deletions(-) diff --git a/src/main/resources/assets/computercraft/lang/fr_fr.json b/src/main/resources/assets/computercraft/lang/fr_fr.json index fdc7e4cb4..b97fa5b4c 100644 --- a/src/main/resources/assets/computercraft/lang/fr_fr.json +++ b/src/main/resources/assets/computercraft/lang/fr_fr.json @@ -2,26 +2,26 @@ "block.computercraft.computer_normal": "Ordinateur", "block.computercraft.computer_advanced": "Ordinateur avancé", "block.computercraft.computer_command": "Ordinateur de commande", - "block.computercraft.disk_drive": "Lecteur disque", + "block.computercraft.disk_drive": "Lecteur de disque", "block.computercraft.printer": "Imprimante", "block.computercraft.speaker": "Haut-parleur", "block.computercraft.monitor_normal": "Moniteur", "block.computercraft.monitor_advanced": "Moniteur avancé", "block.computercraft.wireless_modem_normal": "Modem sans fil", - "block.computercraft.wireless_modem_advanced": "Modem de l'Ender", + "block.computercraft.wireless_modem_advanced": "Modem de l'End", "block.computercraft.wired_modem": "Modem filaire", "block.computercraft.cable": "Câble réseau", "block.computercraft.wired_modem_full": "Modem filaire", "block.computercraft.turtle_normal": "Tortue", "block.computercraft.turtle_normal.upgraded": "Tortue %s", - "block.computercraft.turtle_normal.upgraded_twice": "Tortue %s %s", + "block.computercraft.turtle_normal.upgraded_twice": "Tortue %s et %s", "block.computercraft.turtle_advanced": "Tortue avancée", "block.computercraft.turtle_advanced.upgraded": "Tortue %s avancée", "block.computercraft.turtle_advanced.upgraded_twice": "Tortue %s %s avancée", "item.computercraft.disk": "Disquette", "item.computercraft.treasure_disk": "Disquette", - "item.computercraft.printed_page": "Imprimé", - "item.computercraft.printed_pages": "Imprimés", + "item.computercraft.printed_page": "Page imprimée", + "item.computercraft.printed_pages": "Pages imprimées", "item.computercraft.printed_book": "Livre imprimé", "item.computercraft.pocket_computer_normal": "Ordinateur de poche", "item.computercraft.pocket_computer_normal.upgraded": "Ordinateur de poche %s", @@ -34,15 +34,15 @@ "upgrade.minecraft.diamond_hoe.adjective": "agricole", "upgrade.minecraft.crafting_table.adjective": "ouvrière", "upgrade.computercraft.wireless_modem_normal.adjective": "sans fil", - "upgrade.computercraft.wireless_modem_advanced.adjective": "de l'Ender", - "upgrade.computercraft.speaker.adjective": "parlante", - "chat.computercraft.wired_modem.peripheral_connected": "Le periphérique \"%s\" est connecté au réseau", - "chat.computercraft.wired_modem.peripheral_disconnected": "Le periphérique \"%s\" est déconnecté du réseau", + "upgrade.computercraft.wireless_modem_advanced.adjective": "de l'End", + "upgrade.computercraft.speaker.adjective": "Bruyante", + "chat.computercraft.wired_modem.peripheral_connected": "Le périphérique \"%s\" est connecté au réseau", + "chat.computercraft.wired_modem.peripheral_disconnected": "Le périphérique \"%s\" est déconnecté du réseau", "commands.computercraft.help.desc": "Affiche ce message d'aide", "itemGroup.computercraft": "ComputerCraft", "commands.computercraft.help.no_children": "%s n'a pas de sous-commandes", "commands.computercraft.dump.synopsis": "Affiche le statut des ordinateurs.", - "commands.computercraft.dump.action": "Visualiser plus d'informations à propos de cet ordinateur", + "commands.computercraft.dump.action": "Voir plus d'informations à propos de cet ordinateur", "commands.computercraft.shutdown.synopsis": "Éteindre des ordinateurs à distance.", "commands.computercraft.shutdown.desc": "Éteint les ordinateurs dans la liste ou tous, si aucun n'est spécifié dans cette liste. Vous pouvez spécifier l'identifiant d'instance (ex. 123), l'identifiant d'ordinateur (ex. #123) ou son nom (ex. \"@Mon Ordinateur\").", "commands.computercraft.turn_on.synopsis": "Démarre des ordinateurs à distance.", @@ -108,6 +108,6 @@ "commands.computercraft.queue.desc": "Envoie un événement computer_command à un ordinateur de commande, en passant les éventuels arguments additionnels. Ceci est principalement conçu pour les map makers, imitant la commande /trigger, pour une utilisation avec les ordinateurs. N'importe quel joueur peut exécuter cette commande, qui sera exécutée le plus souvent avec un événement de clic sur du texte.", "commands.computercraft.help.synopsis": "Fournit de l'aide pour une commande spécifique", "tracking_field.computercraft.http_download.name": "Téléchargement HTTP", - "commands.computercraft.synopsis": "Diverses commandes pour contrôler les ordinateurs.", + "commands.computercraft.synopsis": "Commandes diverses pour contrôler les ordinateurs.", "commands.computercraft.shutdown.done": "%s/%s ordinateurs arrêté" } diff --git a/src/main/resources/assets/computercraft/lang/ru.json b/src/main/resources/assets/computercraft/lang/ru.json index 0967ef424..210b77091 100644 --- a/src/main/resources/assets/computercraft/lang/ru.json +++ b/src/main/resources/assets/computercraft/lang/ru.json @@ -1 +1,113 @@ -{} +{ + "block.computercraft.computer_normal": "Компьютер", + "block.computercraft.computer_advanced": "Улучшенный компьютер", + "block.computercraft.computer_command": "Командный компьютер", + "block.computercraft.disk_drive": "ДиÑковод", + "block.computercraft.printer": "Принтер", + "block.computercraft.speaker": "Колонка", + "block.computercraft.monitor_normal": "Монитор", + "block.computercraft.monitor_advanced": "Улучшенный монитор", + "block.computercraft.wireless_modem_normal": "БеÑпроводной модем", + "block.computercraft.wireless_modem_advanced": "Эндер модем", + "block.computercraft.wired_modem": "Проводной модем", + "block.computercraft.cable": "Сетевой кабель", + "block.computercraft.turtle_normal.upgraded": "%s черепашка", + "block.computercraft.turtle_advanced": "Ð£Ð»ÑƒÑ‡ÑˆÐµÐ½Ð½Ð°Ñ Ñ‡ÐµÑ€ÐµÐ¿Ð°ÑˆÐºÐ°", + "block.computercraft.turtle_advanced.upgraded": "Ð£Ð»ÑƒÑ‡ÑˆÐµÐ½Ð½Ð°Ñ %s черепашка", + "block.computercraft.turtle_advanced.upgraded_twice": "Ð£Ð»ÑƒÑ‡ÑˆÐµÐ½Ð½Ð°Ñ %s %s черепашка", + "item.computercraft.treasure_disk": "ДиÑкета", + "item.computercraft.printed_page": "ÐÐ°Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ð½Ð½Ð°Ñ Ñтраница", + "item.computercraft.printed_book": "ÐÐ°Ð¿ÐµÑ‡Ð°Ñ‚Ð°Ð½Ð½Ð°Ñ ÐºÐ½Ð¸Ð³Ð°", + "item.computercraft.pocket_computer_normal": "Карманный компьютер", + "item.computercraft.pocket_computer_normal.upgraded": "%s карманный компьютер", + "item.computercraft.pocket_computer_advanced.upgraded": "Улучшенный %s карманный компьютер", + "upgrade.minecraft.diamond_sword.adjective": "БоеваÑ", + "upgrade.minecraft.diamond_shovel.adjective": "КопающаÑ", + "upgrade.minecraft.diamond_pickaxe.adjective": "ДобывающаÑ", + "upgrade.minecraft.diamond_axe.adjective": "РубÑщаÑ", + "upgrade.minecraft.diamond_hoe.adjective": "ВозделывающаÑ", + "upgrade.minecraft.crafting_table.adjective": "КрафтÑщаÑ", + "upgrade.computercraft.wireless_modem_advanced.adjective": "Эндер", + "upgrade.computercraft.speaker.adjective": "ШумÑщий", + "chat.computercraft.wired_modem.peripheral_connected": "УÑтройÑтво \"%s\" подключено к Ñети", + "commands.computercraft.synopsis": "Команды Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°Ð¼Ð¸.", + "commands.computercraft.help.synopsis": "Получить подÑказку по одной из команд", + "commands.computercraft.help.desc": "Показывает Ñтот текÑÑ‚", + "commands.computercraft.help.no_children": "%s не имеет подкоманд", + "commands.computercraft.help.no_command": "Ðет команды '%s'", + "commands.computercraft.dump.synopsis": "Показать ÑÑ‚Ð°Ñ‚ÑƒÑ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð¾Ð².", + "commands.computercraft.dump.action": "Показать больше информации об Ñтом компьютере", + "commands.computercraft.shutdown.synopsis": "Удалённо выключить компьютер.", + "commands.computercraft.shutdown.done": "%s/%s компьютеров выключено", + "commands.computercraft.turn_on.synopsis": "Удалённо включить компьютеры.", + "commands.computercraft.turn_on.done": "%s/%s компьютеров включено", + "commands.computercraft.tp.synopsis": "ТелепортироватьÑÑ Ðº компьютеру.", + "commands.computercraft.tp.desc": "ТелепортироватьÑÑ Ðº меÑту уÑтановки компьютера. Можно указать номер инÑтанÑа (например 123) или идентификатор компьютера (#123).", + "commands.computercraft.tp.action": "ТелепортироватьÑÑ Ðº Ñтому компьютеру", + "commands.computercraft.tp.not_there": "Ðевозможно найти компьютер в мире", + "commands.computercraft.view.synopsis": "Показать терминал компьютера.", + "commands.computercraft.view.not_player": "ÐÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ терминал Ð´Ð»Ñ Ð½Ðµ-игрока", + "commands.computercraft.view.action": "Открыть Ñтот компьютер", + "commands.computercraft.track.synopsis": "ОтÑлеживание метрик компьютеров.", + "commands.computercraft.track.start.synopsis": "Ðачать Ñобирать метрики Ñо вÑех компьютеров", + "commands.computercraft.track.start.desc": "Ðачать Ñобирать метрики Ñо вÑех компьютеров: Ñколько времени выполнÑетÑÑ ÐºÐ¾Ð´ и Ñколько Ñобытий обрабатываетÑÑ. Это Ñотрёт результаты предыдущего Ñбора.", + "commands.computercraft.track.start.stop": "ЗапуÑтите %s чтобы оÑтановить Ñбор метрик и поÑмотреть результаты", + "commands.computercraft.track.stop.action": "ОÑтановить Ñбор метрик", + "commands.computercraft.track.stop.not_enabled": "Сбор метрик не был запущен", + "commands.computercraft.track.dump.synopsis": "ВывеÑти результаты Ñбора метрик", + "commands.computercraft.track.dump.desc": "ВывеÑти результаты поÑледнего Ñбора метрик.", + "commands.computercraft.track.dump.no_timings": "Ðет доÑтупных результатов Ñбора метрик", + "commands.computercraft.track.dump.computer": "Компьютер", + "commands.computercraft.reload.synopsis": "Перезагрузить конфигурацию ComputerCraft", + "commands.computercraft.reload.done": "ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ¶ÐµÐ½Ð°", + "commands.computercraft.queue.desc": "Отправить Ñобытие computer_command командному компьютеру. Это нужно Ð´Ð»Ñ Ñоздателей карт, более дружеÑÑ‚Ð²ÐµÐ½Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ /trigger. Любой игрок Ñможет запуÑтить команду, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñкорее вÑего будет выполнена Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ click event текÑтового компонента.", + "commands.computercraft.generic.no_position": "<нет позиции>", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.yes": "Д", + "commands.computercraft.generic.no": "Ð", + "commands.computercraft.generic.exception": "Ðеобработанное иÑключение (%s)", + "commands.computercraft.generic.additional_rows": "%d дополнительных Ñтрок…", + "argument.computercraft.computer.no_matching": "Ðет компьютеров Ñовпадающих Ñ '%s'", + "argument.computercraft.tracking_field.no_field": "ÐеизвеÑтное поле '%s'", + "argument.computercraft.argument_expected": "ОжидаетÑÑ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚", + "tracking_field.computercraft.tasks.name": "Задачи", + "tracking_field.computercraft.total.name": "Общее времÑ", + "tracking_field.computercraft.average.name": "Среднее времÑ", + "tracking_field.computercraft.max.name": "МакÑимальное времÑ", + "tracking_field.computercraft.server_count.name": "ЧиÑло Ñерверных задач", + "tracking_field.computercraft.server_time.name": "Ð’Ñ€ÐµÐ¼Ñ Ñерверных задач", + "tracking_field.computercraft.fs.name": "Операций Ñ Ñ„Ð°Ð¹Ð»Ð°Ð¼Ð¸", + "tracking_field.computercraft.turtle.name": "ДейÑтвий черепашек", + "tracking_field.computercraft.http.name": "HTTP запроÑÑ‹", + "tracking_field.computercraft.http_upload.name": "HTTP загрузки", + "tracking_field.computercraft.http_download.name": "HTTP ÑкачиваниÑ", + "tracking_field.computercraft.websocket_outgoing.name": "ИÑходÑщие вебÑокеты", + "tracking_field.computercraft.coroutines_created.name": "Корутин Ñоздано", + "tracking_field.computercraft.coroutines_dead.name": "Корутин удалено", + "gui.computercraft.tooltip.copy": "Скопировать в буфер обмена", + "gui.computercraft.tooltip.disk_id": "ID диÑкеты: %s", + "itemGroup.computercraft": "ComputerCraft", + "block.computercraft.wired_modem_full": "Проводной модем", + "block.computercraft.turtle_normal": "Черепашка", + "block.computercraft.turtle_normal.upgraded_twice": "%s %s черепашка", + "item.computercraft.disk": "ДиÑкета", + "item.computercraft.printed_pages": "Ðапечатанные Ñтраницы", + "item.computercraft.pocket_computer_advanced": "Улучшенный карманный компьютер", + "upgrade.computercraft.wireless_modem_normal.adjective": "БеÑпроводный", + "chat.computercraft.wired_modem.peripheral_disconnected": "УÑтройÑтво \"%s\" отключено от Ñети", + "commands.computercraft.desc": "Команда /computercraft предоÑтавлÑет отладочные и админиÑтративные утилиты Ð´Ð»Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð¿ÑŒÑŽÑ‚ÐµÑ€Ð°Ð¼Ð¸.", + "commands.computercraft.dump.desc": "Показать ÑÑ‚Ð°Ñ‚ÑƒÑ Ð²Ñех компьютеров или информацию об одном из компьютеров. Можно указать номер инÑтанÑа (например 123), идентификатор компьютера (#123) или метку (\"@My Computer\").", + "commands.computercraft.shutdown.desc": "Выключить указанные компьютеры или вÑе. Можно указать номер инÑтанÑа (например 123), идентификатор компьютера (#123) или метку (\"@My Computer\").", + "commands.computercraft.turn_on.desc": "Включить указанные компьютеры. Можно указать номер инÑтанÑа (например 123), идентификатор компьютера (#123) или метку (\"@My Computer\").", + "commands.computercraft.tp.not_player": "ÐÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚ÑŒ терминал Ð´Ð»Ñ Ð½Ðµ-игрока", + "commands.computercraft.view.desc": "Открыть терминал и получить контроль над компьютером. Это не показывает инвентарь черепашек. Можно указать номер инÑтанÑа (например 123) или идентификатор компьютера (#123).", + "commands.computercraft.track.desc": "ОтÑлеживание как долго компьютеры выполнÑÑŽÑ‚ код, как много Ñобытий они обрабатывают. Это показывает информацию аналогично /forge track и может быть полезно в поиÑке причин лагов.", + "commands.computercraft.track.stop.synopsis": "ОÑтановить Ñбор метрик Ñо вÑех компьютеров", + "commands.computercraft.track.stop.desc": "ОÑтановить Ñбор метрик Ñо вÑех компьютеров: Ñколько времени выполнÑетÑÑ ÐºÐ¾Ð´ и Ñколько Ñобытий обрабатываетÑÑ", + "commands.computercraft.reload.desc": "Перезагрузить конфигурацию ComputerCraft", + "commands.computercraft.queue.synopsis": "Отправить Ñобытие computer_command командному компьютеру", + "argument.computercraft.computer.many_matching": "ÐеÑколько компьютеров Ñовпадают Ñ '%s' (инÑтанÑÑ‹ %s)", + "tracking_field.computercraft.peripheral.name": "Вызовы периферийных уÑтройÑтв", + "tracking_field.computercraft.websocket_incoming.name": "ВходÑщие вебÑокеты", + "gui.computercraft.tooltip.computer_id": "ID компьютера: %s" +} From 3075f89797c971e7a57214437ce82ddd0f9c8add Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Sun, 5 Jul 2020 03:26:37 -0400 Subject: [PATCH 277/711] Added Javadoc for currently undocumented functions (#490) This PR adds some documentation for APIs that did not have docs in the source yet. This includes the: * drive peripheral * FS API * OS PAI * printer peripheral * speaker peripheral --- .../dan200/computercraft/core/apis/FSAPI.java | 132 ++++++++++++++++++ .../dan200/computercraft/core/apis/OSAPI.java | 131 +++++++++++++++++ .../diskdrive/DiskDrivePeripheral.java | 64 +++++++++ .../peripheral/printer/PrinterPeripheral.java | 57 ++++++++ .../peripheral/speaker/SpeakerPeripheral.java | 31 ++++ 5 files changed, 415 insertions(+) diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 288f93636..fc909c683 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -61,6 +61,13 @@ public class FSAPI implements ILuaAPI fileSystem = null; } + /** + * Returns a list of files in a directory. + * + * @param path The path to list. + * @return A table with a list of files in the directory. + * @throws LuaException If the path doesn't exist. + */ @LuaFunction public final String[] list( String path ) throws LuaException { @@ -75,24 +82,51 @@ public class FSAPI implements ILuaAPI } } + /** + * Combines two parts of a path into one full path, adding separators as + * needed. + * + * @param pathA The first part of the path. For example, a parent directory path. + * @param pathB The second part of the path. For example, a file name. + * @return The new path, with separators added between parts as needed. + */ @LuaFunction public final String combine( String pathA, String pathB ) { return fileSystem.combine( pathA, pathB ); } + /** + * Returns the file name portion of a path. + * + * @param path The path to get the name from. + * @return The final part of the path (the file name). + */ @LuaFunction public final String getName( String path ) { return FileSystem.getName( path ); } + /** + * Returns the parent directory portion of a path. + * + * @param path The path to get the directory from. + * @return The path with the final part removed (the parent directory). + */ @LuaFunction public final String getDir( String path ) { return FileSystem.getDirectory( path ); } + /** + * Returns the size of the specified file. + * + * @param path The file to get the file size of. + * @return The size of the file, in bytes. + * @throws LuaException If the path doesn't exist. + */ @LuaFunction public final long getSize( String path ) throws LuaException { @@ -106,6 +140,12 @@ public class FSAPI implements ILuaAPI } } + /** + * Returns whether the specified path exists. + * + * @param path The path to check the existence of. + * @return Whether the path exists. + */ @LuaFunction public final boolean exists( String path ) { @@ -119,6 +159,12 @@ public class FSAPI implements ILuaAPI } } + /** + * Returns whether the specified path is a directory. + * + * @param path The path to check. + * @return Whether the path is a directory. + */ @LuaFunction public final boolean isDir( String path ) { @@ -132,6 +178,12 @@ public class FSAPI implements ILuaAPI } } + /** + * Returns whether a path is read-only. + * + * @param path The path to check. + * @return Whether the path cannot be written to. + */ @LuaFunction public final boolean isReadOnly( String path ) { @@ -145,6 +197,12 @@ public class FSAPI implements ILuaAPI } } + /** + * Creates a directory, and any missing parents, at the specified path. + * + * @param path The path to the directory to create. + * @throws LuaException If the directory couldn't be created. + */ @LuaFunction public final void makeDir( String path ) throws LuaException { @@ -159,6 +217,15 @@ public class FSAPI implements ILuaAPI } } + /** + * Moves a file or directory from one path to another. + * + * Any parent directories are created as needed. + * + * @param path The current file or directory to move from. + * @param dest The destination path for the file or directory. + * @throws LuaException If the file or directory couldn't be moved. + */ @LuaFunction public final void move( String path, String dest ) throws LuaException { @@ -173,6 +240,15 @@ public class FSAPI implements ILuaAPI } } + /** + * Copies a file or directory to a new path. + * + * Any parent directories are created as needed. + * + * @param path The file or directory to copy. + * @param dest The path to the destination file or directory. + * @throws LuaException If the file or directory couldn't be copied. + */ @LuaFunction public final void copy( String path, String dest ) throws LuaException { @@ -187,6 +263,15 @@ public class FSAPI implements ILuaAPI } } + /** + * Deletes a file or directory. + * + * If the path points to a directory, all of the enclosed files and + * subdirectories are also deleted. + * + * @param path The path to the file or directory to delete. + * @throws LuaException If the file or directory couldn't be deleted. + */ @LuaFunction public final void delete( String path ) throws LuaException { @@ -201,6 +286,24 @@ public class FSAPI implements ILuaAPI } } + // FIXME: Add individual handle type documentation + + /** + * Opens a file for reading or writing at a path. + * + * The mode parameter can be {@code r} to read, {@code w} to write (deleting + * all contents), or {@code a} to append (keeping contents). If {@code b} is + * added to the end, the file will be opened in binary mode; otherwise, it's + * opened in text mode. + * + * @param path The path to the file to open. + * @param mode The mode to open the file with. + * @return A file handle object for the file, or {@code nil} + an error message on error. + * @throws LuaException If an invalid mode was specified. + * @cc.treturn [1] table A file handle object for the file. + * @cc.treturn [2] nil If the file does not exist, or cannot be opened. + * @cc.treturn string|nil A message explaining why the file cannot be opened. + */ @LuaFunction public final Object[] open( String path, String mode ) throws LuaException { @@ -255,6 +358,14 @@ public class FSAPI implements ILuaAPI } } + /** + * Returns the name of the mount that the specified path is located on. + * + * @param path The path to get the drive of. + * @return The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files. + * @throws LuaException If the path doesn't exist. + * @cc.treturn string The name of the drive that the file is on; e.g. {@code hdd} for local files, or {@code rom} for ROM files. + */ @LuaFunction public final Object[] getDrive( String path ) throws LuaException { @@ -268,6 +379,15 @@ public class FSAPI implements ILuaAPI } } + /** + * Returns the amount of free space available on the drive the path is + * located on. + * + * @param path The path to check the free space for. + * @return The amount of free space available, in bytes. + * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". + * @throws LuaException If the path doesn't exist. + */ @LuaFunction public final Object getFreeSpace( String path ) throws LuaException { @@ -282,6 +402,18 @@ public class FSAPI implements ILuaAPI } } + /** + * Searches for files matching a string with wildcards. + * + * This string is formatted like a normal path string, but can include any + * number of wildcards ({@code *}) to look for files matching anything. + * For example, {@code rom/* /command*} will look for any path starting with + * {@code command} inside any subdirectory of {@code /rom}. + * + * @param path The wildcard-qualified path to search for. + * @return A list of paths that match the search string. + * @throws LuaException If the path doesn't exist. + */ @LuaFunction public final String[] find( String path ) throws LuaException { diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 34ee37853..43a5c473f 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -153,24 +153,58 @@ public class OSAPI implements ILuaAPI return c.getTime().getTime(); } + /** + * Adds an event to the event queue. This event can later be pulled with + * os.pullEvent. + * + * @param name The name of the event to queue. + * @param args The parameters of the event. + * @cc.tparam string name The name of the event to queue. + * @cc.param ... The parameters of the event. + * @cc.see os.pullEvent To pull the event queued + */ @LuaFunction public final void queueEvent( String name, IArguments args ) { apiEnvironment.queueEvent( name, args.drop( 1 ).getAll() ); } + /** + * Starts a timer that will run for the specified number of seconds. Once + * the timer fires, a timer event will be added to the queue with the ID + * returned from this function as the first parameter. + * + * @param timer The number of seconds until the timer fires. + * @return The ID of the new timer. + * @throws LuaException If the time is below zero. + */ @LuaFunction public final int startTimer( double timer ) throws LuaException { return apiEnvironment.startTimer( Math.round( checkFinite( 0, timer ) / 0.05 ) ); } + /** + * Cancels a timer previously started with startTimer. This will stop the + * timer from firing. + * + * @param token The ID of the timer to cancel. + * @see #startTimer To start a timer. + */ @LuaFunction public final void cancelTimer( int token ) { apiEnvironment.cancelTimer( token ); } + /** + * Sets an alarm that will fire at the specified world time. When it fires, + * an alarm event will be added to the event queue. + * + * @param time The time at which to fire the alarm, in the range [0.0, 24.0). + * @return The ID of the alarm that was set. + * @throws LuaException If the time is out of range. + */ @LuaFunction public final int setAlarm( double time ) throws LuaException { @@ -184,6 +218,13 @@ public class OSAPI implements ILuaAPI } } + /** + * Cancels an alarm previously started with setAlarm. This will stop the + * alarm from firing. + * + * @param token The ID of the alarm to cancel. + * @see #setAlarm To set an alarm. + */ @LuaFunction public final void cancelAlarm( int token ) { @@ -193,24 +234,41 @@ public class OSAPI implements ILuaAPI } } + /** + * Shuts down the computer immediately. + */ @LuaFunction( "shutdown" ) public final void doShutdown() { apiEnvironment.shutdown(); } + /** + * Reboots the computer immediately. + */ @LuaFunction( "reboot" ) public final void doReboot() { apiEnvironment.reboot(); } + /** + * Returns the ID of the computer. + * + * @return The ID of the computer. + */ @LuaFunction( { "getComputerID", "computerID" } ) public final int getComputerID() { return apiEnvironment.getComputerID(); } + /** + * Returns the label of the computer, or {@code nil} if none is set. + * + * @return The label of the computer. + * @cc.treturn string The label of the computer. + */ @LuaFunction( { "getComputerLabel", "computerLabel" } ) public final Object[] getComputerLabel() { @@ -229,12 +287,37 @@ public class OSAPI implements ILuaAPI apiEnvironment.setLabel( StringUtil.normaliseLabel( label.orElse( null ) ) ); } + /** + * Returns the number of seconds that the computer has been running. + * + * @return The computer's uptime. + */ @LuaFunction public final double clock() { return m_clock * 0.05; } + /** + * Returns the current time depending on the string passed in. This will + * always be in the range [0.0, 24.0). + * + * * If called with {@code ingame}, the current world time will be returned. + * This is the default if nothing is passed. + * * If called with {@code utc}, returns the hour of the day in UTC time. + * * If called with {@code local}, returns the hour of the day in the + * timezone the server is located in. + * + * This function can also be called with a table returned from {@link #date}, + * which will convert the date fields into a UNIX timestamp (number of + * seconds since 1 January 1970). + * + * @param args The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified. + * @return The hour of the selected locale, or a UNIX timestamp from the table, depending on the argument passed in. + * @cc.tparam [opt] string|table locale The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified. + * @see #date To get a date table that can be converted with this function. + * @throws LuaException If an invalid locale is passed. + */ @LuaFunction public final Object time( IArguments args ) throws LuaException { @@ -255,6 +338,20 @@ public class OSAPI implements ILuaAPI } } + /** + * Returns the day depending on the locale specified. + * + * * If called with {@code ingame}, returns the number of days since the + * world was created. This is the default. + * * If called with {@code utc}, returns the number of days since 1 January + * 1970 in the UTC timezone. + * * If called with {@code local}, returns the number of days since 1 + * January 1970 in the server's local timezone. + * + * @param args The locale to get the day for. Defaults to {@code ingame} if not set. + * @return The day depending on the selected locale. + * @throws LuaException If an invalid locale is passed. + */ @LuaFunction public final int day( Optional args ) throws LuaException { @@ -271,6 +368,20 @@ public class OSAPI implements ILuaAPI } } + /** + * Returns the number of seconds since an epoch depending on the locale. + * + * * If called with {@code ingame}, returns the number of seconds since the + * world was created. This is the default. + * * If called with {@code utc}, returns the number of seconds since 1 + * January 1970 in the UTC timezone. + * * If called with {@code local}, returns the number of seconds since 1 + * January 1970 in the server's local timezone. + * + * @param args The locale to get the seconds for. Defaults to {@code ingame} if not set. + * @return The seconds since the epoch depending on the selected locale. + * @throws LuaException If an invalid locale is passed. + */ @LuaFunction public final long epoch( Optional args ) throws LuaException { @@ -299,6 +410,26 @@ public class OSAPI implements ILuaAPI } } + /** + * Returns a date string (or table) using a specified format string and + * optional time to format. + * + * The format string takes the same formats as C's {@code strftime} function + * (http://www.cplusplus.com/reference/ctime/strftime/). In extension, it + * can be prefixed with an exclamation mark ({@code !}) to use UTC time + * instead of the server's local timezone. + * + * If the format is exactly {@code *t} (optionally prefixed with {@code !}), a + * table will be returned instead. This table has fields for the year, month, + * day, hour, minute, second, day of the week, day of the year, and whether + * Daylight Savings Time is in effect. This table can be converted to a UNIX + * timestamp (days since 1 January 1970) with {@link #date}. + * + * @param formatA The format of the string to return. This defaults to {@code %c}, which expands to a string similar to "Sat Dec 24 16:58:00 2011". + * @param timeA The time to convert to a string. This defaults to the current time. + * @return The resulting format string. + * @throws LuaException If an invalid format is passed. + */ @LuaFunction public final Object date( Optional formatA, Optional timeA ) throws LuaException { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index 8367e1f8b..dd15192db 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -16,6 +16,7 @@ import dan200.computercraft.shared.util.StringUtil; import net.minecraft.item.ItemStack; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Optional; /** @@ -47,12 +48,23 @@ public class DiskDrivePeripheral implements IPeripheral return "drive"; } + /** + * Returns whether a disk is currently inserted in the drive. + * + * @return Whether a disk is currently inserted in the drive. + */ @LuaFunction public final boolean isDiskPresent() { return !diskDrive.getDiskStack().isEmpty(); } + /** + * Returns the label of the disk in the drive if available. + * + * @return The label of the disk, or {@code nil} if either no disk is inserted or the disk doesn't have a label. + * @cc.treturn string The label of the disk, or {@code nil} if either no disk is inserted or the disk doesn't have a label. + */ @LuaFunction public final Object[] getDiskLabel() { @@ -61,6 +73,17 @@ public class DiskDrivePeripheral implements IPeripheral return media == null ? null : new Object[] { media.getLabel( stack ) }; } + /** + * Sets or clears the label for a disk. + * + * If no label or {@code nil} is passed, the label will be cleared. + * + * If the inserted disk's label can't be changed (for example, a record), + * an error will be thrown. + * + * @param labelA The new label of the disk, or {@code nil} to clear. + * @throws LuaException If the disk's label can't be changed. + */ @LuaFunction( mainThread = true ) public final void setDiskLabel( Optional labelA ) throws LuaException { @@ -76,18 +99,36 @@ public class DiskDrivePeripheral implements IPeripheral diskDrive.setDiskStack( stack ); } + /** + * Returns whether a disk with data is inserted. + * + * @param computer The computer object + * @return Whether a disk with data is inserted. + */ @LuaFunction public final boolean hasData( IComputerAccess computer ) { return diskDrive.getDiskMountPath( computer ) != null; } + /** + * Returns the mount path for the inserted disk. + * + * @param computer The computer object + * @return The mount path for the disk, or {@code nil} if no data disk is inserted. + */ @LuaFunction + @Nullable public final String getMountPath( IComputerAccess computer ) { return diskDrive.getDiskMountPath( computer ); } + /** + * Returns whether a disk with audio is inserted. + * + * @return Whether a disk with audio is inserted. + */ @LuaFunction public final boolean hasAudio() { @@ -96,7 +137,13 @@ public class DiskDrivePeripheral implements IPeripheral return media != null && media.getAudio( stack ) != null; } + /** + * Returns the title of the inserted audio disk. + * + * @return The title of the audio, or {@code nil} if no audio disk is inserted. + */ @LuaFunction + @Nullable public final Object getAudioTitle() { ItemStack stack = diskDrive.getDiskStack(); @@ -104,24 +151,41 @@ public class DiskDrivePeripheral implements IPeripheral return media != null ? media.getAudioTitle( stack ) : false; } + /** + * Plays the audio in the inserted disk, if available. + */ @LuaFunction public final void playAudio() { diskDrive.playDiskAudio(); } + /** + * Stops any audio that may be playing. + * + * @see #playAudio + */ @LuaFunction public final void stopAudio() { diskDrive.stopDiskAudio(); } + /** + * Ejects any disk that may be in the drive. + */ @LuaFunction public final void ejectDisk() { diskDrive.ejectDisk(); } + /** + * Returns the ID of the disk inserted in the drive. + * + * @return The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted. + * @cc.treturn number The The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted. + */ @LuaFunction public final Object[] getDiskID() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index 5235e127c..6e7da2aad 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -42,6 +42,13 @@ public class PrinterPeripheral implements IPeripheral // FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be // persisted correctly. + /** + * Writes text to the current page. + * + * @param arguments The values to write to the page. + * @cc.tparam string|number ... The values to write to the page. + * @throws LuaException If any values couldn't be converted to a string, or if no page is started. + */ @LuaFunction public final void write( IArguments arguments ) throws LuaException { @@ -51,6 +58,14 @@ public class PrinterPeripheral implements IPeripheral page.setCursorPos( page.getCursorX() + text.length(), page.getCursorY() ); } + /** + * Returns the current position of the cursor on the page. + * + * @return The position of the cursor. + * @cc.treturn number The X position of the cursor. + * @cc.treturn number The Y position of the cursor. + * @throws LuaException If a page isn't being printed. + */ @LuaFunction public final Object[] getCursorPos() throws LuaException { @@ -60,6 +75,13 @@ public class PrinterPeripheral implements IPeripheral return new Object[] { x + 1, y + 1 }; } + /** + * Sets the position of the cursor on the page. + * + * @param x The X coordinate to set the cursor at. + * @param y The Y coordinate to set the cursor at. + * @throws LuaException If a page isn't being printed. + */ @LuaFunction public final void setCursorPos( int x, int y ) throws LuaException { @@ -67,6 +89,14 @@ public class PrinterPeripheral implements IPeripheral page.setCursorPos( x - 1, y - 1 ); } + /** + * Returns the size of the current page. + * + * @return The size of the page. + * @cc.treturn number The width of the page. + * @cc.treturn number The height of the page. + * @throws LuaException If a page isn't being printed. + */ @LuaFunction public final Object[] getPageSize() throws LuaException { @@ -76,12 +106,23 @@ public class PrinterPeripheral implements IPeripheral return new Object[] { width, height }; } + /** + * Starts printing a new page. + * + * @return Whether a new page could be started. + */ @LuaFunction( mainThread = true ) public final boolean newPage() { return printer.startNewPage(); } + /** + * Finalizes printing of the current page and outputs it to the tray. + * + * @return Whether the page could be successfully finished. + * @throws LuaException If a page isn't being printed. + */ @LuaFunction( mainThread = true ) public final boolean endPage() throws LuaException { @@ -89,6 +130,12 @@ public class PrinterPeripheral implements IPeripheral return printer.endCurrentPage(); } + /** + * Sets the title of the current page. + * + * @param title The title to set for the page. + * @throws LuaException If a page isn't being printed. + */ @LuaFunction public final void setPageTitle( Optional title ) throws LuaException { @@ -96,12 +143,22 @@ public class PrinterPeripheral implements IPeripheral printer.setPageTitle( StringUtil.normaliseLabel( title.orElse( "" ) ) ); } + /** + * Returns the amount of ink left in the printer. + * + * @return The amount of ink available to print with. + */ @LuaFunction public final int getInkLevel() { return printer.getInkLevel(); } + /** + * Returns the amount of paper left in the printer. + * + * @return The amount of paper available to print with. + */ @LuaFunction public final int getPaperLevel() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index c1c5527e7..217b5b59f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -58,6 +58,20 @@ public abstract class SpeakerPeripheral implements IPeripheral return "speaker"; } + /** + * Plays a sound through the speaker. + * + * This plays sounds similar to the {@code /playsound} command in Minecraft. + * It takes the namespaced path of a sound (e.g. {@code minecraft:block.note_block.harp}) + * with an optional volume and speed multiplier, and plays it through the speaker. + * + * @param context The Lua context + * @param name The name of the sound to play. + * @param volumeA The volume to play the sound at, from 0.0 to 3.0. Defaults to 1.0. + * @param pitchA The speed to play the sound at, from 0.5 to 2.0. Defaults to 1.0. + * @return Whether the sound could be played. + * @throws LuaException If the sound name couldn't be decoded. + */ @LuaFunction public final boolean playSound( ILuaContext context, String name, Optional volumeA, Optional pitchA ) throws LuaException { @@ -77,6 +91,23 @@ public abstract class SpeakerPeripheral implements IPeripheral return playSound( context, identifier, volume, pitch, false ); } + /** + * Plays a note block note through the speaker. + * + * This takes the name of a note to play, as well as optionally the volume + * and pitch to play the note at. + * + * The pitch argument uses semitones as the unit. This directly maps to the + * number of clicks on a note block. For reference, 0, 12, and 24 map to F#, + * and 6 and 18 map to C. + * + * @param context The Lua context + * @param name The name of the note to play. + * @param volumeA The volume to play the note at, from 0.0 to 3.0. Defaults to 1.0. + * @param pitchA The pitch to play the note at in semitones, from 0 to 24. Defaults to 12. + * @return Whether the note could be played. + * @throws LuaException If the instrument doesn't exist. + */ @LuaFunction public final synchronized boolean playNote( ILuaContext context, String name, Optional volumeA, Optional pitchA ) throws LuaException { From a5f7cf833400377fb4cf6464a6b04d8a0f50615e Mon Sep 17 00:00:00 2001 From: Naheulf Date: Mon, 6 Jul 2020 15:18:07 +0200 Subject: [PATCH 278/711] Add enchantments and unbreakable to ItemData.java. (#488) --- .../peripheral/generic/data/BlockData.java | 3 +- .../peripheral/generic/data/DataHelpers.java | 18 ++++- .../peripheral/generic/data/FluidData.java | 3 +- .../peripheral/generic/data/ItemData.java | 78 ++++++++++++++++++- 4 files changed, 93 insertions(+), 9 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java index d037be6af..13d516c8f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -13,14 +13,13 @@ import net.minecraft.state.IProperty; import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; -import java.util.Objects; public class BlockData { @Nonnull public static > T fill( @Nonnull T data, @Nonnull BlockState state ) { - data.put( "name", Objects.toString( state.getBlock().getRegistryName() ) ); + data.put( "name", DataHelpers.getId( state.getBlock() ) ); Map stateTable = new HashMap<>(); for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java index 8ed831dd0..5a3f5c4d0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java @@ -7,17 +7,31 @@ package dan200.computercraft.shared.peripheral.generic.data; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.registries.IForgeRegistryEntry; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collection; import java.util.HashMap; import java.util.Map; -public class DataHelpers +public final class DataHelpers { - public static Map getTags( Collection tags ) + private DataHelpers() + { } + + @Nonnull + public static Map getTags( @Nonnull Collection tags ) { Map result = new HashMap<>( tags.size() ); for( ResourceLocation location : tags ) result.put( location.toString(), true ); return result; } + + @Nullable + public static String getId( @Nonnull IForgeRegistryEntry entry ) + { + ResourceLocation id = entry.getRegistryName(); + return id == null ? null : id.toString(); + } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java index d4249d733..e5b19af7d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java @@ -10,14 +10,13 @@ import net.minecraftforge.fluids.FluidStack; import javax.annotation.Nonnull; import java.util.Map; -import java.util.Objects; public class FluidData { @Nonnull public static > T fillBasic( @Nonnull T data, @Nonnull FluidStack stack ) { - data.put( "name", Objects.toString( stack.getFluid().getRegistryName() ) ); + data.put( "name", DataHelpers.getId( stack.getFluid() ) ); data.put( "amount", stack.getAmount() ); return data; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 534a10182..1a422487e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -7,6 +7,9 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.item.EnchantedBookItem; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.INBT; @@ -16,8 +19,7 @@ import net.minecraftforge.common.util.Constants; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Map; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; public class ItemData @@ -25,7 +27,7 @@ public class ItemData @Nonnull public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) { - data.put( "name", Objects.toString( stack.getItem().getRegistryName() ) ); + data.put( "name", DataHelpers.getId( stack.getItem() ) ); data.put( "count", stack.getCount() ); return data; } @@ -68,6 +70,21 @@ public class ItemData } } + /* + * Used to hide some data from ItemStack tooltip. + * @see https://minecraft.gamepedia.com/Tutorials/Command_NBT_tags + * @see ItemStack#getTooltip + */ + int hideFlags = tag != null ? tag.getInt( "HideFlags" ) : 0; + + List> enchants = getAllEnchants( stack, hideFlags ); + if( !enchants.isEmpty() ) data.put( "enchantments", enchants ); + + if( tag != null && tag.getBoolean( "Unbreakable" ) && (hideFlags & 4) == 0 ) + { + data.put( "unbreakable", true ); + } + return data; } @@ -83,4 +100,59 @@ public class ItemData return null; } } + + /** + * Retrieve all visible enchantments from given stack. Try to follow all tooltip rules : order and visibility. + * + * @param stack Stack to analyse + * @param hideFlags An int used as bit field to provide visibility rules. + * @return A filled list that contain all visible enchantments. + */ + @Nonnull + private static List> getAllEnchants( @Nonnull ItemStack stack, int hideFlags ) + { + ArrayList> enchants = new ArrayList<>( 0 ); + + if( stack.getItem() instanceof EnchantedBookItem && (hideFlags & 32) == 0 ) + { + addEnchantments( EnchantedBookItem.getEnchantments( stack ), enchants ); + } + + if( stack.isEnchanted() && (hideFlags & 1) == 0 ) + { + /* + * Mimic the EnchantmentHelper.getEnchantments(ItemStack stack) behavior without special case for Enchanted book. + * I'll do that to have the same data than ones displayed in tooltip. + * @see EnchantmentHelper.getEnchantments(ItemStack stack) + */ + addEnchantments( stack.getEnchantmentTagList(), enchants ); + } + + return enchants; + } + + /** + * Converts a Mojang enchant map to a Lua list. + * + * @param rawEnchants The raw NBT list of enchantments + * @param enchants The enchantment map to add it to. + * @see net.minecraft.enchantment.EnchantmentHelper + */ + private static void addEnchantments( @Nonnull ListNBT rawEnchants, @Nonnull ArrayList> enchants ) + { + if( rawEnchants.isEmpty() ) return; + + enchants.ensureCapacity( enchants.size() + rawEnchants.size() ); + + for( Map.Entry entry : EnchantmentHelper.func_226652_a_( rawEnchants ).entrySet() ) + { + Enchantment enchantment = entry.getKey(); + Integer level = entry.getValue(); + HashMap enchant = new HashMap<>( 3 ); + enchant.put( "name", DataHelpers.getId( enchantment ) ); + enchant.put( "level", level ); + enchant.put( "displayName", enchantment.getDisplayName( level ).getString() ); + enchants.add( enchant ); + } + } } From 90c5d3f1e8228938facc99dfd0a3d97296d740a7 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 6 Jul 2020 15:20:55 +0100 Subject: [PATCH 279/711] Don't load the chunk when watching monitors Hopefully fixes #493 --- .../shared/peripheral/monitor/MonitorWatcher.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java index 8ea81ceb4..89032b3bb 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java @@ -15,6 +15,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.world.ChunkWatchEvent; @@ -46,7 +47,7 @@ public final class MonitorWatcher public static void onWatch( ChunkWatchEvent.Watch event ) { ChunkPos chunkPos = event.getPos(); - Chunk chunk = event.getWorld().getChunk( chunkPos.x, chunkPos.z ); + Chunk chunk = (Chunk) event.getWorld().getChunk( chunkPos.x, chunkPos.z, ChunkStatus.FULL, false ); if( chunk == null ) return; for( TileEntity te : chunk.getTileEntityMap().values() ) From 3f277a7a7b1c5f5c5260810eebfbc699cc382396 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 6 Jul 2020 15:38:09 +0100 Subject: [PATCH 280/711] Bump version to 1.90.0 Going to let this stew for a couple of days - there's probably something else which'll break. --- gradle.properties | 2 +- .../data/computercraft/lua/rom/help/changelog.txt | 15 ++++++++++++++- .../data/computercraft/lua/rom/help/whatsnew.txt | 13 ++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/gradle.properties b/gradle.properties index 0a6ccbc8b..08369c0f6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.89.2 +mod_version=1.90.0 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 294e53eb5..9440b0f00 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,6 +1,19 @@ -# New features in CC: Tweaked 1.89.2 +# New features in CC: Tweaked 1.90.0 +* Add cc.image.nft module, for working with nft files. (JakobDev) +* [experimental] Provide a generic peripheral for any tile entity without an existing one. We currently provide methods for working with inventories, fluid tanks and energy storage. This is disabled by default, and must be turned on in the config. +* Add configuration to control the sizes of monitors and terminals. +* Allow getting "detailed" information about an item, using `turtle.getItemDetail(slot, true)`. This will contain the same information that the generic peripheral supplies. + +And several bug fixes: +* Add back config for allowing interacting with command computers. +* Fix write method missing from printers. * Fix dupe bug when killing an entity with a turtle. +* Correctly supply port in the Host header (neumond). +* Fix turtle.craft failing when missing an argument. +* Fix deadlock when mistakenly "watching" an unloaded chunk. + +Type "help changelog" to see the full version history. # New features in CC: Tweaked 1.89.1 diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index d6718d6b8..62a5aa8ca 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,5 +1,16 @@ -New features in CC: Tweaked 1.89.2 +New features in CC: Tweaked 1.90.0 +* Add cc.image.nft module, for working with nft files. (JakobDev) +* [experimental] Provide a generic peripheral for any tile entity without an existing one. We currently provide methods for working with inventories, fluid tanks and energy storage. This is disabled by default, and must be turned on in the config. +* Add configuration to control the sizes of monitors and terminals. +* Allow getting "detailed" information about an item, using `turtle.getItemDetail(slot, true)`. This will contain the same information that the generic peripheral supplies. + +And several bug fixes: +* Add back config for allowing interacting with command computers. +* Fix write method missing from printers. * Fix dupe bug when killing an entity with a turtle. +* Correctly supply port in the Host header (neumond). +* Fix turtle.craft failing when missing an argument. +* Fix deadlock when mistakenly "watching" an unloaded chunk. Type "help changelog" to see the full version history. From a6a1b9b8e527cb2f40714394a533763048989369 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 9 Jul 2020 21:59:19 +0100 Subject: [PATCH 281/711] Add a whole tonne of documentation There's a bit of duplication here, so we might try to clean this up, but it's a good starting point. --- build.gradle | 2 +- doc/stub/fs.lua | 38 ++-- doc/stub/http.lua | 41 ---- doc/stub/term.lua | 50 ----- illuaminate.sexp | 8 +- .../computercraft/core/apis/TermAPI.java | 2 + .../computercraft/core/apis/TermMethods.java | 180 ++++++++++++++++-- .../apis/handles/BinaryReadableHandle.java | 60 +++++- .../apis/handles/BinaryWritableHandle.java | 42 +++- .../apis/handles/EncodedReadableHandle.java | 30 +++ .../apis/handles/EncodedWritableHandle.java | 24 +++ .../core/apis/handles/HandleGeneric.java | 27 ++- .../apis/http/request/HttpResponseHandle.java | 37 +++- .../computercraft/core/terminal/Terminal.java | 10 +- .../shared/common/ClientTerminal.java | 4 - .../shared/common/ServerTerminal.java | 3 - .../modem/wired/WiredModemPeripheral.java | 1 + .../shared/turtle/apis/TurtleAPI.java | 26 +++ .../turtle/core/TurtleDetectCommand.java | 9 +- 19 files changed, 424 insertions(+), 170 deletions(-) delete mode 100644 doc/stub/term.lua diff --git a/build.gradle b/build.gradle index 590c6a713..eab59f562 100644 --- a/build.gradle +++ b/build.gradle @@ -122,7 +122,7 @@ dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" - cctJavadoc 'cc.tweaked:cct-javadoc:1.0.0' + cctJavadoc 'cc.tweaked:cct-javadoc:1.1.0' } // Compile tasks diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua index 4b20a96ed..6e3b56c84 100644 --- a/doc/stub/fs.lua +++ b/doc/stub/fs.lua @@ -14,27 +14,21 @@ -- @see getDrive function isDriveRoot(path) end --- Defined in bios.lua -function complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) end +--[[- Provides completion for a file or directory name, suitable for use with +@{read}. ---- A file handle which can be read from. --- --- @type ReadHandle --- @see fs.open -local ReadHandle = {} -function ReadHandle.read(count) end -function ReadHandle.readAll() end -function ReadHandle.readLine(with_trailing) end -function ReadHandle.seek(whence, offset) end -function ReadHandle.close() end +When a directory is a possible candidate for completion, two entries are +included - one with a trailing slash (indicating that entries within this +directory exist) and one without it (meaning this entry is an immediate +completion candidate). `include_dirs` can be set to @{false} to only include +those with a trailing slash. ---- A file handle which can be written to. --- --- @type WriteHandle --- @see fs.open -local WriteHandle = {} -function WriteHandle.write(text) end -function WriteHandle.writeLine(text) end -function WriteHandle.flush(text) end -function WriteHandle.seek(whence, offset) end -function WriteHandle.close() end +@tparam string path The path to complete. +@tparam string location The location where paths are resolved from. +@tparam[opt] boolean include_files When @{false}, only directories will be +included in the returned list. +@tparam[opt] boolean include_dirs When @{false}, "raw" directories will not be +included in the returned list. +@treturn { string... } A list of possible completion candidates. +]] +function complete(path, location, include_files, include_dirs) end diff --git a/doc/stub/http.lua b/doc/stub/http.lua index 7f9b51296..4be7a4180 100644 --- a/doc/stub/http.lua +++ b/doc/stub/http.lua @@ -93,47 +93,6 @@ function get(...) end -- @treturn Response|nil The failing http response, if available. function post(...) end ---- A http response. This acts very much like a @{fs.ReadHandle|file}, though --- provides some http specific methods. --- --- #### `http_success` event --- #### `http_failure` event --- --- @type Response --- @see http.request On how to make a http request. -local Response = {} - ---- Returns the response code and response message returned by the server --- --- @treturn number The response code (i.e. 200) --- @treturn string The response message (i.e. "OK") -function Response.getResponseCode() end - ---- Get a table containing the response's headers, in a format similar to that --- required by @{http.request}. If multiple headers are sent with the same --- name, they will be combined with a comma. --- --- @treturn { [string]=string } The response's headers. --- Make a request to [example.computercraft.cc](https://example.computercraft.cc), --- and print the returned headers. --- ```lua --- local request = http.get("https://example.computercraft.cc") --- print(textutils.serialize(request.getResponseHeaders())) --- -- => { --- -- [ "Content-Type" ] = "text/plain; charset=utf8", --- -- [ "content-length" ] = 17, --- -- ... --- -- } --- request.close() --- ``` -function Response.getResponseHeaders() end - -function Response.read(count) end -function Response.readAll() end -function Response.readLine(with_trailing) end -function Response.seek(whence, offset) end -function Response.close() end - --- Asynchronously determine whether a URL can be requested. -- -- If this returns `true`, one should also listen for [`http_check` diff --git a/doc/stub/term.lua b/doc/stub/term.lua deleted file mode 100644 index a9ea4e058..000000000 --- a/doc/stub/term.lua +++ /dev/null @@ -1,50 +0,0 @@ -function write(text) end -function scroll(lines) end -function setCursorPos(x, y) end -function setCursorBlink(blink) end -function getCursorPos() end -function getSize() end -function clear() end -function clearLine() end -function setTextColour(colour) end -setTextColor = setTextColour -function setBackgroundColour(colour) end -setBackgroundColor = setBackgroundColour -function isColour() end -isColor = isColour -function getTextColour() end -getTextColor = getTextColor -function getBackgroundColour() end -getBackgroundColor = getBackgroundColour -function blit(text, text_colours, background_colours) end -function setPaletteColour(colour, ...) end -setPaletteColor = setPaletteColour -function getPaletteColour(colour, ...) end -getPaletteColor = getPaletteColour - ---- @type Redirect -local Redirect = {} - -Redirect.write = write -Redirect.scroll = scroll -Redirect.setCursorPos = setCursorPos -Redirect.setCursorBlink = setCursorBlink -Redirect.getCursorPos = getCursorPos -Redirect.getSize = getSize -Redirect.clear = clear -Redirect.clearLine = clearLine -Redirect.setTextColour = setTextColour -Redirect.setTextColor = setTextColor -Redirect.setBackgroundColour = setBackgroundColour -Redirect.setBackgroundColor = setBackgroundColor -Redirect.isColour = isColour -Redirect.isColor = isColor -Redirect.getTextColour = getTextColour -Redirect.getTextColor = getTextColor -Redirect.getBackgroundColour = getBackgroundColour -Redirect.getBackgroundColor = getBackgroundColor -Redirect.blit = blit -Redirect.setPaletteColour = setPaletteColour -Redirect.setPaletteColor = setPaletteColor -Redirect.getPaletteColour = getPaletteColour -Redirect.getPaletteColor = getPaletteColor diff --git a/illuaminate.sexp b/illuaminate.sexp index 80276a487..2c2ebdc84 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -76,15 +76,10 @@ ;; Suppress warnings for currently undocumented modules. (at (; Java APIs - /doc/stub/fs.lua /doc/stub/http.lua /doc/stub/os.lua - /doc/stub/term.lua /doc/stub/turtle.lua ; Java generated APIs - /doc/javadoc/fs.lua - /doc/javadoc/http.lua - /doc/javadoc/os.lua /doc/javadoc/turtle.lua ; Peripherals /doc/javadoc/drive.lua @@ -101,7 +96,8 @@ (/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua /src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua - /src/main/resources/*/computercraft/lua/rom/programs/shell.lua) + /src/main/resources/*/computercraft/lua/rom/programs/shell.lua + /doc/stub/fs.lua) (linters -doc:unresolved-reference)) (at /src/test/resources/test-rom diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index ed05df142..243cca146 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; @@ -45,6 +46,7 @@ public class TermAPI extends TermMethods implements ILuaAPI * @cc.treturn number The red channel, will be between 0 and 1. * @cc.treturn number The green channel, will be between 0 and 1. * @cc.treturn number The blue channel, will be between 0 and 1. + * @see TermMethods#setPaletteColour(IArguments) To change the palette colour. */ @LuaFunction( { "nativePaletteColour", "nativePaletteColor" } ) public final Object[] nativePaletteColour( int colour ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/src/main/java/dan200/computercraft/core/apis/TermMethods.java index c55c59f7a..43090405d 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermMethods.java +++ b/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -20,7 +20,6 @@ import javax.annotation.Nonnull; * A base class for all objects which interact with a terminal. Namely the {@link TermAPI} and monitors. * * @cc.module term.Redirect - * @hidden */ public abstract class TermMethods { @@ -40,6 +39,16 @@ public abstract class TermMethods public abstract boolean isColour() throws LuaException; + /** + * Write {@code text} at the current cursor position, moving the cursor to the end of the text. + * + * Unlike functions like {@code write} and {@code print}, this does not wrap the text - it simply copies the + * text to the current terminal line. + * + * @param arguments The text to write. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.param text The text to write. + */ @LuaFunction public final void write( IArguments arguments ) throws LuaException { @@ -52,12 +61,29 @@ public abstract class TermMethods } } + /** + * Move all positions up (or down) by {@code y} pixels. + * + * Every pixel in the terminal will be replaced by the line {@code y} pixels below it. If {@code y} is negative, it + * will copy pixels from above instead. + * + * @param y The number of lines to move up by. This may be a negative number. + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction public final void scroll( int y ) throws LuaException { getTerminal().scroll( y ); } + /** + * Get the position of the cursor. + * + * @return The cursor's position. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.treturn number The x position of the cursor. + * @cc.treturn number The y position of the cursor. + */ @LuaFunction public final Object[] getCursorPos() throws LuaException { @@ -65,6 +91,13 @@ public abstract class TermMethods return new Object[] { terminal.getCursorX() + 1, terminal.getCursorY() + 1 }; } + /** + * Set the position of the cursor. {@link #write(IArguments) terminal writes} will begin from this position. + * + * @param x The new x position of the cursor. + * @param y The new y position of the cursor. + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction public final void setCursorPos( int x, int y ) throws LuaException { @@ -75,12 +108,24 @@ public abstract class TermMethods } } + /** + * Checks if the cursor is currently blinking. + * + * @return If the cursor is blinking. + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction public final boolean getCursorBlink() throws LuaException { return getTerminal().getCursorBlink(); } + /** + * Sets whether the cursor should be visible (and blinking) at the current {@link #getCursorPos() cursor position}. + * + * @param blink Whether the cursor should blink. + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction public final void setCursorBlink( boolean blink ) throws LuaException { @@ -91,6 +136,14 @@ public abstract class TermMethods } } + /** + * Get the size of the terminal. + * + * @return The terminal's size. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.treturn number The terminal's width. + * @cc.treturn number The terminal's height. + */ @LuaFunction public final Object[] getSize() throws LuaException { @@ -98,24 +151,49 @@ public abstract class TermMethods return new Object[] { terminal.getWidth(), terminal.getHeight() }; } + /** + * Clears the terminal, filling it with the {@link #getBackgroundColour() current background colour}. + * + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction public final void clear() throws LuaException { getTerminal().clear(); } + /** + * Clears the line the cursor is currently on, filling it with the {@link #getBackgroundColour() current background + * colour}. + * + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction public final void clearLine() throws LuaException { getTerminal().clearLine(); } + /** + * Return the colour that new text will be written as. + * + * @return The current text colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants, returned by this function. + */ @LuaFunction( { "getTextColour", "getTextColor" } ) public final int getTextColour() throws LuaException { return encodeColour( getTerminal().getTextColour() ); } + /** + * Set the colour that new text will be written as. + * + * @param colourArg The new text colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants. + */ @LuaFunction( { "setTextColour", "setTextColor" } ) public final void setTextColour( int colourArg ) throws LuaException { @@ -127,12 +205,28 @@ public abstract class TermMethods } } + /** + * Return the current background colour. This is used when {@link #write writing text} and {@link #clear clearing} + * the terminal. + * + * @return The current background colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants, returned by this function. + */ @LuaFunction( { "getBackgroundColour", "getBackgroundColor" } ) public final int getBackgroundColour() throws LuaException { return encodeColour( getTerminal().getBackgroundColour() ); } + /** + * Set the current background colour. This is used when {@link #write writing text} and {@link #clear clearing} the + * terminal. + * + * @param colourArg The new background colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.see colors For a list of colour constants. + */ @LuaFunction( { "setBackgroundColour", "setBackgroundColor" } ) public final void setBackgroundColour( int colourArg ) throws LuaException { @@ -144,12 +238,41 @@ public abstract class TermMethods } } + /** + * Determine if this terminal supports colour. + * + * Terminals which do not support colour will still allow writing coloured text/backgrounds, but it will be + * displayed in greyscale. + * + * @return Whether this terminal supports colour. + * @throws LuaException (hidden) If the terminal cannot be found. + */ @LuaFunction( { "isColour", "isColor" } ) public final boolean getIsColour() throws LuaException { return isColour(); } + /** + * Writes {@code text} to the terminal with the specific foreground and background characters. + * + * As with {@link #write(IArguments)}, the text will be written at the current cursor location, with the cursor + * moving to the end of the text. + * + * {@code textColour} and {@code backgroundColour} must both be strings the same length as {@code text}. All + * characters represent a single hexadecimal digit, which is converted to one of CC's colours. For instance, + * {@code "a"} corresponds to purple. + * + * @param text The text to write. + * @param textColour The corresponding text colours. + * @param backgroundColour The corresponding background colours. + * @throws LuaException If the three inputs are not the same length. + * @cc.see colors For a list of colour constants, and their hexadecimal values. + * @cc.usage Prints "Hello, world!" in rainbow text. + *
{@code
+     * term.blit("Hello, world!","01234456789ab","0000000000000")
+     * }
+ */ @LuaFunction public final void blit( String text, String textColour, String backgroundColour ) throws LuaException { @@ -166,6 +289,38 @@ public abstract class TermMethods } } + /** + * Set the palette for a specific colour. + * + * ComputerCraft's palette system allows you to change how a specific colour should be displayed. For instance, you + * can make @{colors.red} more red by setting its palette to #FF0000. This does now allow you to draw more + * colours - you are still limited to 16 on the screen at one time - but you can change which colours are + * used. + * + * @param args The new palette values. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.tparam [1] number index The colour whose palette should be changed. + * @cc.tparam number colour A 24-bit integer representing the RGB value of the colour. For instance the integer + * `0xFF0000` corresponds to the colour #FF0000. + * @cc.tparam [2] number index The colour whose palette should be changed. + * @cc.tparam number r The intensity of the red channel, between 0 and 1. + * @cc.tparam number g The intensity of the green channel, between 0 and 1. + * @cc.tparam number b The intensity of the blue channel, between 0 and 1. + * @cc.usage Change the @{colors.red|red colour} from the default #CC4C4C to #FF0000. + *
{@code
+     * term.setPaletteColour(colors.red, 0xFF0000)
+     * term.setTextColour(colors.red)
+     * print("Hello, world!")
+     * }
+ * @cc.usage As above, but specifying each colour channel separately. + *
{@code
+     * term.setPaletteColour(colors.red, 1, 0, 0)
+     * term.setTextColour(colors.red)
+     * print("Hello, world!")
+     * }
+ * @cc.see colors.unpackRGB To convert from the 24-bit format to three separate channels. + * @cc.see colors.packRGB To convert from three separate channels to the 24-bit format. + */ @LuaFunction( { "setPaletteColour", "setPaletteColor" } ) public final void setPaletteColour( IArguments args ) throws LuaException { @@ -185,6 +340,16 @@ public abstract class TermMethods } } + /** + * Get the current palette for a specific colour. + * + * @param colourArg The colour whose palette should be fetched. + * @return The resulting colour. + * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.treturn number The red channel, will be between 0 and 1. + * @cc.treturn number The green channel, will be between 0 and 1. + * @cc.treturn number The blue channel, will be between 0 and 1. + */ @LuaFunction( { "getPaletteColour", "getPaletteColor" } ) public final Object[] getPaletteColour( int colourArg ) throws LuaException { @@ -192,12 +357,8 @@ public abstract class TermMethods Terminal terminal = getTerminal(); synchronized( terminal ) { - if( terminal.getPalette() != null ) - { - return ArrayUtils.toObject( terminal.getPalette().getColour( colour ) ); - } + return ArrayUtils.toObject( terminal.getPalette().getColour( colour ) ); } - return null; } public static int parseColour( int colour ) throws LuaException @@ -216,10 +377,7 @@ public abstract class TermMethods public static void setColour( Terminal terminal, int colour, double r, double g, double b ) { - if( terminal.getPalette() != null ) - { - terminal.getPalette().setColour( colour, r, g, b ); - terminal.setChanged(); - } + terminal.getPalette().setColour( colour, r, g, b ); + terminal.setChanged(); } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index ce9fda477..807e1c331 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.core.apis.handles; -import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; @@ -19,6 +18,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +/** + * A file handle opened with {@link dan200.computercraft.core.apis.FSAPI#open(String, String)} with the {@code "rb"} + * mode. + * + * @cc.module fs.BinaryReadHandle + */ public class BinaryReadableHandle extends HandleGeneric { private static final int BUFFER_SIZE = 8192; @@ -27,7 +32,7 @@ public class BinaryReadableHandle extends HandleGeneric final SeekableByteChannel seekable; private final ByteBuffer single = ByteBuffer.allocate( 1 ); - protected BinaryReadableHandle( ReadableByteChannel reader, SeekableByteChannel seekable, Closeable closeable ) + BinaryReadableHandle( ReadableByteChannel reader, SeekableByteChannel seekable, Closeable closeable ) { super( closeable ); this.reader = reader; @@ -45,6 +50,18 @@ public class BinaryReadableHandle extends HandleGeneric return of( channel, channel ); } + /** + * Read a number of bytes from this file. + * + * @param countArg The number of bytes to read. When absent, a single byte will be read as a number. This + * may be 0 to determine we are at the end of the file. + * @return The read bytes. + * @throws LuaException When trying to read a negative number of bytes. + * @throws LuaException If the file has been closed. + * @cc.treturn [1] nil If we are at the end of the file. + * @cc.treturn [2] number The value of the byte read. This is returned when the {@code count} is absent. + * @cc.treturn [3] string The bytes read as a string. This is returned when the {@code count} is given. + */ @LuaFunction public final Object[] read( Optional countArg ) throws LuaException { @@ -122,6 +139,13 @@ public class BinaryReadableHandle extends HandleGeneric } } + /** + * Read the remainder of the file. + * + * @return The file, or {@code null} if at the end of it. + * @throws LuaException If the file has been closed. + * @cc.treturn string|nil The remaining contents of the file, or {@code nil} if we are at the end. + */ @LuaFunction public final Object[] readAll() throws LuaException { @@ -151,6 +175,14 @@ public class BinaryReadableHandle extends HandleGeneric } } + /** + * Read a line from the file. + * + * @param withTrailingArg Whether to include the newline characters with the returned string. Defaults to {@code false}. + * @return The read string. + * @throws LuaException If the file has been closed. + * @cc.treturn string|nil The read line or {@code nil} if at the end of the file. + */ @LuaFunction public final Object[] readLine( Optional withTrailingArg ) throws LuaException { @@ -205,16 +237,34 @@ public class BinaryReadableHandle extends HandleGeneric public static class Seekable extends BinaryReadableHandle { - public Seekable( SeekableByteChannel seekable, Closeable closeable ) + Seekable( SeekableByteChannel seekable, Closeable closeable ) { super( seekable, seekable, closeable ); } + /** + * Seek to a new position within the file, changing where bytes are written to. The new position is an offset + * given by {@code offset}, relative to a start position determined by {@code whence}: + * + * - {@code "set"}: {@code offset} is relative to the beginning of the file. + * - {@code "cur"}: Relative to the current position. This is the default. + * - {@code "end"}: Relative to the end of the file. + * + * In case of success, {@code seek} returns the new file position from the beginning of the file. + * + * @param whence Where the offset is relative to. + * @param offset The offset to seek to. + * @return The new position. + * @throws LuaException If the file has been closed. + * @cc.treturn [1] number The new position. + * @cc.treturn [2] nil If seeking failed. + * @cc.treturn string The reason seeking failed. + */ @LuaFunction - public final Object[] seek( IArguments arguments ) throws LuaException + public final Object[] seek( Optional whence, Optional offset ) throws LuaException { checkOpen(); - return handleSeek( seekable, arguments ); + return handleSeek( seekable, whence, offset ); } } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index b5b3647bb..e1a71c964 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -16,7 +16,14 @@ import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; import java.nio.channels.WritableByteChannel; +import java.util.Optional; +/** + * A file handle opened by {@link dan200.computercraft.core.apis.FSAPI#open} using the {@code "wb"} or {@code "ab"} + * modes. + * + * @cc.module fs.BinaryWriteHandle + */ public class BinaryWritableHandle extends HandleGeneric { private final WritableByteChannel writer; @@ -41,6 +48,14 @@ public class BinaryWritableHandle extends HandleGeneric return of( channel, channel ); } + /** + * Write a string or byte to the file. + * + * @param arguments The value to write. + * @throws LuaException If the file has been closed. + * @cc.tparam [1] number The byte to write. + * @cc.tparam [2] string The string to write. + */ @LuaFunction public final void write( IArguments arguments ) throws LuaException { @@ -72,6 +87,11 @@ public class BinaryWritableHandle extends HandleGeneric } } + /** + * Save the current file without closing it. + * + * @throws LuaException If the file has been closed. + */ @LuaFunction public final void flush() throws LuaException { @@ -93,11 +113,29 @@ public class BinaryWritableHandle extends HandleGeneric super( seekable, seekable, closeable ); } + /** + * Seek to a new position within the file, changing where bytes are written to. The new position is an offset + * given by {@code offset}, relative to a start position determined by {@code whence}: + * + * - {@code "set"}: {@code offset} is relative to the beginning of the file. + * - {@code "cur"}: Relative to the current position. This is the default. + * - {@code "end"}: Relative to the end of the file. + * + * In case of success, {@code seek} returns the new file position from the beginning of the file. + * + * @param whence Where the offset is relative to. + * @param offset The offset to seek to. + * @return The new position. + * @throws LuaException If the file has been closed. + * @cc.treturn [1] number The new position. + * @cc.treturn [2] nil If seeking failed. + * @cc.treturn string The reason seeking failed. + */ @LuaFunction - public final Object[] seek( IArguments args ) throws LuaException + public final Object[] seek( Optional whence, Optional offset ) throws LuaException { checkOpen(); - return handleSeek( seekable, args ); + return handleSeek( seekable, whence, offset ); } } } diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index 0a935fc22..3f2080f3f 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -20,6 +20,12 @@ import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.util.Optional; +/** + * A file handle opened with {@link dan200.computercraft.core.apis.FSAPI#open(String, String)} with the {@code "r"} + * mode. + * + * @cc.module fs.ReadHandle + */ public class EncodedReadableHandle extends HandleGeneric { private static final int BUFFER_SIZE = 8192; @@ -37,6 +43,14 @@ public class EncodedReadableHandle extends HandleGeneric this( reader, reader ); } + /** + * Read a line from the file. + * + * @param withTrailingArg Whether to include the newline characters with the returned string. Defaults to {@code false}. + * @return The read string. + * @throws LuaException If the file has been closed. + * @cc.treturn string|nil The read line or {@code nil} if at the end of the file. + */ @LuaFunction public final Object[] readLine( Optional withTrailingArg ) throws LuaException { @@ -62,6 +76,13 @@ public class EncodedReadableHandle extends HandleGeneric } } + /** + * Read the remainder of the file. + * + * @return The file, or {@code null} if at the end of it. + * @throws LuaException If the file has been closed. + * @cc.treturn nil|string The remaining contents of the file, or {@code nil} if we are at the end. + */ @LuaFunction public final Object[] readAll() throws LuaException { @@ -87,6 +108,15 @@ public class EncodedReadableHandle extends HandleGeneric } } + /** + * Read a number of characters from this file. + * + * @param countA The number of characters to read, defaulting to 1. + * @return The read characters. + * @throws LuaException When trying to read a negative number of characters. + * @throws LuaException If the file has been closed. + * @cc.treturn string|nil The read characters, or {@code nil} if at the of the file. + */ @LuaFunction public final Object[] read( Optional countA ) throws LuaException { diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java index 61bfe152b..4d548ce03 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java @@ -21,6 +21,11 @@ import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; +/** + * A file handle opened by {@link dan200.computercraft.core.apis.FSAPI#open} using the {@code "w"} or {@code "a"} modes. + * + * @cc.module fs.WriteHandle + */ public class EncodedWritableHandle extends HandleGeneric { private final BufferedWriter writer; @@ -31,6 +36,13 @@ public class EncodedWritableHandle extends HandleGeneric this.writer = writer; } + /** + * Write a string of characters to the file. + * + * @param args The value to write. + * @throws LuaException If the file has been closed. + * @cc.param The value to write to the file. + */ @LuaFunction public final void write( IArguments args ) throws LuaException { @@ -46,6 +58,13 @@ public class EncodedWritableHandle extends HandleGeneric } } + /** + * Write a string of characters to the file, follwing them with a new line character. + * + * @param args The value to write. + * @throws LuaException If the file has been closed. + * @cc.param The value to write to the file. + */ @LuaFunction public final void writeLine( IArguments args ) throws LuaException { @@ -62,6 +81,11 @@ public class EncodedWritableHandle extends HandleGeneric } } + /** + * Save the current file without closing it. + * + * @throws LuaException If the file has been closed. + */ @LuaFunction public final void flush() throws LuaException { diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index 3f816a1aa..418ab07dd 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.core.apis.handles; -import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.shared.util.IoUtil; @@ -15,6 +14,7 @@ import java.io.Closeable; import java.io.IOException; import java.nio.channels.Channel; import java.nio.channels.SeekableByteChannel; +import java.util.Optional; public abstract class HandleGeneric { @@ -39,6 +39,13 @@ public abstract class HandleGeneric closable = null; } + /** + * Close this file, freeing any resources it uses. + * + * Once a file is closed it may no longer be read or written to. + * + * @throws LuaException If the file has already been closed. + */ @LuaFunction( "close" ) public final void doClose() throws LuaException { @@ -51,27 +58,27 @@ public abstract class HandleGeneric * Shared implementation for various file handle types. * * @param channel The channel to seek in - * @param args The Lua arguments to process, like Lua's {@code file:seek}. + * @param whence The seeking mode. + * @param offset The offset to seek to. * @return The new position of the file, or null if some error occurred. * @throws LuaException If the arguments were invalid * @see {@code file:seek} in the Lua manual. */ - protected static Object[] handleSeek( SeekableByteChannel channel, IArguments args ) throws LuaException + protected static Object[] handleSeek( SeekableByteChannel channel, Optional whence, Optional offset ) throws LuaException { - String whence = args.optString( 0, "cur" ); - long offset = args.optLong( 1, 0 ); + long actualOffset = offset.orElse( 0L ); try { - switch( whence ) + switch( whence.orElse( "cur" ) ) { case "set": - channel.position( offset ); + channel.position( actualOffset ); break; case "cur": - channel.position( channel.position() + offset ); + channel.position( channel.position() + actualOffset ); break; case "end": - channel.position( channel.size() + offset ); + channel.position( channel.size() + actualOffset ); break; default: throw new LuaException( "bad argument #1 to 'seek' (invalid option '" + whence + "'" ); @@ -81,7 +88,7 @@ public abstract class HandleGeneric } catch( IllegalArgumentException e ) { - return new Object[] { false, "Position is negative" }; + return new Object[] { null, "Position is negative" }; } catch( IOException e ) { diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java index 8000a6c1e..89038f99c 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java @@ -5,7 +5,11 @@ */ package dan200.computercraft.core.apis.http.request; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.core.apis.HTTPAPI; +import dan200.computercraft.core.apis.handles.BinaryReadableHandle; +import dan200.computercraft.core.apis.handles.EncodedReadableHandle; import dan200.computercraft.core.apis.handles.HandleGeneric; import dan200.computercraft.core.asm.ObjectSource; @@ -14,8 +18,12 @@ import java.util.Collections; import java.util.Map; /** - * Wraps a {@link dan200.computercraft.core.apis.handles.HandleGeneric} and provides additional methods for - * getting the response code and headers. + * A http response. This provides the same methods as a {@link EncodedReadableHandle file} (or + * {@link BinaryReadableHandle binary file} if the request used binary mode), though provides several request specific + * methods. + * + * @cc.module http.Response + * @see HTTPAPI#request(IArguments) On how to make a http request. */ public class HttpResponseHandle implements ObjectSource { @@ -32,12 +40,37 @@ public class HttpResponseHandle implements ObjectSource this.responseHeaders = responseHeaders; } + /** + * Returns the response code and response message returned by the server. + * + * @return The response code and message. + * @cc.treturn number The response code (i.e. 200) + * @cc.treturn string The response message (i.e. "OK") + */ @LuaFunction public final Object[] getResponseCode() { return new Object[] { responseCode, responseStatus }; } + /** + * Get a table containing the response's headers, in a format similar to that required by {@link HTTPAPI#request}. + * If multiple headers are sent with the same name, they will be combined with a comma. + * + * @return The response's headers. + * @cc.usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), and print the + * returned headers. + *
{@code
+     * local request = http.get("https://example.computercraft.cc")
+     * print(textutils.serialize(request.getResponseHeaders()))
+     * -- => {
+     * --  [ "Content-Type" ] = "text/plain; charset=utf8",
+     * --  [ "content-length" ] = 17,
+     * --  ...
+     * -- }
+     * request.close()
+     * }
+ */ @LuaFunction public final Map getResponseHeaders() { diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 6f8f6b921..f3ec0b2cf 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -10,6 +10,8 @@ import dan200.computercraft.shared.util.Palette; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; +import javax.annotation.Nonnull; + public class Terminal { private static final String base16 = "0123456789abcdef"; @@ -29,7 +31,6 @@ public class Terminal private final Palette m_palette = new Palette(); - private boolean m_changed = false; private final Runnable onChanged; public Terminal( int width, int height ) @@ -184,6 +185,7 @@ public class Terminal return m_cursorBackgroundColour; } + @Nonnull public Palette getPalette() { return m_palette; @@ -305,15 +307,9 @@ public class Terminal public final void setChanged() { - m_changed = true; if( onChanged != null ) onChanged.run(); } - public final void clearChanged() - { - m_changed = false; - } - public synchronized void write( PacketBuffer buffer ) { buffer.writeInt( m_cursorX ); diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 08fb599fe..73b6d6e9a 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -25,10 +25,6 @@ public class ClientTerminal implements ITerminal { boolean changed = m_terminalChanged; m_terminalChanged = false; - - Terminal terminal = m_terminal; - if( terminal != null ) terminal.clearChanged(); - return changed; } diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index a2385b684..4f2445ce5 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -58,9 +58,6 @@ public class ServerTerminal implements ITerminal public void update() { - Terminal terminal = m_terminal; - if( terminal != null ) terminal.clearChanged(); - m_terminalChangedLastFrame = m_terminalChanged.getAndSet( false ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index b4472f377..bdd1187ca 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -137,6 +137,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW * @param computer The calling computer. * @param name The peripheral's name. * @return A list of methods provided by this peripheral, or {@code nil} if it is not present. + * @cc.treturn { string... }|nil A list of methods provided by this peripheral, or {@code nil} if it is not present. * @see PeripheralAPI#getMethods */ @LuaFunction diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 3abcef060..260c9423f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -108,6 +108,8 @@ public class TurtleAPI implements ILuaAPI * Rotate the turtle 90 degress to the left. * * @return The turtle command result. + * @cc.treturn boolean Whether the turtle could successfully turn. + * @cc.treturn string|nil The reason the turtle could not turn. */ @LuaFunction public final MethodResult turnLeft() @@ -119,6 +121,8 @@ public class TurtleAPI implements ILuaAPI * Rotate the turtle 90 degress to the right. * * @return The turtle command result. + * @cc.treturn boolean Whether the turtle could successfully turn. + * @cc.treturn string|nil The reason the turtle could not turn. */ @LuaFunction public final MethodResult turnRight() @@ -279,6 +283,7 @@ public class TurtleAPI implements ILuaAPI * @param slot The slot to select. * @return The turtle command result. * @throws LuaException If the slot is out of range. + * @cc.treturn true When the slot has been selected. * @see #getSelectedSlot */ @@ -525,18 +530,39 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleEquipCommand( TurtleSide.RIGHT ) ); } + /** + * Get information about the block in front of the turtle. + * + * @return The turtle command result. + * @cc.treturn boolean Whether there is a block in front of the turtle. + * @cc.treturn table|string Information about the block in front, or a message explaining that there is no block. + */ @LuaFunction public final MethodResult inspect() { return trackCommand( new TurtleInspectCommand( InteractDirection.FORWARD ) ); } + /** + * Get information about the block above the turtle. + * + * @return The turtle command result. + * @cc.treturn boolean Whether there is a block above the turtle. + * @cc.treturn table|string Information about the above below, or a message explaining that there is no block. + */ @LuaFunction public final MethodResult inspectUp() { return trackCommand( new TurtleInspectCommand( InteractDirection.UP ) ); } + /** + * Get information about the block below the turtle. + * + * @return The turtle command result. + * @cc.treturn boolean Whether there is a block below the turtle. + * @cc.treturn table|string Information about the block below, or a message explaining that there is no block. + */ @LuaFunction public final MethodResult inspectDown() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index f036977d2..bb3b5126c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -36,11 +36,8 @@ public class TurtleDetectCommand implements ITurtleCommand BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.offset( direction ); - if( !WorldUtil.isLiquidBlock( world, newPosition ) && !world.isAirBlock( newPosition ) ) - { - return TurtleCommandResult.success(); - } - - return TurtleCommandResult.failure(); + return !WorldUtil.isLiquidBlock( world, newPosition ) && !world.isAirBlock( newPosition ) + ? TurtleCommandResult.success() + : TurtleCommandResult.failure(); } } From 46595e73dfc08d75c542f7ac637111c6d917fa30 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 11 Jul 2020 20:36:10 +0100 Subject: [PATCH 282/711] Initial update to Minecraft 1.16.1 A lot is broken, but at least we can get in game: - GUIs render a whole bunch of additional "inventory" text, which we really don't want. - Computers load from the wrong location. - There's some issues with using Forge's tags from outside of JSON recipes. We need to work out why. --- build.gradle | 2 +- gradle.properties | 6 ++-- .../dan200/computercraft/ComputerCraft.java | 4 +-- .../computercraft/ComputerCraftAPIImpl.java | 2 +- .../api/client/TransformedModel.java | 2 +- .../api/network/IPacketReceiver.java | 4 +-- .../api/network/IPacketSender.java | 4 +-- .../api/turtle/ITurtleAccess.java | 4 +-- .../client/ClientTableFormatter.java | 13 ++++--- .../client/gui/FixedWidthFontRenderer.java | 6 +++- .../computercraft/client/gui/GuiComputer.java | 12 ++++--- .../client/gui/GuiDiskDrive.java | 23 +++++------- .../computercraft/client/gui/GuiPrinter.java | 22 ++++++------ .../computercraft/client/gui/GuiPrintout.java | 22 +++++++----- .../computercraft/client/gui/GuiTurtle.java | 17 +++++---- .../proxy/ComputerCraftProxyClient.java | 27 ++++++++++++++ .../client/render/CableHighlightRenderer.java | 6 ++-- .../client/render/ComputerBorderRenderer.java | 2 +- .../client/render/ItemMapLikeRenderer.java | 2 +- .../client/render/ItemPocketRenderer.java | 6 +++- .../client/render/ItemPrintoutRenderer.java | 4 +-- .../render/MonitorHighlightRenderer.java | 6 ++-- .../render/MonitorTextureBufferShader.java | 2 +- .../client/render/PrintoutRenderer.java | 2 +- .../render/TileEntityMonitorRenderer.java | 8 ++++- .../render/TileEntityTurtleRenderer.java | 8 ++--- .../client/render/TurtleModelLoader.java | 6 ++-- .../client/render/TurtleMultiModel.java | 2 +- .../client/render/TurtleSmartItemModel.java | 6 ++-- .../dan200/computercraft/core/apis/FSAPI.java | 2 +- .../dan200/computercraft/core/apis/OSAPI.java | 20 +++++------ .../dan200/computercraft/data/Generators.java | 3 +- .../computercraft/data/LootTableProvider.java | 8 ++--- .../dan200/computercraft/data/LootTables.java | 12 +++---- .../dan200/computercraft/data/Recipes.java | 4 +-- .../java/dan200/computercraft/data/Tags.java | 36 +++++++++---------- .../dan200/computercraft/shared/Registry.java | 10 +++--- .../shared/TurtlePermissions.java | 6 ++-- .../shared/command/CommandComputerCraft.java | 17 ++++----- .../builder/HelpingArgumentBuilder.java | 21 +++++------ .../shared/command/text/ChatHelpers.java | 32 ++++++++--------- .../shared/command/text/TableFormatter.java | 16 ++++----- .../shared/common/TileGeneric.java | 4 +-- .../computer/blocks/BlockComputerBase.java | 4 +-- .../computer/blocks/TileCommandComputer.java | 9 ++--- .../computer/blocks/TileComputerBase.java | 4 +-- .../shared/computer/core/ComputerState.java | 2 +- .../computer/items/ItemComputerBase.java | 2 +- .../data/BlockNamedEntityLootCondition.java | 17 +++++---- .../data/ConstantLootConditionSerializer.java | 18 +++++----- .../data/HasComputerIdLootCondition.java | 17 +++++---- .../data/PlayerCreativeLootCondition.java | 17 +++++---- .../shared/media/items/ItemDisk.java | 2 +- .../shared/media/recipes/DiskRecipe.java | 4 +-- .../shared/network/NetworkHandler.java | 6 ++-- .../client/PlayRecordClientMessage.java | 5 +-- .../peripheral/diskdrive/DiskDriveState.java | 2 +- .../peripheral/diskdrive/TileDiskDrive.java | 6 ++-- .../peripheral/generic/data/BlockData.java | 8 ++--- .../peripheral/generic/data/ItemData.java | 2 +- .../peripheral/modem/ModemPeripheral.java | 4 +-- .../peripheral/modem/wired/BlockCable.java | 6 ++-- .../modem/wired/CableModemVariant.java | 2 +- .../peripheral/modem/wired/TileCable.java | 20 ++++------- .../modem/wired/TileWiredModemFull.java | 18 +++++----- .../modem/wireless/BlockWirelessModem.java | 4 +-- .../modem/wireless/TileWirelessModem.java | 6 ++-- .../wireless/WirelessModemPeripheral.java | 4 +-- .../peripheral/monitor/MonitorEdgeState.java | 2 +- .../peripheral/monitor/TileMonitor.java | 14 ++++---- .../peripheral/printer/PrinterPeripheral.java | 6 ++-- .../peripheral/printer/TilePrinter.java | 10 +++--- .../peripheral/speaker/SpeakerPeripheral.java | 18 +++++----- .../peripheral/speaker/TileSpeaker.java | 6 ++-- .../pocket/core/PocketServerComputer.java | 2 +- .../pocket/items/ItemPocketComputer.java | 13 +++---- .../peripherals/PocketModemPeripheral.java | 8 ++--- .../peripherals/PocketSpeakerPeripheral.java | 8 ++--- .../proxy/ComputerCraftProxyCommon.java | 31 +++++----------- .../shared/turtle/blocks/BlockTurtle.java | 20 ++++++----- .../shared/turtle/blocks/ITurtleTile.java | 4 +-- .../shared/turtle/blocks/TileTurtle.java | 9 ++--- .../shared/turtle/core/TurtleBrain.java | 22 ++++++------ .../turtle/core/TurtlePlaceCommand.java | 24 ++++++------- .../shared/turtle/core/TurtlePlayer.java | 7 ---- .../shared/turtle/upgrades/TurtleModem.java | 6 ++-- .../shared/turtle/upgrades/TurtleSpeaker.java | 6 ++-- .../shared/turtle/upgrades/TurtleTool.java | 20 +++++------ .../shared/util/ColourUtils.java | 6 ++-- .../shared/util/DropConsumer.java | 4 +-- .../computercraft/shared/util/IDAssigner.java | 7 ++-- .../shared/util/InventoryUtil.java | 8 ++--- .../computercraft/shared/util/RecordUtil.java | 4 +-- .../shared/util/WaterloggableHelpers.java | 4 +-- .../computercraft/shared/util/WorldUtil.java | 31 +++++++++------- .../shared/wired/WiredNetwork.java | 4 +-- src/main/resources/META-INF/mods.toml | 4 +-- .../core/ComputerTestDelegate.java | 6 ++-- .../core/filesystem/ResourceMountTest.java | 2 +- .../shared/wired/NetworkTest.java | 8 ++--- 100 files changed, 491 insertions(+), 443 deletions(-) diff --git a/build.gradle b/build.gradle index eab59f562..fbfe1da1b 100644 --- a/build.gradle +++ b/build.gradle @@ -109,7 +109,7 @@ dependencies { compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3:api") compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.15.2:6.0.0.9") - runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") + // runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") compileOnly 'com.google.auto.service:auto-service:1.0-rc7' annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' diff --git a/gradle.properties b/gradle.properties index 08369c0f6..77974d726 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.90.0 # Minecraft properties (update mods.toml when changing) -mc_version=1.15.2 -forge_version=31.1.41 -mappings_version=20200429-1.15.1 +mc_version=1.16.1 +forge_version=32.0.63 +mappings_version=20200707-1.16.1 diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index d712dc914..aeb00ad15 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -16,7 +16,7 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.turtle.upgrades.*; -import net.minecraft.resources.IReloadableResourceManager; +import net.minecraft.resources.IResourceManager; import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.server.ServerLifecycleHooks; @@ -141,7 +141,7 @@ public final class ComputerCraft public static InputStream getResourceFile( String domain, String subPath ) { - IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); + IResourceManager manager = ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().func_240970_h_(); try { return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream(); diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 28f6d4e71..fbe140d69 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -81,7 +81,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI @Override public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) { - IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); + IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().func_240970_h_(); ResourceMount mount = ResourceMount.get( domain, subPath, manager ); return mount.exists( "" ) ? mount : null; } diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java index c4c88eec3..ee40a44aa 100644 --- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -6,11 +6,11 @@ package dan200.computercraft.api.client; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelManager; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.vector.TransformationMatrix; import javax.annotation.Nonnull; import java.util.Objects; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index 49b37d889..509dc1d68 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.api.network; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -29,7 +29,7 @@ public interface IPacketReceiver * @return The receiver's position. */ @Nonnull - Vec3d getPosition(); + Vector3d getPosition(); /** * Get the maximum distance this receiver can send and receive messages. diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index bb9dc63d1..7276fbf51 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.api.network; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -29,7 +29,7 @@ public interface IPacketSender * @return The sender's position. */ @Nonnull - Vec3d getPosition(); + Vector3d getPosition(); /** * Get some sort of identification string for this sender. This does not strictly need to be unique, but you diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 53b176dbf..b11aaf0c7 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -13,7 +13,7 @@ import net.minecraft.inventory.IInventory; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.items.IItemHandlerModifiable; @@ -67,7 +67,7 @@ public interface ITurtleAccess * @see #getVisualYaw(float) */ @Nonnull - Vec3d getVisualPosition( float f ); + Vector3d getVisualPosition( float f ); /** * Returns the yaw the turtle is facing when it is rendered. diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 991fbbb1d..14c471faa 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -12,14 +12,12 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.NewChatGui; -import net.minecraft.client.gui.RenderComponentsUtil; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextFormatting; import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; -import java.util.List; public class ClientTableFormatter implements TableFormatter { @@ -57,7 +55,7 @@ public class ClientTableFormatter implements TableFormatter @Override public int getWidth( ITextComponent component ) { - return renderer().getStringWidth( component.getFormattedText() ); + return renderer().func_238414_a_( component ); } @Override @@ -66,10 +64,11 @@ public class ClientTableFormatter implements TableFormatter Minecraft mc = Minecraft.getInstance(); NewChatGui chat = mc.ingameGUI.getChatGUI(); - // Trim the text if it goes over the allowed length - int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); - List list = RenderComponentsUtil.splitText( component, maxWidth, mc.fontRenderer, false, false ); - if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); + // TODO: Trim the text if it goes over the allowed length + // int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() ); + // List list = RenderComponentsUtil.func_238505_a_( component, maxWidth, mc.fontRenderer ); + // if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id ); + chat.printChatMessageWithOptionalDeletion( component, id ); } @Override diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index e10c0351a..67b304185 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -13,10 +13,14 @@ import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderState; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexFormat; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.TransformationMatrix; import org.lwjgl.opengl.GL11; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 3008c9386..bd354e30c 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; @@ -21,6 +22,8 @@ import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; +import javax.annotation.Nonnull; + import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER; import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN; @@ -120,7 +123,7 @@ public final class GuiComputer extends Containe } @Override - public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) + public void func_230450_a_( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY ) { // Draw terminal terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); @@ -135,11 +138,10 @@ public final class GuiComputer extends Containe } @Override - public void render( int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) { - renderBackground(); - super.render( mouseX, mouseY, partialTicks ); - renderHoveredToolTip( mouseX, mouseY ); + super.render( stack, mouseX, mouseY, partialTicks ); + func_230459_a_( stack, mouseX, mouseY ); } @Override diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index 59b6e38d2..e4d2ab06c 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import net.minecraft.client.gui.screen.inventory.ContainerScreen; @@ -12,6 +13,8 @@ import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; +import javax.annotation.Nonnull; + public class GuiDiskDrive extends ContainerScreen { private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/disk_drive.png" ); @@ -22,26 +25,18 @@ public class GuiDiskDrive extends ContainerScreen } @Override - protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY ) - { - String title = this.title.getFormattedText(); - font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 ); - font.drawString( title, 8, ySize - 96 + 2, 0x404040 ); - } - - @Override - protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) + protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( BACKGROUND ); - blit( guiLeft, guiTop, 0, 0, xSize, ySize ); + blit( transform, guiLeft, guiTop, 0, 0, xSize, ySize ); } @Override - public void render( int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull MatrixStack transform, int mouseX, int mouseY, float partialTicks ) { - renderBackground(); - super.render( mouseX, mouseY, partialTicks ); - renderHoveredToolTip( mouseX, mouseY ); + renderBackground( transform ); + super.render( transform, mouseX, mouseY, partialTicks ); + func_230459_a_( transform, mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index 6073a459f..a6c14aea3 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -5,14 +5,16 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.shared.peripheral.printer.ContainerPrinter; import net.minecraft.client.gui.screen.inventory.ContainerScreen; -import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; +import javax.annotation.Nonnull; + public class GuiPrinter extends ContainerScreen { private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/printer.png" ); @@ -22,29 +24,29 @@ public class GuiPrinter extends ContainerScreen super( container, player, title ); } - @Override + /*@Override protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY ) { String title = getTitle().getFormattedText(); font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 ); font.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 ); - } + }*/ @Override - protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) + protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( BACKGROUND ); - blit( guiLeft, guiTop, 0, 0, xSize, ySize ); + blit( transform, guiLeft, guiTop, 0, 0, xSize, ySize ); - if( getContainer().isPrinting() ) blit( guiLeft + 34, guiTop + 21, 176, 0, 25, 45 ); + if( getContainer().isPrinting() ) blit( transform, guiLeft + 34, guiTop + 21, 176, 0, 25, 45 ); } @Override - public void render( int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) { - renderBackground(); - super.render( mouseX, mouseY, partialTicks ); - renderHoveredToolTip( mouseX, mouseY ); + renderBackground( stack ); + super.render( stack, mouseX, mouseY, partialTicks ); + func_230459_a_( stack, mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 37927e62a..e60d997aa 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.common.ContainerHeldItem; @@ -12,12 +13,14 @@ import dan200.computercraft.shared.media.items.ItemPrintout; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.TransformationMatrix; import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; +import javax.annotation.Nonnull; + import static dan200.computercraft.client.render.PrintoutRenderer.*; public class GuiPrintout extends ContainerScreen @@ -91,27 +94,28 @@ public class GuiPrintout extends ContainerScreen } @Override - public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) + protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { // Draw the printout RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); RenderSystem.enableDepthTest(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource(); - drawBorder( IDENTITY, renderer, guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book ); - drawText( IDENTITY, renderer, guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); + Matrix4f matrix = transform.getLast().getMatrix(); + drawBorder( matrix, renderer, guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book ); + drawText( matrix, renderer, guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); renderer.finish(); } @Override - public void render( int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) { // We must take the background further back in order to not overlap with our printed pages. setBlitOffset( getBlitOffset() - 1 ); - renderBackground(); + renderBackground( stack ); setBlitOffset( getBlitOffset() + 1 ); - super.render( mouseX, mouseY, partialTicks ); - renderHoveredToolTip( mouseX, mouseY ); + super.render( stack, mouseX, mouseY, partialTicks ); + func_230459_a_( stack, mouseX, mouseY ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 517cf140f..f84902e6b 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.client.gui; +import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; @@ -18,6 +19,8 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; +import javax.annotation.Nonnull; + public class GuiTurtle extends ContainerScreen { private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" ); @@ -102,12 +105,12 @@ public class GuiTurtle extends ContainerScreen int slotX = slot % 4; int slotY = slot / 4; minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 ); + // TODO: blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 ); } } @Override - protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY ) + protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { // Draw term boolean advanced = m_family == ComputerFamily.ADVANCED; @@ -116,17 +119,17 @@ public class GuiTurtle extends ContainerScreen // Draw border/inventory RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - blit( guiLeft, guiTop, 0, 0, xSize, ySize ); + blit( transform, guiLeft, guiTop, 0, 0, xSize, ySize ); drawSelectionSlot( advanced ); } @Override - public void render( int mouseX, int mouseY, float partialTicks ) + public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks ) { - renderBackground(); - super.render( mouseX, mouseY, partialTicks ); - renderHoveredToolTip( mouseX, mouseY ); + renderBackground( stack ); + super.render( stack, mouseX, mouseY, partialTicks ); + func_230459_a_( stack, mouseX, mouseY ); } @Override diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 70147c4c6..79facbaaf 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -11,13 +11,19 @@ import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TurtlePlayerRenderer; import dan200.computercraft.shared.Registry; +import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.inventory.ContainerComputer; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer; +import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.client.gui.ScreenManager; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderTypeLookup; +import net.minecraft.item.IItemPropertyGetter; +import net.minecraft.item.Item; +import net.minecraft.item.ItemModelsProperties; +import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -26,6 +32,8 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import java.util.function.Supplier; + @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD ) public final class ComputerCraftProxyClient { @@ -50,6 +58,25 @@ public final class ComputerCraftProxyClient // TODO: ClientRegistry.bindTileEntityRenderer( TileCable.FACTORY, x -> new TileEntityCableRenderer() ); RenderingRegistry.registerEntityRenderingHandler( Registry.ModEntities.TURTLE_PLAYER.get(), TurtlePlayerRenderer::new ); + + registerItemProperty( "state", + ( stack, world, player ) -> ItemPocketComputer.getState( stack ).ordinal(), + Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED + ); + registerItemProperty( "state", + ( stack, world, player ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0, + Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED + ); + } + + @SafeVarargs + private static void registerItemProperty( String name, IItemPropertyGetter getter, Supplier... items ) + { + ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, name ); + for( Supplier item : items ) + { + ItemModelsProperties.func_239418_a_( item.get(), id, getter ); + } } private static void registerContainers() diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index f88700b98..b8571e938 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -14,14 +14,14 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.DrawHighlightEvent; @@ -63,7 +63,7 @@ public final class CableHighlightRenderer ? CableShapes.getModemShape( state ) : CableShapes.getCableShape( state ); - Vec3d cameraPos = info.getProjectedView(); + Vector3d cameraPos = info.getProjectedView(); double xOffset = pos.getX() - cameraPos.getX(); double yOffset = pos.getY() - cameraPos.getY(); double zOffset = pos.getZ() - cameraPos.getZ(); diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java index 9c784d7fc..fb051995a 100644 --- a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java @@ -11,10 +11,10 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Matrix4f; import org.lwjgl.opengl.GL11; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index f25deea79..7ef903136 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -10,12 +10,12 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.AbstractClientPlayerEntity; import net.minecraft.client.renderer.FirstPersonRenderer; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Vector3f; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.Hand; import net.minecraft.util.HandSide; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3f; public abstract class ItemMapLikeRenderer { diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 157250d56..e260c048d 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -15,9 +15,13 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3f; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index 5fa6ada5d..9de945077 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -9,9 +9,9 @@ import com.mojang.blaze3d.matrix.MatrixStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.media.items.ItemPrintout; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.Vector3f; import net.minecraft.item.ItemStack; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3f; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.RenderHandEvent; import net.minecraftforge.client.event.RenderItemInFrameEvent; diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 54e8c80b9..847a45160 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -9,12 +9,12 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; -import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.RenderType; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.DrawHighlightEvent; @@ -61,7 +61,7 @@ public final class MonitorHighlightRenderer if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() ); MatrixStack transformStack = event.getMatrix(); - Vec3d cameraPos = event.getInfo().getProjectedView(); + Vector3d cameraPos = event.getInfo().getProjectedView(); transformStack.push(); transformStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() ); diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index 483957a31..a1e361b3b 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -12,8 +12,8 @@ import com.mojang.blaze3d.systems.RenderSystem; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.shared.util.Palette; -import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.texture.TextureUtil; +import net.minecraft.util.math.vector.Matrix4f; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 53f1c358e..3d48b2d80 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -10,11 +10,11 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.shared.util.Palette; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.RenderState; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.vector.Matrix4f; import org.lwjgl.opengl.GL11; import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 8f8530360..23edc49c7 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -17,13 +17,19 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.client.renderer.vertex.VertexBuffer; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.TransformationMatrix; +import net.minecraft.util.math.vector.Vector3f; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL20; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 91162280b..5c182b501 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -19,8 +19,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.renderer.Atlases; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ModelManager; @@ -31,7 +29,9 @@ import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3f; import net.minecraftforge.client.model.data.EmptyModelData; import javax.annotation.Nonnull; @@ -99,7 +99,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer transform.push(); // Setup the transform. - Vec3d offset = turtle.getRenderOffset( partialTicks ); + Vector3d offset = turtle.getRenderOffset( partialTicks ); float yaw = turtle.getRenderYaw( partialTicks ); transform.translate( offset.x, offset.y, offset.z ); diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index 41249f178..fd8a1a67a 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -57,16 +57,16 @@ public final class TurtleModelLoader implements IModelLoader getTextures( IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors ) + public Collection getTextures( IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors ) { - Set materials = new HashSet<>(); + Set materials = new HashSet<>(); materials.addAll( modelGetter.apply( family ).getTextures( modelGetter, missingTextureErrors ) ); materials.addAll( modelGetter.apply( COLOUR_TURTLE_MODEL ).getTextures( modelGetter, missingTextureErrors ) ); return materials; } @Override - public IBakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform transform, ItemOverrideList overrides, ResourceLocation modelLocation ) + public IBakedModel bake( IModelConfiguration owner, ModelBakery bakery, Function spriteGetter, IModelTransform transform, ItemOverrideList overrides, ResourceLocation modelLocation ) { return new TurtleSmartItemModel( bakery.getBakedModel( family, transform, spriteGetter ), diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 8f9a65cfd..256c53544 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -7,12 +7,12 @@ package dan200.computercraft.client.render; import dan200.computercraft.api.client.TransformedModel; import net.minecraft.block.BlockState; -import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ItemOverrideList; import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.TransformationMatrix; import net.minecraftforge.client.model.data.EmptyModelData; import net.minecraftforge.client.model.data.IModelData; import net.minecraftforge.client.model.pipeline.BakedQuadBuilder; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index f99b61264..3272b6f50 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -15,14 +15,14 @@ import dan200.computercraft.shared.util.Holiday; import dan200.computercraft.shared.util.HolidayUtil; import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.client.renderer.model.*; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; +import net.minecraft.util.math.vector.TransformationMatrix; import net.minecraftforge.client.model.data.IModelData; import javax.annotation.Nonnull; @@ -109,7 +109,7 @@ public class TurtleSmartItemModel implements IBakedModel { @Nonnull @Override - public IBakedModel getModelWithOverrides( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable LivingEntity entity ) + public IBakedModel func_239290_a_( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity ) { ItemTurtle turtle = (ItemTurtle) stack.getItem(); int colour = turtle.getColour( stack ); diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index fc909c683..6d923ef77 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -385,8 +385,8 @@ public class FSAPI implements ILuaAPI * * @param path The path to check the free space for. * @return The amount of free space available, in bytes. - * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". * @throws LuaException If the path doesn't exist. + * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". */ @LuaFunction public final Object getFreeSpace( String path ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 43a5c473f..d2e3cbb71 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -303,10 +303,10 @@ public class OSAPI implements ILuaAPI * always be in the range [0.0, 24.0). * * * If called with {@code ingame}, the current world time will be returned. - * This is the default if nothing is passed. + * This is the default if nothing is passed. * * If called with {@code utc}, returns the hour of the day in UTC time. * * If called with {@code local}, returns the hour of the day in the - * timezone the server is located in. + * timezone the server is located in. * * This function can also be called with a table returned from {@link #date}, * which will convert the date fields into a UNIX timestamp (number of @@ -314,9 +314,9 @@ public class OSAPI implements ILuaAPI * * @param args The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified. * @return The hour of the selected locale, or a UNIX timestamp from the table, depending on the argument passed in. + * @throws LuaException If an invalid locale is passed. * @cc.tparam [opt] string|table locale The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified. * @see #date To get a date table that can be converted with this function. - * @throws LuaException If an invalid locale is passed. */ @LuaFunction public final Object time( IArguments args ) throws LuaException @@ -342,11 +342,11 @@ public class OSAPI implements ILuaAPI * Returns the day depending on the locale specified. * * * If called with {@code ingame}, returns the number of days since the - * world was created. This is the default. + * world was created. This is the default. * * If called with {@code utc}, returns the number of days since 1 January - * 1970 in the UTC timezone. + * 1970 in the UTC timezone. * * If called with {@code local}, returns the number of days since 1 - * January 1970 in the server's local timezone. + * January 1970 in the server's local timezone. * * @param args The locale to get the day for. Defaults to {@code ingame} if not set. * @return The day depending on the selected locale. @@ -372,11 +372,11 @@ public class OSAPI implements ILuaAPI * Returns the number of seconds since an epoch depending on the locale. * * * If called with {@code ingame}, returns the number of seconds since the - * world was created. This is the default. + * world was created. This is the default. * * If called with {@code utc}, returns the number of seconds since 1 - * January 1970 in the UTC timezone. + * January 1970 in the UTC timezone. * * If called with {@code local}, returns the number of seconds since 1 - * January 1970 in the server's local timezone. + * January 1970 in the server's local timezone. * * @param args The locale to get the seconds for. Defaults to {@code ingame} if not set. * @return The seconds since the epoch depending on the selected locale. @@ -426,7 +426,7 @@ public class OSAPI implements ILuaAPI * timestamp (days since 1 January 1970) with {@link #date}. * * @param formatA The format of the string to return. This defaults to {@code %c}, which expands to a string similar to "Sat Dec 24 16:58:00 2011". - * @param timeA The time to convert to a string. This defaults to the current time. + * @param timeA The time to convert to a string. This defaults to the current time. * @return The resulting format string. * @throws LuaException If an invalid format is passed. */ diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java index 69ef83b78..6fb250c19 100644 --- a/src/main/java/dan200/computercraft/data/Generators.java +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -7,6 +7,7 @@ package dan200.computercraft.data; import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; +import net.minecraft.data.BlockTagsProvider; import net.minecraft.data.DataGenerator; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -23,6 +24,6 @@ public class Generators DataGenerator generator = event.getGenerator(); generator.addProvider( new Recipes( generator ) ); generator.addProvider( new LootTables( generator ) ); - generator.addProvider( new Tags( generator ) ); + generator.addProvider( new Tags( generator, new BlockTagsProvider( generator ) ) ); } } diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java index e24d07206..16be3be38 100644 --- a/src/main/java/dan200/computercraft/data/LootTableProvider.java +++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -13,11 +13,11 @@ import dan200.computercraft.ComputerCraft; import net.minecraft.data.DataGenerator; import net.minecraft.data.DirectoryCache; import net.minecraft.data.IDataProvider; +import net.minecraft.loot.LootParameterSets; +import net.minecraft.loot.LootTable; +import net.minecraft.loot.LootTableManager; +import net.minecraft.loot.ValidationTracker; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.storage.loot.LootParameterSets; -import net.minecraft.world.storage.loot.LootTable; -import net.minecraft.world.storage.loot.LootTableManager; -import net.minecraft.world.storage.loot.ValidationTracker; import javax.annotation.Nonnull; import java.io.IOException; diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index b85f0dea1..fbeee9e31 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -14,10 +14,10 @@ import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; import net.minecraft.block.Block; import net.minecraft.data.DataGenerator; +import net.minecraft.loot.*; +import net.minecraft.loot.conditions.Alternative; +import net.minecraft.loot.conditions.SurvivesExplosion; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.storage.loot.*; -import net.minecraft.world.storage.loot.conditions.Alternative; -import net.minecraft.world.storage.loot.conditions.SurvivesExplosion; import net.minecraftforge.fml.RegistryObject; import java.util.function.BiConsumer; @@ -77,9 +77,9 @@ public class LootTables extends LootTableProvider .rolls( ConstantRange.of( 1 ) ) .addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) ) .acceptCondition( Alternative.builder( - BlockNamedEntityLootCondition.builder(), - HasComputerIdLootCondition.builder(), - PlayerCreativeLootCondition.builder().inverted() + BlockNamedEntityLootCondition.BUILDER, + HasComputerIdLootCondition.BUILDER, + PlayerCreativeLootCondition.BUILDER.inverted() ) ) ).build() ); } diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java index a86ac212e..071de897b 100644 --- a/src/main/java/dan200/computercraft/data/Recipes.java +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -21,7 +21,7 @@ import net.minecraft.advancements.criterion.ItemPredicate; import net.minecraft.block.Blocks; import net.minecraft.data.*; import net.minecraft.item.*; -import net.minecraft.tags.Tag; +import net.minecraft.tags.ITag; import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.Tags; @@ -309,7 +309,7 @@ public class Recipes extends RecipeProvider return DyeColor.byId( 15 - colour.ordinal() ); } - private static InventoryChangeTrigger.Instance inventoryChange( Tag stack ) + private static InventoryChangeTrigger.Instance inventoryChange( ITag stack ) { return InventoryChangeTrigger.Instance.forItems( ItemPredicate.Builder.create().tag( stack ).build() ); } diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java index d822d6150..a8f981b2e 100644 --- a/src/main/java/dan200/computercraft/data/Tags.java +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -8,11 +8,12 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.Registry; +import net.minecraft.data.BlockTagsProvider; import net.minecraft.data.DataGenerator; import net.minecraft.data.ItemTagsProvider; import net.minecraft.item.Item; +import net.minecraft.tags.ITag; import net.minecraft.tags.ItemTags; -import net.minecraft.tags.Tag; import net.minecraft.util.ResourceLocation; import static dan200.computercraft.data.Tags.CCTags.*; @@ -21,33 +22,32 @@ public class Tags extends ItemTagsProvider { public static class CCTags { - public static final Tag COMPUTER = item( "computer" ); - public static final Tag TURTLE = item( "turtle" ); - public static final Tag WIRED_MODEM = item( "wired_modem" ); - public static final Tag MONITOR = item( "monitor" ); + public static final ITag.INamedTag COMPUTER = item( "computer" ); + public static final ITag.INamedTag TURTLE = item( "turtle" ); + public static final ITag.INamedTag WIRED_MODEM = item( "wired_modem" ); + public static final ITag.INamedTag MONITOR = item( "monitor" ); } - public Tags( DataGenerator generator ) + public Tags( DataGenerator generator, BlockTagsProvider tags ) { - super( generator ); + super( generator, tags ); } @Override protected void registerTags() { - getBuilder( COMPUTER ) - .add( Registry.ModItems.COMPUTER_NORMAL.get() ) - .add( Registry.ModItems.COMPUTER_ADVANCED.get() ) - .add( Registry.ModItems.COMPUTER_COMMAND.get() ); - getBuilder( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() ); - getBuilder( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() ); - getBuilder( MONITOR ) - .add( Registry.ModItems.MONITOR_NORMAL.get() ) - .add( Registry.ModItems.MONITOR_ADVANCED.get() ); + func_240522_a_( COMPUTER ).func_240534_a_( + Registry.ModItems.COMPUTER_NORMAL.get(), + Registry.ModItems.COMPUTER_ADVANCED.get(), + Registry.ModItems.COMPUTER_COMMAND.get() + ); + func_240522_a_( TURTLE ).func_240534_a_( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() ); + func_240522_a_( WIRED_MODEM ).func_240534_a_( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() ); + func_240522_a_( MONITOR ).func_240534_a_( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() ); } - private static Tag item( String name ) + private static ITag.INamedTag item( String name ) { - return new ItemTags.Wrapper( new ResourceLocation( ComputerCraft.MOD_ID, name ) ); + return ItemTags.makeWrapperTag( new ResourceLocation( ComputerCraft.MOD_ID, name ).toString() ); } } diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index fe8a2d448..903aa4c97 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -92,7 +92,7 @@ public final class Registry public static final class ModBlocks { - static final DeferredRegister BLOCKS = new DeferredRegister<>( ForgeRegistries.BLOCKS, ComputerCraft.MOD_ID ); + static final DeferredRegister BLOCKS = DeferredRegister.create( ForgeRegistries.BLOCKS, ComputerCraft.MOD_ID ); private static Block.Properties properties() { @@ -145,7 +145,7 @@ public final class Registry public static class ModTiles { - static final DeferredRegister> TILES = new DeferredRegister<>( ForgeRegistries.TILE_ENTITIES, ComputerCraft.MOD_ID ); + static final DeferredRegister> TILES = DeferredRegister.create( ForgeRegistries.TILE_ENTITIES, ComputerCraft.MOD_ID ); private static RegistryObject> ofBlock( RegistryObject block, Function, T> factory ) { @@ -183,7 +183,7 @@ public final class Registry public static final class ModItems { - static final DeferredRegister ITEMS = new DeferredRegister<>( ForgeRegistries.ITEMS, ComputerCraft.MOD_ID ); + static final DeferredRegister ITEMS = DeferredRegister.create( ForgeRegistries.ITEMS, ComputerCraft.MOD_ID ); private static Item.Properties properties() { @@ -281,7 +281,7 @@ public final class Registry public static class ModEntities { - static final DeferredRegister> ENTITIES = new DeferredRegister<>( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID ); + static final DeferredRegister> ENTITIES = DeferredRegister.create( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID ); public static final RegistryObject> TURTLE_PLAYER = ENTITIES.register( "turtle_player", () -> EntityType.Builder.create( EntityClassification.MISC ) @@ -293,7 +293,7 @@ public final class Registry public static class ModContainers { - static final DeferredRegister> CONTAINERS = new DeferredRegister<>( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID ); + static final DeferredRegister> CONTAINERS = DeferredRegister.create( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID ); public static final RegistryObject> COMPUTER = CONTAINERS.register( "computer", () -> ContainerData.toType( ComputerContainerData::new, ContainerComputer::new ) ); diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index 98c7eca75..57511d018 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -11,6 +11,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -20,13 +21,12 @@ public final class TurtlePermissions public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player ) { MinecraftServer server = world.getServer(); - return server == null || world.isRemote || !server.isBlockProtected( world, pos, player ); + return server == null || world.isRemote || (world instanceof ServerWorld && !server.isBlockProtected( (ServerWorld) world, pos, player )); } public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player ) { - MinecraftServer server = world.getServer(); - return server == null || world.isRemote || !server.isBlockProtected( world, pos, player ); + return isBlockEnterable( world, pos, player ); } @SubscribeEvent diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 876dcad5a..c8afb9c44 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -30,6 +30,7 @@ import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.network.play.server.SPlayerPositionLookPacket; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.IFormattableTextComponent; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; @@ -283,16 +284,16 @@ public final class CommandComputerCraft private static ITextComponent linkComputer( CommandSource source, ServerComputer serverComputer, int computerId ) { - ITextComponent out = new StringTextComponent( "" ); + IFormattableTextComponent out = new StringTextComponent( "" ); // Append the computer instance if( serverComputer == null ) { - out.appendSibling( text( "?" ) ); + out.func_230529_a_( text( "?" ) ); } else { - out.appendSibling( link( + out.func_230529_a_( link( text( Integer.toString( serverComputer.getInstanceID() ) ), "/computercraft dump " + serverComputer.getInstanceID(), translate( "commands.computercraft.dump.action" ) @@ -300,20 +301,20 @@ public final class CommandComputerCraft } // And ID - out.appendText( " (id " + computerId + ")" ); + out.func_240702_b_( " (id " + computerId + ")" ); // And, if we're a player, some useful links if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) ) { out - .appendText( " " ) - .appendSibling( link( + .func_240702_b_( " " ) + .func_230529_a_( link( text( "\u261b" ), "/computercraft tp " + serverComputer.getInstanceID(), translate( "commands.computercraft.tp.action" ) ) ) - .appendText( " " ) - .appendSibling( link( + .func_240702_b_( " " ) + .func_230529_a_( link( text( "\u20e2" ), "/computercraft view " + serverComputer.getInstanceID(), translate( "commands.computercraft.view.action" ) diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index a90713133..48ba35e6c 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -13,6 +13,7 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.tree.CommandNode; import com.mojang.brigadier.tree.LiteralCommandNode; import net.minecraft.command.CommandSource; +import net.minecraft.util.text.IFormattableTextComponent; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; @@ -173,12 +174,12 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder child : node.getChildren() ) { @@ -187,16 +188,16 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder T coloured( T component, TextFormatting colour ) + public static T coloured( T component, TextFormatting colour ) { - component.getStyle().setColor( colour ); + component.getStyle().setFormatting( colour ); return component; } - public static ITextComponent text( String text ) + public static IFormattableTextComponent text( String text ) { return new StringTextComponent( text == null ? "" : text ); } - public static ITextComponent translate( String text ) + public static IFormattableTextComponent translate( String text ) { return new TranslationTextComponent( text == null ? "" : text ); } - public static ITextComponent translate( String text, Object... args ) + public static IFormattableTextComponent translate( String text, Object... args ) { return new TranslationTextComponent( text == null ? "" : text, args ); } - public static ITextComponent list( ITextComponent... children ) + public static IFormattableTextComponent list( ITextComponent... children ) { - ITextComponent component = new StringTextComponent( "" ); + IFormattableTextComponent component = new StringTextComponent( "" ); for( ITextComponent child : children ) { - component.appendSibling( child ); + component.func_230529_a_( child ); } return component; } - public static ITextComponent position( BlockPos pos ) + public static IFormattableTextComponent position( BlockPos pos ) { if( pos == null ) return translate( "commands.computercraft.generic.no_position" ); return translate( "commands.computercraft.generic.position", pos.getX(), pos.getY(), pos.getZ() ); } - public static ITextComponent bool( boolean value ) + public static IFormattableTextComponent bool( boolean value ) { return value ? coloured( translate( "commands.computercraft.generic.yes" ), TextFormatting.GREEN ) : coloured( translate( "commands.computercraft.generic.no" ), TextFormatting.RED ); } - public static ITextComponent link( ITextComponent component, String command, ITextComponent toolTip ) + public static IFormattableTextComponent link( IFormattableTextComponent component, String command, ITextComponent toolTip ) { Style style = component.getStyle(); - if( style.getColor() == null ) style.setColor( TextFormatting.YELLOW ); + if( style.getColor() == null ) style.setFormatting( TextFormatting.YELLOW ); style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) ); style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) ); return component; } - public static ITextComponent header( String text ) + public static IFormattableTextComponent header( String text ) { return coloured( text, HEADER ); } diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index 683989cd6..7d001f20c 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -79,12 +79,12 @@ public interface TableFormatter StringTextComponent line = new StringTextComponent( "" ); for( int i = 0; i < columns - 1; i++ ) { - line.appendSibling( headers[i] ); + line.func_230529_a_( headers[i] ); ITextComponent padding = getPadding( headers[i], maxWidths[i] ); - if( padding != null ) line.appendSibling( padding ); - line.appendSibling( SEPARATOR ); + if( padding != null ) line.func_230529_a_( padding ); + line.func_230529_a_( SEPARATOR ); } - line.appendSibling( headers[columns - 1] ); + line.func_230529_a_( headers[columns - 1] ); writeLine( rowId++, line ); @@ -100,12 +100,12 @@ public interface TableFormatter StringTextComponent line = new StringTextComponent( "" ); for( int i = 0; i < columns - 1; i++ ) { - line.appendSibling( row[i] ); + line.func_230529_a_( row[i] ); ITextComponent padding = getPadding( row[i], maxWidths[i] ); - if( padding != null ) line.appendSibling( padding ); - line.appendSibling( SEPARATOR ); + if( padding != null ) line.func_230529_a_( padding ); + line.func_230529_a_( SEPARATOR ); } - line.appendSibling( row[columns - 1] ); + line.func_230529_a_( row[columns - 1] ); writeLine( rowId++, line ); } diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 5d391cf8a..3814a7f74 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -105,9 +105,9 @@ public abstract class TileGeneric extends TileEntity } @Override - public void handleUpdateTag( @Nonnull CompoundNBT tag ) + public void handleUpdateTag( @Nonnull BlockState state, @Nonnull CompoundNBT tag ) { - super.handleUpdateTag( tag ); + super.handleUpdateTag( state, tag ); readDescription( tag ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 0bf82c8e2..f990647c2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -16,6 +16,8 @@ import net.minecraft.block.BlockState; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameters; import net.minecraft.stats.Stats; import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; @@ -26,8 +28,6 @@ import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.storage.loot.LootContext; -import net.minecraft.world.storage.loot.LootParameters; import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 20d542463..ed55abf4b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -14,8 +14,8 @@ import net.minecraft.command.ICommandSource; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.math.Vec2f; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector2f; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; @@ -25,6 +25,7 @@ import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; +import java.util.UUID; public class TileCommandComputer extends TileComputer { @@ -48,7 +49,7 @@ public class TileCommandComputer extends TileComputer } @Override - public void sendMessage( @Nonnull ITextComponent textComponent ) + public void sendMessage( @Nonnull ITextComponent textComponent, @Nonnull UUID id ) { output.put( output.size() + 1, textComponent.getString() ); } @@ -96,7 +97,7 @@ public class TileCommandComputer extends TileComputer } return new CommandSource( receiver, - new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ), Vec2f.ZERO, + new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ), Vector2f.ZERO, (ServerWorld) getWorld(), 2, name, new StringTextComponent( name ), getWorld().getServer(), null diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index b384810b9..c77012bbc 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -189,9 +189,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } @Override - public void read( @Nonnull CompoundNBT nbt ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( nbt ); + super.read( state, nbt ); // Load ID, label and power state m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java index 82f603306..1d4699a7c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java @@ -24,7 +24,7 @@ public enum ComputerState implements IStringSerializable @Nonnull @Override - public String getName() + public String getString() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 3ac904dc8..04d61c252 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -43,7 +43,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte if( id >= 0 ) { list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id ) - .applyTextStyle( TextFormatting.GRAY ) ); + .func_240699_a_( TextFormatting.GRAY ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index 898c321ce..e08f5825d 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -5,12 +5,13 @@ */ package dan200.computercraft.shared.data; +import net.minecraft.loot.LootConditionType; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameter; +import net.minecraft.loot.LootParameters; +import net.minecraft.loot.conditions.ILootCondition; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.INameable; -import net.minecraft.world.storage.loot.LootContext; -import net.minecraft.world.storage.loot.LootParameter; -import net.minecraft.world.storage.loot.LootParameters; -import net.minecraft.world.storage.loot.conditions.ILootCondition; import javax.annotation.Nonnull; import java.util.Collections; @@ -22,6 +23,8 @@ import java.util.Set; public final class BlockNamedEntityLootCondition implements ILootCondition { public static final BlockNamedEntityLootCondition INSTANCE = new BlockNamedEntityLootCondition(); + public static final LootConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); + public static final IBuilder BUILDER = () -> INSTANCE; private BlockNamedEntityLootCondition() { @@ -41,8 +44,10 @@ public final class BlockNamedEntityLootCondition implements ILootCondition return Collections.singleton( LootParameters.BLOCK_ENTITY ); } - public static IBuilder builder() + @Override + @Nonnull + public LootConditionType func_230419_b_() { - return () -> INSTANCE; + return TYPE; } } diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java index 07ac6a830..87182f010 100644 --- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -8,34 +8,34 @@ package dan200.computercraft.shared.data; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; -import net.minecraft.util.ResourceLocation; -import net.minecraft.world.storage.loot.conditions.ILootCondition; +import net.minecraft.loot.ILootSerializer; +import net.minecraft.loot.LootConditionType; +import net.minecraft.loot.conditions.ILootCondition; import javax.annotation.Nonnull; -public final class ConstantLootConditionSerializer extends ILootCondition.AbstractSerializer +public final class ConstantLootConditionSerializer implements ILootSerializer { private final T instance; - private ConstantLootConditionSerializer( ResourceLocation id, Class klass, T instance ) + public ConstantLootConditionSerializer( T instance ) { - super( id, klass ); this.instance = instance; } - public static ILootCondition.AbstractSerializer of( ResourceLocation id, Class klass, T instance ) + public static LootConditionType type( T condition ) { - return new ConstantLootConditionSerializer<>( id, klass, instance ); + return new LootConditionType( new ConstantLootConditionSerializer<>( condition ) ); } @Override - public void serialize( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context ) + public void func_230424_a_( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context ) { } @Nonnull @Override - public T deserialize( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context ) + public T func_230423_a_( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context ) { return instance; } diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java index 4da10a15c..57837e2b0 100644 --- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java @@ -6,11 +6,12 @@ package dan200.computercraft.shared.data; import dan200.computercraft.shared.computer.blocks.IComputerTile; +import net.minecraft.loot.LootConditionType; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameter; +import net.minecraft.loot.LootParameters; +import net.minecraft.loot.conditions.ILootCondition; import net.minecraft.tileentity.TileEntity; -import net.minecraft.world.storage.loot.LootContext; -import net.minecraft.world.storage.loot.LootParameter; -import net.minecraft.world.storage.loot.LootParameters; -import net.minecraft.world.storage.loot.conditions.ILootCondition; import javax.annotation.Nonnull; import java.util.Collections; @@ -22,6 +23,8 @@ import java.util.Set; public final class HasComputerIdLootCondition implements ILootCondition { public static final HasComputerIdLootCondition INSTANCE = new HasComputerIdLootCondition(); + public static final LootConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); + public static final IBuilder BUILDER = () -> INSTANCE; private HasComputerIdLootCondition() { @@ -41,8 +44,10 @@ public final class HasComputerIdLootCondition implements ILootCondition return Collections.singleton( LootParameters.BLOCK_ENTITY ); } - public static IBuilder builder() + @Override + @Nonnull + public LootConditionType func_230419_b_() { - return () -> INSTANCE; + return TYPE; } } diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 6a91f90fe..10f4ca56a 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -7,10 +7,11 @@ package dan200.computercraft.shared.data; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.world.storage.loot.LootContext; -import net.minecraft.world.storage.loot.LootParameter; -import net.minecraft.world.storage.loot.LootParameters; -import net.minecraft.world.storage.loot.conditions.ILootCondition; +import net.minecraft.loot.LootConditionType; +import net.minecraft.loot.LootContext; +import net.minecraft.loot.LootParameter; +import net.minecraft.loot.LootParameters; +import net.minecraft.loot.conditions.ILootCondition; import javax.annotation.Nonnull; import java.util.Collections; @@ -22,6 +23,8 @@ import java.util.Set; public final class PlayerCreativeLootCondition implements ILootCondition { public static final PlayerCreativeLootCondition INSTANCE = new PlayerCreativeLootCondition(); + public static final LootConditionType TYPE = ConstantLootConditionSerializer.type( INSTANCE ); + public static final IBuilder BUILDER = () -> INSTANCE; private PlayerCreativeLootCondition() { @@ -41,8 +44,10 @@ public final class PlayerCreativeLootCondition implements ILootCondition return Collections.singleton( LootParameters.THIS_ENTITY ); } - public static IBuilder builder() + @Override + @Nonnull + public LootConditionType func_230419_b_() { - return () -> INSTANCE; + return TYPE; } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 6ef877402..017781cba 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -69,7 +69,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem if( id >= 0 ) { list.add( new TranslationTextComponent( "gui.computercraft.tooltip.disk_id", id ) - .applyTextStyle( TextFormatting.GRAY ) ); + .func_240699_a_( TextFormatting.GRAY ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index 0e5f81ab5..4ad832519 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -19,14 +19,14 @@ import net.minecraft.item.crafting.SpecialRecipe; import net.minecraft.item.crafting.SpecialRecipeSerializer; import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; -import net.minecraftforge.common.Tags; import javax.annotation.Nonnull; public class DiskRecipe extends SpecialRecipe { private final Ingredient paper = Ingredient.fromItems( Items.PAPER ); - private final Ingredient redstone = Ingredient.fromTag( Tags.Items.DUSTS_REDSTONE ); + private final Ingredient redstone = Ingredient.fromItems( Items.REDSTONE ); + // TODO: Ingredient.fromTag( Tags.Items.DUSTS_REDSTONE ); public DiskRecipe( ResourceLocation id ) { diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 5b905a76b..ca391be00 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -13,7 +13,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraftforge.fml.network.NetworkDirection; @@ -76,9 +76,9 @@ public final class NetworkHandler network.sendToServer( packet ); } - public static void sendToAllAround( NetworkMessage packet, World world, Vec3d pos, double range ) + public static void sendToAllAround( NetworkMessage packet, World world, Vector3d pos, double range ) { - PacketDistributor.TargetPoint target = new PacketDistributor.TargetPoint( pos.x, pos.y, pos.z, range, world.getDimension().getType() ); + PacketDistributor.TargetPoint target = new PacketDistributor.TargetPoint( pos.x, pos.y, pos.z, range, world.func_234923_W_() ); network.send( PacketDistributor.NEAR.with( () -> target ), packet ); } diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 9ba8d2021..fef9f5c11 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -10,6 +10,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.network.PacketBuffer; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkEvent; @@ -81,7 +82,7 @@ public class PlayRecordClientMessage implements NetworkMessage public void handle( NetworkEvent.Context context ) { Minecraft mc = Minecraft.getInstance(); - mc.worldRenderer.playRecord( soundEvent, pos ); - if( name != null ) mc.ingameGUI.setRecordPlayingMessage( name ); + mc.worldRenderer.playRecord( soundEvent, pos, null ); + if( name != null ) mc.ingameGUI.func_238451_a_( new StringTextComponent( name ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java index 17faae369..2d0a2d810 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java @@ -24,7 +24,7 @@ public enum DiskDriveState implements IStringSerializable @Override @Nonnull - public String getName() + public String getString() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 8e53b02b4..0ade6c201 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -122,10 +122,10 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory } @Override - public void read( @Nonnull CompoundNBT nbt ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( nbt ); - customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; + super.read( state, nbt ); + customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.func_240643_a_( nbt.getString( NBT_NAME ) ) : null; if( nbt.contains( NBT_ITEM ) ) { CompoundNBT item = nbt.getCompound( NBT_ITEM ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java index 13d516c8f..9a6fbdab3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.common.collect.ImmutableMap; import net.minecraft.block.BlockState; -import net.minecraft.state.IProperty; +import net.minecraft.state.Property; import javax.annotation.Nonnull; import java.util.HashMap; @@ -22,9 +22,9 @@ public class BlockData data.put( "name", DataHelpers.getId( state.getBlock() ) ); Map stateTable = new HashMap<>(); - for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) + for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() ) { - IProperty property = entry.getKey(); + Property property = entry.getKey(); stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) ); } data.put( "state", stateTable ); @@ -34,7 +34,7 @@ public class BlockData } @SuppressWarnings( { "unchecked", "rawtypes" } ) - private static Object getPropertyValue( IProperty property, Comparable value ) + private static Object getPropertyValue( Property property, Comparable value ) { if( value instanceof String || value instanceof Number || value instanceof Boolean ) return value; return property.getName( value ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 1a422487e..c20a91c85 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -93,7 +93,7 @@ public class ItemData { try { - return ITextComponent.Serializer.fromJson( x.getString() ); + return ITextComponent.Serializer.func_240643_a_( x.getString() ); } catch( JsonParseException e ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 0805406a9..15527e062 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -13,7 +13,7 @@ import dan200.computercraft.api.network.IPacketSender; import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -171,7 +171,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa parseChannel( replyChannel ); World world = getWorld(); - Vec3d position = getPosition(); + Vector3d position = getPosition(); IPacketNetwork network = m_network; if( world == null || position == null || network == null ) return; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 3bdbfee7a..a9c5ea36e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -15,7 +15,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.IWaterLoggable; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.IFluidState; +import net.minecraft.fluid.FluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.BooleanProperty; @@ -100,7 +100,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable } @Override - public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid ) + public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, FluidState fluid ) { if( state.get( CABLE ) && state.get( MODEM ).getFacing() != null ) { @@ -180,7 +180,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public IFluidState getFluidState( @Nonnull BlockState state ) + public FluidState getFluidState( @Nonnull BlockState state ) { return getWaterloggedFluidState( state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index 22d4b5ead..ed422b477 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -65,7 +65,7 @@ public enum CableModemVariant implements IStringSerializable @Nonnull @Override - public String getName() + public String getString() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 7d548ec5a..a5a506402 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -28,7 +28,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; @@ -58,10 +58,10 @@ public class TileCable extends TileGeneric @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = getPos(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Override @@ -103,10 +103,10 @@ public class TileCable extends TileGeneric @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = getPos().offset( modemDirection ); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Nonnull @@ -281,9 +281,9 @@ public class TileCable extends TileGeneric } @Override - public void read( @Nonnull CompoundNBT nbt ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( nbt ); + super.read( state, nbt ); m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); m_peripheral.read( nbt, "" ); } @@ -422,12 +422,6 @@ public class TileCable extends TileGeneric m_node.updatePeripherals( peripherals ); } - @Override - public boolean canRenderBreaking() - { - return true; - } - @Nonnull @Override public LazyOptional getCapability( @Nonnull Capability capability, @Nullable Direction side ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 349cb6d28..459aa7277 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -26,7 +26,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; @@ -85,10 +85,10 @@ public class TileWiredModemFull extends TileGeneric @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = m_entity.getPos(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } } @@ -217,17 +217,17 @@ public class TileWiredModemFull extends TileGeneric StringTextComponent base = new StringTextComponent( "" ); for( int i = 0; i < names.size(); i++ ) { - if( i > 0 ) base.appendText( ", " ); - base.appendSibling( CommandCopy.createCopyText( names.get( i ) ) ); + if( i > 0 ) base.func_240702_b_( ", " ); + base.func_230529_a_( CommandCopy.createCopyText( names.get( i ) ) ); } player.sendStatusMessage( new TranslationTextComponent( kind, base ), false ); } @Override - public void read( @Nonnull CompoundNBT nbt ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( nbt ); + super.read( state, nbt ); m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].read( nbt, Integer.toString( i ) ); } @@ -399,10 +399,10 @@ public class TileWiredModemFull extends TileGeneric @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = getPos().offset( side ); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index f95066025..9c26780d3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -10,7 +10,7 @@ import dan200.computercraft.shared.peripheral.modem.ModemShapes; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.IWaterLoggable; -import net.minecraft.fluid.IFluidState; +import net.minecraft.fluid.FluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.state.BooleanProperty; import net.minecraft.state.DirectionProperty; @@ -62,7 +62,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable @Nonnull @Override @Deprecated - public IFluidState getFluidState( @Nonnull BlockState state ) + public FluidState getFluidState( @Nonnull BlockState state ) { return getWaterloggedFluidState( state ); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index d13915afc..0ed6921c7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -15,7 +15,7 @@ import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -46,10 +46,10 @@ public class TileWirelessModem extends TileGeneric @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = entity.getPos().offset( entity.modemDirection ); - return new Vec3d( pos.getX(), pos.getY(), pos.getZ() ); + return new Vector3d( pos.getX(), pos.getY(), pos.getZ() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index 68d77d366..6f8295f7d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -9,7 +9,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.network.IPacketNetwork; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; public abstract class WirelessModemPeripheral extends ModemPeripheral @@ -40,7 +40,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral World world = getWorld(); if( world != null ) { - Vec3d position = getPosition(); + Vector3d position = getPosition(); double minRange = ComputerCraft.modemRange; double maxRange = ComputerCraft.modemHighAltitudeRange; if( world.isRaining() && world.isThundering() ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java index 0ada54c82..cfc3a46e9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -59,7 +59,7 @@ public enum MonitorEdgeState implements IStringSerializable @Nonnull @Override - public String getName() + public String getString() { return name; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 129f5f783..c9521f754 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -14,6 +14,7 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.TickScheduler; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -134,13 +135,14 @@ public class TileMonitor extends TileGeneric } @Override - public void read( @Nonnull CompoundNBT tag ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( tag ); - m_xIndex = tag.getInt( NBT_X ); - m_yIndex = tag.getInt( NBT_Y ); - m_width = tag.getInt( NBT_WIDTH ); - m_height = tag.getInt( NBT_HEIGHT ); + super.read( state, nbt ); + + m_xIndex = nbt.getInt( NBT_X ); + m_yIndex = nbt.getInt( NBT_Y ); + m_width = nbt.getInt( NBT_WIDTH ); + m_height = nbt.getInt( NBT_HEIGHT ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index 6e7da2aad..7c6543b14 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -46,8 +46,8 @@ public class PrinterPeripheral implements IPeripheral * Writes text to the current page. * * @param arguments The values to write to the page. - * @cc.tparam string|number ... The values to write to the page. * @throws LuaException If any values couldn't be converted to a string, or if no page is started. + * @cc.tparam string|number ... The values to write to the page. */ @LuaFunction public final void write( IArguments arguments ) throws LuaException @@ -62,9 +62,9 @@ public class PrinterPeripheral implements IPeripheral * Returns the current position of the cursor on the page. * * @return The position of the cursor. + * @throws LuaException If a page isn't being printed. * @cc.treturn number The X position of the cursor. * @cc.treturn number The Y position of the cursor. - * @throws LuaException If a page isn't being printed. */ @LuaFunction public final Object[] getCursorPos() throws LuaException @@ -93,9 +93,9 @@ public class PrinterPeripheral implements IPeripheral * Returns the size of the current page. * * @return The size of the page. + * @throws LuaException If a page isn't being printed. * @cc.treturn number The width of the page. * @cc.treturn number The height of the page. - * @throws LuaException If a page isn't being printed. */ @LuaFunction public final Object[] getPageSize() throws LuaException diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index ac560c8b4..fc44c7dac 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -22,7 +22,7 @@ import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.*; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraftforge.common.capabilities.Capability; @@ -91,11 +91,11 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } @Override - public void read( @Nonnull CompoundNBT nbt ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( nbt ); + super.read( state, nbt ); - customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; + customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.func_240643_a_( nbt.getString( NBT_NAME ) ) : null; // Read page synchronized( m_page ) @@ -403,7 +403,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent setInventorySlotContents( i, ItemStack.EMPTY ); // Spawn the item in the world - WorldUtil.dropItemStack( stack, getWorld(), new Vec3d( getPos() ).add( 0.5, 0.75, 0.5 ) ); + WorldUtil.dropItemStack( stack, getWorld(), Vector3d.func_237491_b_( getPos() ).add( 0.5, 0.75, 0.5 ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 217b5b59f..2e6202ac6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -16,7 +16,7 @@ import net.minecraft.state.properties.NoteBlockInstrument; import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocationException; import net.minecraft.util.SoundCategory; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -44,7 +44,7 @@ public abstract class SpeakerPeripheral implements IPeripheral public abstract World getWorld(); - public abstract Vec3d getPosition(); + public abstract Vector3d getPosition(); public boolean madeSound( long ticks ) { @@ -66,9 +66,9 @@ public abstract class SpeakerPeripheral implements IPeripheral * with an optional volume and speed multiplier, and plays it through the speaker. * * @param context The Lua context - * @param name The name of the sound to play. + * @param name The name of the sound to play. * @param volumeA The volume to play the sound at, from 0.0 to 3.0. Defaults to 1.0. - * @param pitchA The speed to play the sound at, from 0.5 to 2.0. Defaults to 1.0. + * @param pitchA The speed to play the sound at, from 0.5 to 2.0. Defaults to 1.0. * @return Whether the sound could be played. * @throws LuaException If the sound name couldn't be decoded. */ @@ -102,9 +102,9 @@ public abstract class SpeakerPeripheral implements IPeripheral * and 6 and 18 map to C. * * @param context The Lua context - * @param name The name of the note to play. + * @param name The name of the note to play. * @param volumeA The volume to play the note at, from 0.0 to 3.0. Defaults to 1.0. - * @param pitchA The pitch to play the note at in semitones, from 0 to 24. Defaults to 12. + * @param pitchA The pitch to play the note at in semitones, from 0 to 24. Defaults to 12. * @return Whether the note could be played. * @throws LuaException If the instrument doesn't exist. */ @@ -117,7 +117,7 @@ public abstract class SpeakerPeripheral implements IPeripheral NoteBlockInstrument instrument = null; for( NoteBlockInstrument testInstrument : NoteBlockInstrument.values() ) { - if( testInstrument.getName().equalsIgnoreCase( name ) ) + if( testInstrument.getString().equalsIgnoreCase( name ) ) { instrument = testInstrument; break; @@ -144,7 +144,7 @@ public abstract class SpeakerPeripheral implements IPeripheral } World world = getWorld(); - Vec3d pos = getPosition(); + Vector3d pos = getPosition(); context.issueMainThreadTask( () -> { MinecraftServer server = world.getServer(); @@ -152,7 +152,7 @@ public abstract class SpeakerPeripheral implements IPeripheral float adjVolume = Math.min( volume, 3.0f ); server.getPlayerList().sendToAllNearExcept( - null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.dimension.getType(), + null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.func_234923_W_(), new SPlaySoundPacket( name, SoundCategory.RECORDS, pos, adjVolume, pitch ) ); return null; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 793ef4aad..79f2d7162 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -12,7 +12,7 @@ import net.minecraft.tileentity.ITickableTileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -77,10 +77,10 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity } @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = speaker.getPos(); - return new Vec3d( pos.getX(), pos.getY(), pos.getZ() ); + return new Vector3d( pos.getX(), pos.getY(), pos.getZ() ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index e165daf95..fdc21e23f 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -163,7 +163,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces if( entity != null ) { setWorld( entity.getEntityWorld() ); - setPosition( entity.getPosition() ); + setPosition( entity.func_233580_cy_() ); } // If a new entity has picked it up then rebroadcast the terminal to them diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index a6258216a..2c4979270 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -27,12 +27,14 @@ import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.IInventory; -import net.minecraft.item.IItemPropertyGetter; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.util.*; +import net.minecraft.util.ActionResult; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Hand; +import net.minecraft.util.NonNullList; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; @@ -60,8 +62,6 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I { super( settings ); this.family = family; - addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "state" ), COMPUTER_STATE ); - addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "coloured" ), COMPUTER_COLOURED ); } public ItemStack create( int id, String label, int colour, IPocketUpgrade upgrade ) @@ -190,7 +190,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I if( id >= 0 ) { list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id ) - .applyTextStyle( TextFormatting.GRAY ) ); + .func_240699_a_( TextFormatting.GRAY ) ); } } } @@ -408,7 +408,4 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I { return stack.getOrCreateChildTag( NBT_UPGRADE_INFO ); } - - private static final IItemPropertyGetter COMPUTER_STATE = ( stack, world, player ) -> getState( stack ).ordinal(); - private static final IItemPropertyGetter COMPUTER_COLOURED = ( stack, world, player ) -> IColouredItem.getColourBasic( stack ) != -1 ? 1 : 0; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index 12e98c000..ceecca676 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -16,14 +16,14 @@ import javax.annotation.Nonnull; public class PocketModemPeripheral extends WirelessModemPeripheral { private World world = null; - private Vec3d position = Vec3d.ZERO; + private Vector3d position = Vector3d.ZERO; public PocketModemPeripheral( boolean advanced ) { super( new ModemState(), advanced ); } - void setLocation( World world, Vec3d position ) + void setLocation( World world, Vector3d position ) { this.position = position; this.world = world; @@ -38,7 +38,7 @@ public class PocketModemPeripheral extends WirelessModemPeripheral @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { return position; } diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java index 66182ff4d..cbd88aa3a 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java @@ -7,15 +7,15 @@ package dan200.computercraft.shared.pocket.peripherals; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; public class PocketSpeakerPeripheral extends SpeakerPeripheral { private World world = null; - private Vec3d position = Vec3d.ZERO; + private Vector3d position = Vector3d.ZERO; - void setLocation( World world, Vec3d position ) + void setLocation( World world, Vector3d position ) { this.position = position; this.world = world; @@ -28,7 +28,7 @@ public class PocketSpeakerPeripheral extends SpeakerPeripheral } @Override - public Vec3d getPosition() + public Vector3d getPosition() { return world != null ? position : null; } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index d4b962cb3..5cf2699c3 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -19,7 +19,6 @@ import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; -import dan200.computercraft.shared.data.ConstantLootConditionSerializer; import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.media.items.RecordMedia; @@ -29,12 +28,9 @@ import dan200.computercraft.shared.util.NullStorage; import net.minecraft.inventory.container.Container; import net.minecraft.item.Item; import net.minecraft.item.MusicDiscItem; +import net.minecraft.loot.*; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.storage.loot.ConstantRange; -import net.minecraft.world.storage.loot.LootPool; -import net.minecraft.world.storage.loot.LootTables; -import net.minecraft.world.storage.loot.TableLootEntry; -import net.minecraft.world.storage.loot.conditions.LootConditionManager; +import net.minecraft.util.registry.Registry; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.event.LootTableLoadEvent; import net.minecraftforge.event.TickEvent; @@ -68,23 +64,14 @@ public final class ComputerCraftProxyCommon public static void registerLoot() { - LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( - new ResourceLocation( ComputerCraft.MOD_ID, "block_named" ), - BlockNamedEntityLootCondition.class, - BlockNamedEntityLootCondition.INSTANCE - ) ); + registerCondition( "block_named", BlockNamedEntityLootCondition.TYPE ); + registerCondition( "player_creative", PlayerCreativeLootCondition.TYPE ); + registerCondition( "has_id", HasComputerIdLootCondition.TYPE ); + } - LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( - new ResourceLocation( ComputerCraft.MOD_ID, "player_creative" ), - PlayerCreativeLootCondition.class, - PlayerCreativeLootCondition.INSTANCE - ) ); - - LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( - new ResourceLocation( ComputerCraft.MOD_ID, "has_id" ), - HasComputerIdLootCondition.class, - HasComputerIdLootCondition.INSTANCE - ) ); + private static void registerCondition( String name, LootConditionType serializer ) + { + Registry.register( Registry.field_239704_ba_, new ResourceLocation( ComputerCraft.MOD_ID, name ), serializer ); } private static void registerProviders() diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 6c1eb4871..9ccce8beb 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -20,7 +20,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.DamagingProjectileEntity; -import net.minecraft.fluid.IFluidState; +import net.minecraft.fluid.FluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemStack; import net.minecraft.state.DirectionProperty; @@ -31,11 +31,14 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.ISelectionContext; import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; -import net.minecraft.world.*; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.Explosion; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; import net.minecraftforge.fml.RegistryObject; import javax.annotation.Nonnull; @@ -82,8 +85,8 @@ public class BlockTurtle extends BlockComputerBase implements IWater public VoxelShape getShape( @Nonnull BlockState state, IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context ) { TileEntity tile = world.getTileEntity( pos ); - Vec3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3d.ZERO; - return offset.equals( Vec3d.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.withOffset( offset.x, offset.y, offset.z ); + Vector3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vector3d.ZERO; + return offset.equals( Vector3d.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.withOffset( offset.x, offset.y, offset.z ); } @Nullable @@ -98,7 +101,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater @Nonnull @Override @Deprecated - public IFluidState getFluidState( @Nonnull BlockState state ) + public FluidState getFluidState( @Nonnull BlockState state ) { return getWaterloggedFluidState( state ); } @@ -151,14 +154,15 @@ public class BlockTurtle extends BlockComputerBase implements IWater } @Override - public float getExplosionResistance( BlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion ) + public float getExplosionResistance( BlockState state, IBlockReader world, BlockPos pos, Explosion explosion ) { + Entity exploder = explosion.getExploder(); if( getFamily() == ComputerFamily.ADVANCED || exploder instanceof LivingEntity || exploder instanceof DamagingProjectileEntity ) { return 2000; } - return super.getExplosionResistance( state, world, pos, exploder, explosion ); + return super.getExplosionResistance( state, world, pos, explosion ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java index 541186682..505a25e78 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java @@ -10,7 +10,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.blocks.IComputerTile; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; public interface ITurtleTile extends IComputerTile { @@ -22,7 +22,7 @@ public interface ITurtleTile extends IComputerTile ITurtleAccess getAccess(); - Vec3d getRenderOffset( float f ); + Vector3d getRenderOffset( float f ); float getRenderYaw( float f ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 2d52d0ef9..939c4007e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -23,6 +23,7 @@ import dan200.computercraft.shared.turtle.apis.TurtleAPI; import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.inventory.ContainerTurtle; import dan200.computercraft.shared.util.*; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; @@ -36,7 +37,7 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.LazyOptional; @@ -256,9 +257,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - public void read( @Nonnull CompoundNBT nbt ) + public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt ) { - super.read( nbt ); + super.read( state, nbt ); // Read inventory ListNBT nbttaglist = nbt.getList( "Items", Constants.NBT.TAG_COMPOUND ); @@ -353,7 +354,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - public Vec3d getRenderOffset( float f ) + public Vector3d getRenderOffset( float f ) { return m_brain.getRenderOffset( f ); } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 31b363aa3..52f9f666a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -26,7 +26,7 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.MoverType; -import net.minecraft.fluid.IFluidState; +import net.minecraft.fluid.FluidState; import net.minecraft.inventory.IInventory; import net.minecraft.item.DyeColor; import net.minecraft.nbt.CompoundNBT; @@ -38,7 +38,7 @@ import net.minecraft.util.EntityPredicates; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; import net.minecraftforge.items.IItemHandlerModifiable; @@ -304,7 +304,7 @@ public class TurtleBrain implements ITurtleAccess // Ensure we're inside the world border if( !world.getWorldBorder().contains( pos ) ) return false; - IFluidState existingFluid = world.getBlockState( pos ).getFluidState(); + FluidState existingFluid = world.getBlockState( pos ).getFluidState(); BlockState newState = oldBlock // We only mark this as waterlogged when travelling into a source block. This prevents us from spreading // fluid by creating a new source when moving into a block, causing the next block to be almost full and @@ -357,11 +357,11 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public Vec3d getVisualPosition( float f ) + public Vector3d getVisualPosition( float f ) { - Vec3d offset = getRenderOffset( f ); + Vector3d offset = getRenderOffset( f ); BlockPos pos = m_owner.getPos(); - return new Vec3d( + return new Vector3d( pos.getX() + 0.5 + offset.x, pos.getY() + 0.5 + offset.y, pos.getZ() + 0.5 + offset.z @@ -659,7 +659,7 @@ public class TurtleBrain implements ITurtleAccess m_owner.updateBlock(); } - public Vec3d getRenderOffset( float f ) + public Vector3d getRenderOffset( float f ) { switch( m_animation ) { @@ -688,7 +688,7 @@ public class TurtleBrain implements ITurtleAccess } double distance = -1.0 + getAnimationFraction( f ); - return new Vec3d( + return new Vector3d( distance * dir.getXOffset(), distance * dir.getYOffset(), distance * dir.getZOffset() @@ -696,7 +696,7 @@ public class TurtleBrain implements ITurtleAccess } default: { - return Vec3d.ZERO; + return Vector3d.ZERO; } } } @@ -880,7 +880,7 @@ public class TurtleBrain implements ITurtleAccess double pushStepZ = moveDir.getZOffset() * pushStep; for( Entity entity : list ) { - entity.move( MoverType.PISTON, new Vec3d( pushStepX, pushStepY, pushStepZ ) ); + entity.move( MoverType.PISTON, new Vector3d( pushStepX, pushStepY, pushStepZ ) ); } } } @@ -893,7 +893,7 @@ public class TurtleBrain implements ITurtleAccess Holiday currentHoliday = HolidayUtil.getCurrentHoliday(); if( currentHoliday == Holiday.VALENTINES ) { - Vec3d position = getVisualPosition( 1.0f ); + Vector3d position = getVisualPosition( 1.0f ); if( position != null ) { double x = position.x + world.rand.nextGaussian() * 0.1; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 84dc412fb..69b903cba 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -28,7 +28,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.World; import net.minecraftforge.common.ForgeHooks; @@ -210,9 +210,9 @@ public class TurtlePlaceCommand implements ITurtleCommand // See if there is an entity present final World world = turtle.getWorld(); final BlockPos position = turtle.getPosition(); - Vec3d turtlePos = turtlePlayer.getPositionVec(); - Vec3d rayDir = turtlePlayer.getLook( 1.0f ); - Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); + Vector3d turtlePos = turtlePlayer.getPositionVec(); + Vector3d rayDir = turtlePlayer.getLook( 1.0f ); + Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); if( hit == null ) { return stack; @@ -224,7 +224,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // Start claiming entity drops Entity hitEntity = hit.getKey(); - Vec3d hitPos = hit.getValue(); + Vector3d hitPos = hit.getValue(); DropConsumer.set( hitEntity, drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ) @@ -252,13 +252,13 @@ public class TurtlePlaceCommand implements ITurtleCommand } else if( cancelResult == null ) { - if( hitEntity.processInitialInteract( turtlePlayer, Hand.MAIN_HAND ) ) + if( hitEntity.processInitialInteract( turtlePlayer, Hand.MAIN_HAND ) == ActionResultType.CONSUME ) { placed = true; } else if( hitEntity instanceof LivingEntity ) { - placed = stackCopy.interactWithEntity( turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND ); + placed = stackCopy.interactWithEntity( turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND ).isSuccessOrConsume(); if( placed ) turtlePlayer.loadInventory( stackCopy ); } } @@ -338,7 +338,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } // Check if there's something suitable to place onto - BlockRayTraceResult hit = new BlockRayTraceResult( new Vec3d( hitX, hitY, hitZ ), side, position, false ); + BlockRayTraceResult hit = new BlockRayTraceResult( new Vector3d( hitX, hitY, hitZ ), side, position, false ); ItemUseContext context = new ItemUseContext( turtlePlayer, Hand.MAIN_HAND, hit ); if( !canDeployOnBlock( new BlockItemUseContext( context ), turtle, turtlePlayer, position, side, allowReplace, outErrorMessage ) ) { @@ -405,22 +405,22 @@ public class TurtlePlaceCommand implements ITurtleCommand String s = (String) extraArguments[0]; String[] split = s.split( "\n" ); int firstLine = split.length <= 2 ? 1 : 0; - for( int i = 0; i < signTile.signText.length; i++ ) + for( int i = 0; i < 4; i++ ) { if( i >= firstLine && i < firstLine + split.length ) { if( split[i - firstLine].length() > 15 ) { - signTile.signText[i] = new StringTextComponent( split[i - firstLine].substring( 0, 15 ) ); + signTile.setText( i, new StringTextComponent( split[i - firstLine].substring( 0, 15 ) ) ); } else { - signTile.signText[i] = new StringTextComponent( split[i - firstLine] ); + signTile.setText( i, new StringTextComponent( split[i - firstLine] ) ); } } else { - signTile.signText[i] = new StringTextComponent( "" ); + signTile.setText( i, new StringTextComponent( "" ) ); } } signTile.markDirty(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index a9480bc40..691079d1e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -25,7 +25,6 @@ import net.minecraft.tileentity.SignTileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.FakePlayer; @@ -130,12 +129,6 @@ public final class TurtlePlayer extends FakePlayer return Registry.ModEntities.TURTLE_PLAYER.get(); } - @Override - public Vec3d getPositionVector() - { - return getPositionVec(); - } - @Override public float getEyeHeight( @Nonnull Pose pose ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 4632d5db9..65f901f73 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -16,7 +16,7 @@ import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -44,10 +44,10 @@ public class TurtleModem extends AbstractTurtleUpgrade @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos turtlePos = turtle.getPosition(); - return new Vec3d( + return new Vector3d( turtlePos.getX(), turtlePos.getY(), turtlePos.getZ() diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 0a605660e..bcdb4b198 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -17,7 +17,7 @@ import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -42,10 +42,10 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade } @Override - public Vec3d getPosition() + public Vector3d getPosition() { BlockPos pos = turtle.getPosition(); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + return new Vector3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index e3ddec335..721fa4f64 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -19,12 +19,10 @@ import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import net.minecraft.client.renderer.Matrix4f; -import net.minecraft.client.renderer.TransformationMatrix; import net.minecraft.entity.Entity; -import net.minecraft.entity.SharedMonsterAttributes; +import net.minecraft.entity.ai.attributes.Attributes; import net.minecraft.entity.item.ArmorStandEntity; -import net.minecraft.fluid.IFluidState; +import net.minecraft.fluid.FluidState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.tileentity.TileEntity; @@ -32,7 +30,9 @@ import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.TransformationMatrix; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -119,9 +119,9 @@ public class TurtleTool extends AbstractTurtleUpgrade final TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction ); // See if there is an entity present - Vec3d turtlePos = turtlePlayer.getPositionVec(); - Vec3d rayDir = turtlePlayer.getLook( 1.0f ); - Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); + Vector3d turtlePos = turtlePlayer.getPositionVec(); + Vector3d rayDir = turtlePlayer.getLook( 1.0f ); + Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 ); if( hit != null ) { // Load up the turtle's inventory @@ -149,7 +149,7 @@ public class TurtleTool extends AbstractTurtleUpgrade boolean attacked = false; if( !hitEntity.hitByEntity( turtlePlayer ) ) { - float damage = (float) turtlePlayer.getAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getValue(); + float damage = (float) turtlePlayer.func_233637_b_( Attributes.ATTACK_DAMAGE ); damage *= getDamageMultiplier(); if( damage > 0.0f ) { @@ -201,7 +201,7 @@ public class TurtleTool extends AbstractTurtleUpgrade } BlockState state = world.getBlockState( blockPosition ); - IFluidState fluidState = world.getFluidState( blockPosition ); + FluidState fluidState = world.getFluidState( blockPosition ); TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); turtlePlayer.loadInventory( item.copy() ); diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 3c776d1bd..f9f649f63 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.util; import net.minecraft.item.DyeColor; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.tags.Tag; +import net.minecraft.tags.ITag; import net.minecraftforge.common.Tags; import javax.annotation.Nullable; @@ -16,7 +16,7 @@ import javax.annotation.Nullable; public final class ColourUtils { @SuppressWarnings( { "unchecked", "rawtypes" } ) - private static final Tag[] DYES = new Tag[] { + private static final ITag[] DYES = new ITag[] { Tags.Items.DYES_WHITE, Tags.Items.DYES_ORANGE, Tags.Items.DYES_MAGENTA, @@ -42,7 +42,7 @@ public final class ColourUtils { for( int i = 0; i < DYES.length; i++ ) { - Tag dye = DYES[i]; + ITag dye = DYES[i]; if( dye.contains( stack.getItem() ) ) return DyeColor.byId( i ); } diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 14200f0eb..0378a620d 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -41,7 +41,7 @@ public final class DropConsumer remainingDrops = new ArrayList<>(); dropEntity = entity; dropWorld = entity.world; - dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); + dropBounds = new AxisAlignedBB( entity.func_233580_cy_() ).grow( 2, 2, 2 ); entity.captureDrops( new ArrayList<>() ); } @@ -79,7 +79,7 @@ public final class DropConsumer { // Capture any nearby item spawns if( dropWorld == event.getWorld() && event.getEntity() instanceof ItemEntity - && dropBounds.contains( event.getEntity().getPositionVector() ) ) + && dropBounds.contains( event.getEntity().getPositionVec() ) ) { handleDrops( ((ItemEntity) event.getEntity()).getItem() ); event.setCanceled( true ); diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 229488422..4456fe493 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -10,7 +10,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import dan200.computercraft.ComputerCraft; import net.minecraft.server.MinecraftServer; -import net.minecraft.world.dimension.DimensionType; import net.minecraftforge.fml.server.ServerLifecycleHooks; import java.io.File; @@ -41,9 +40,9 @@ public final class IDAssigner public static File getDir() { - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).getSaveHandler().getWorldDirectory(); - return new File( worldDirectory, ComputerCraft.MOD_ID ); + File root = ServerLifecycleHooks.getCurrentServer().getDataDirectory(); + // TODO: File worldDirectory = server.getWorld( World.field_234918_g_ ).getSaveHandler().getWorldDirectory(); + return new File( root, ComputerCraft.MOD_ID ); } private static MinecraftServer getCachedServer() diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 11b8438ec..681627314 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -13,7 +13,7 @@ import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; @@ -93,16 +93,16 @@ public final class InventoryUtil } // Look for entity with inventory - Vec3d vecStart = new Vec3d( + Vector3d vecStart = new Vector3d( pos.getX() + 0.5 + 0.6 * side.getXOffset(), pos.getY() + 0.5 + 0.6 * side.getYOffset(), pos.getZ() + 0.5 + 0.6 * side.getZOffset() ); Direction dir = side.getOpposite(); - Vec3d vecDir = new Vec3d( + Vector3d vecDir = new Vector3d( dir.getXOffset(), dir.getYOffset(), dir.getZOffset() ); - Pair hit = WorldUtil.rayTraceEntities( world, vecStart, vecDir, 1.1 ); + Pair hit = WorldUtil.rayTraceEntities( world, vecStart, vecDir, 1.1 ); if( hit != null ) { Entity entity = hit.getKey(); diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index 2fdb56422..66d3fef58 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -10,7 +10,7 @@ import dan200.computercraft.shared.network.NetworkMessage; import dan200.computercraft.shared.network.client.PlayRecordClientMessage; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; public final class RecordUtil @@ -20,6 +20,6 @@ public final class RecordUtil public static void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos ) { NetworkMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos ); - NetworkHandler.sendToAllAround( packet, world, new Vec3d( pos ), 64 ); + NetworkHandler.sendToAllAround( packet, world, Vector3d.func_237489_a_( pos ), 64 ); } } diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java index 978b78eff..13491150b 100644 --- a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java +++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java @@ -6,8 +6,8 @@ package dan200.computercraft.shared.util; import net.minecraft.block.BlockState; +import net.minecraft.fluid.FluidState; import net.minecraft.fluid.Fluids; -import net.minecraft.fluid.IFluidState; import net.minecraft.item.BlockItemUseContext; import net.minecraft.state.BooleanProperty; import net.minecraft.state.properties.BlockStateProperties; @@ -34,7 +34,7 @@ public final class WaterloggableHelpers * @param state The current state * @return This waterlogged block's current fluid */ - public static IFluidState getWaterloggedFluidState( BlockState state ) + public static FluidState getWaterloggedFluidState( BlockState state ) { return state.get( WATERLOGGED ) ? Fluids.WATER.getStillFluidState( false ) : Fluids.EMPTY.getDefaultState(); } diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index d483c7d74..f835911e3 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -12,9 +12,14 @@ import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; -import net.minecraft.util.math.*; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; +import net.minecraftforge.common.ForgeMod; import org.apache.commons.lang3.tuple.Pair; import javax.annotation.Nonnull; @@ -56,7 +61,7 @@ public final class WorldUtil return world.getBlockState( pos ).getMaterial().isLiquid(); } - public static boolean isVecInside( VoxelShape shape, Vec3d vec ) + public static boolean isVecInside( VoxelShape shape, Vector3d vec ) { if( shape.isEmpty() ) return false; // AxisAlignedBB.contains, but without strict inequalities. @@ -64,9 +69,9 @@ public final class WorldUtil return vec.x >= bb.minX && vec.x <= bb.maxX && vec.y >= bb.minY && vec.y <= bb.maxY && vec.z >= bb.minZ && vec.z <= bb.maxZ; } - public static Pair rayTraceEntities( World world, Vec3d vecStart, Vec3d vecDir, double distance ) + public static Pair rayTraceEntities( World world, Vector3d vecStart, Vector3d vecDir, double distance ) { - Vec3d vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); + Vector3d vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance ); // Raycast for blocks Entity collisionEntity = getEntity( world ); @@ -105,7 +110,7 @@ public final class WorldUtil continue; } - Vec3d littleBoxResult = littleBox.rayTrace( vecStart, vecEnd ).orElse( null ); + Vector3d littleBoxResult = littleBox.rayTrace( vecStart, vecEnd ).orElse( null ); if( littleBoxResult != null ) { double dist = vecStart.distanceTo( littleBoxResult ); @@ -126,21 +131,21 @@ public final class WorldUtil } if( closest != null && closestDist <= distance ) { - Vec3d closestPos = vecStart.add( vecDir.x * closestDist, vecDir.y * closestDist, vecDir.z * closestDist ); + Vector3d closestPos = vecStart.add( vecDir.x * closestDist, vecDir.y * closestDist, vecDir.z * closestDist ); return Pair.of( closest, closestPos ); } return null; } - public static Vec3d getRayStart( LivingEntity entity ) + public static Vector3d getRayStart( LivingEntity entity ) { return entity.getEyePosition( 1 ); } - public static Vec3d getRayEnd( PlayerEntity player ) + public static Vector3d getRayEnd( PlayerEntity player ) { - double reach = player.getAttribute( PlayerEntity.REACH_DISTANCE ).getValue(); - Vec3d look = player.getLookVec(); + double reach = player.getAttribute( ForgeMod.REACH_DISTANCE.get() ).getValue(); + Vector3d look = player.getLookVec(); return getRayStart( player ).add( look.x * reach, look.y * reach, look.z * reach ); } @@ -170,15 +175,15 @@ public final class WorldUtil double xPos = pos.getX() + 0.5 + xDir * 0.4; double yPos = pos.getY() + 0.5 + yDir * 0.4; double zPos = pos.getZ() + 0.5 + zDir * 0.4; - dropItemStack( stack, world, new Vec3d( xPos, yPos, zPos ), xDir, yDir, zDir ); + dropItemStack( stack, world, new Vector3d( xPos, yPos, zPos ), xDir, yDir, zDir ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos ) + public static void dropItemStack( @Nonnull ItemStack stack, World world, Vector3d pos ) { dropItemStack( stack, world, pos, 0.0, 0.0, 0.0 ); } - public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos, double xDir, double yDir, double zDir ) + public static void dropItemStack( @Nonnull ItemStack stack, World world, Vector3d pos, double xDir, double yDir, double zDir ) { ItemEntity item = new ItemEntity( world, pos.x, pos.y, pos.z, stack.copy() ); item.setMotion( diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index c66c7e19b..a80758c65 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -10,7 +10,7 @@ import dan200.computercraft.api.network.Packet; import dan200.computercraft.api.network.wired.IWiredNetwork; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -337,7 +337,7 @@ public final class WiredNetwork implements IWiredNetwork while( (point = transmitTo.pollFirst()) != null ) { World world = point.node.element.getWorld(); - Vec3d position = point.node.element.getPosition(); + Vector3d position = point.node.element.getPosition(); for( WiredNode neighbour : point.node.neighbours ) { TransmitPoint neighbourPoint = points.get( neighbour ); diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 94b6f2073..7c0c1635c 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[31,32)" +loaderVersion="[32,33)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[31.0.13,32)" + versionRange="[32.0.23,33)" ordering="NONE" side="BOTH" diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 2807f189b..8d8dfded7 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -20,7 +20,7 @@ import dan200.computercraft.core.filesystem.FileSystemException; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemPeripheral; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -281,9 +281,9 @@ public class ComputerTestDelegate @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { - return Vec3d.ZERO; + return Vector3d.ZERO; } @Override diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java index 5c61f24fb..257f14326 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -28,7 +28,7 @@ public class ResourceMountTest @BeforeEach public void before() { - SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA, null ); + SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA ); manager.addResourcePack( new FolderPack( new File( "src/main/resources" ) ) ); mount = ResourceMount.get( "computercraft", "lua/rom", manager ); diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 174558001..5bd4adbdb 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -16,7 +16,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.util.DirectionUtil; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -315,13 +315,13 @@ public class NetworkTest private static final class NetworkElement implements IWiredElement { private final World world; - private final Vec3d position; + private final Vector3d position; private final String id; private final IWiredNode node; private final Map localPeripherals = Maps.newHashMap(); private final Map remotePeripherals = Maps.newHashMap(); - private NetworkElement( World world, Vec3d position, String id ) + private NetworkElement( World world, Vector3d position, String id ) { this.world = world; this.position = position; @@ -339,7 +339,7 @@ public class NetworkTest @Nonnull @Override - public Vec3d getPosition() + public Vector3d getPosition() { return position; } From 2e9d6603e39388987667d50d9d790fa9da350f4a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 14 Jul 2020 19:53:10 +0100 Subject: [PATCH 283/711] Correct IPeripheral documentation It's no longer possible to implement this on the tile, due to the conflict in getType. Given this is a really bad idea, it's not a big issue, but we should mention it in the documentation. Fixes #496. --- .../java/dan200/computercraft/api/peripheral/IPeripheral.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index c5d897e8c..88c8154a4 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -15,8 +15,7 @@ import javax.annotation.Nullable; * The interface that defines a peripheral. * * In order to expose a peripheral for your block or tile entity, you may either attach a {@link Capability}, or - * register a {@link IPeripheralProvider}. It is not recommended to implement {@link IPeripheral} directly on - * the tile. + * register a {@link IPeripheralProvider}. This cannot be implemented {@link IPeripheral} directly on the tile. * * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing * {@link IDynamicPeripheral}. From 8f069a9b72fe99e209d46ef7622541a36393dfda Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 10:06:23 +0100 Subject: [PATCH 284/711] Remove absolute file path from FS errors When dealing with invalid paths (for instance, ones which are too long or malformed), Java may throw a FileSystemException. This contains the absolute path (i.e. C:/Users/Moi/.../.minecraft/...), which is printed to the user within CC - obviously not ideal! We simply catch this exception within the MountWrapper and map it back to the local path. The disadvantage of doing it here is that we can't map the path in the exception back to the computer - we'd need to catch it in FileMount for that - so we just assume it referrs to the original path instead. Doing it in FileMount ends up being a little uglier, as we already do all the exception wrangling in FileWrapper, so this'll do for now. Fixes #495 --- .../core/filesystem/MountWrapper.java | 33 ++++++++++++------- .../resources/test-rom/spec/apis/fs_spec.lua | 9 +++++ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java index a83838118..86a97426d 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java @@ -10,6 +10,7 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; @@ -85,7 +86,7 @@ class MountWrapper } catch( IOException e ) { - throw new FileSystemException( e.getMessage() ); + throw localExceptionOf( path, e ); } } @@ -98,7 +99,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -116,7 +117,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -130,7 +131,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -145,7 +146,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -165,7 +166,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -187,7 +188,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -195,9 +196,9 @@ class MountWrapper { if( writableMount == null ) throw exceptionOf( path, "Access denied" ); + path = toLocal( path ); try { - path = toLocal( path ); if( mount.exists( path ) ) { writableMount.delete( path ); @@ -209,7 +210,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -243,7 +244,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -281,7 +282,7 @@ class MountWrapper } catch( IOException e ) { - throw localExceptionOf( e ); + throw localExceptionOf( path, e ); } } @@ -290,7 +291,7 @@ class MountWrapper return FileSystem.toLocal( path, location ); } - private FileSystemException localExceptionOf( IOException e ) + private FileSystemException localExceptionOf( @Nullable String localPath, @Nonnull IOException e ) { if( !location.isEmpty() && e instanceof FileOperationException ) { @@ -298,6 +299,14 @@ class MountWrapper if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() ); } + if( e instanceof java.nio.file.FileSystemException ) + { + // This error will contain the absolute path, leaking information about where MC is installed. We drop that, + // just taking the reason. We assume that the error refers to the input path. + String message = ((java.nio.file.FileSystemException) e).getReason().trim(); + return localPath == null ? new FileSystemException( message ) : localExceptionOf( localPath, message ); + } + return new FileSystemException( e.getMessage() ); } diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index fd16599de..a593cfcd9 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -99,6 +99,15 @@ describe("The fs library", function() handle.close() expect.error(handle.close):eq("attempt to use a closed file") end) + + it("fails gracefully when opening 'CON' on Windows", function() + local ok, err = fs.open("test-files/con", "w") + if ok then fs.delete("test-files/con") return end + + -- On my Windows/Java version the message appears to be "Incorrect function.". It may not be + -- consistent though, and honestly doesn't matter too much. + expect(err):str_match("^/test%-files/con: .*") + end) end) describe("writing in binary mode", function() From 89c1b2771dd1bf735e585348b3c0ceb741b85ead Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 10:25:21 +0100 Subject: [PATCH 285/711] Allow configuring max monitor render distance 64 blocks out to be enough for anyone. But just in case. Closes #494 --- src/main/java/dan200/computercraft/ComputerCraft.java | 1 + src/main/java/dan200/computercraft/shared/Config.java | 6 ++++++ .../shared/peripheral/monitor/TileMonitor.java | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index d712dc914..fe522ed8a 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -82,6 +82,7 @@ public final class ComputerCraft public static int modemHighAltitudeRangeDuringStorm = 384; public static int maxNotesPerTick = 8; public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST; + public static double monitorDistanceSq = 4096; public static long monitorBandwidth = 1_000_000; public static boolean turtlesNeedFuel = true; diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 812ef4c9c..f93bc5a0a 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -85,6 +85,7 @@ public final class Config private static final ConfigValue genericPeripheral; private static final ConfigValue monitorRenderer; + private static final ConfigValue monitorDistance; private static final ForgeConfigSpec serverSpec; private static final ForgeConfigSpec clientSpec; @@ -311,6 +312,10 @@ public final class Config .comment( "The renderer to use for monitors. Generally this should be kept at \"best\" - if " + "monitors have performance issues, you may wish to experiment with alternative renderers." ) .defineEnum( "monitor_renderer", MonitorRenderer.BEST ); + monitorDistance = clientBuilder + .comment( "The maximum distance monitors will render at. This defaults to the standard tile entity limit, " + + "but may be extended if you wish to build larger monitors." ) + .defineInRange( "monitor_distance", 64, 16, 1024 ); clientSpec = clientBuilder.build(); } @@ -379,6 +384,7 @@ public final class Config // Client ComputerCraft.monitorRenderer = monitorRenderer.get(); + ComputerCraft.monitorDistanceSq = monitorDistance.get() * monitorDistance.get(); } @SubscribeEvent diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 129f5f783..e9ba5e304 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -688,4 +688,10 @@ public class TileMonitor extends TileGeneric return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 ); } } + + @Override + public double getMaxRenderDistanceSquared() + { + return ComputerCraft.monitorDistanceSq; + } } From 95554a53d10279dd78492de51fcc5639d3271ab6 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 10:31:28 +0100 Subject: [PATCH 286/711] Move getResourceFile to CCAPIImpl Just means we've got all the resource processing code in one place, and keeps (most) MC code out of CC itself. --- .../dan200/computercraft/ComputerCraft.java | 17 ----------------- .../computercraft/ComputerCraftAPIImpl.java | 16 ++++++++++++++++ .../shared/computer/core/ServerComputer.java | 3 ++- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index fe522ed8a..6332348c3 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -16,15 +16,10 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.turtle.upgrades.*; -import net.minecraft.resources.IReloadableResourceManager; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.server.ServerLifecycleHooks; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.io.IOException; -import java.io.InputStream; import java.util.Collections; import java.util.EnumSet; import java.util.List; @@ -140,16 +135,4 @@ public final class ComputerCraft Registry.setup(); } - public static InputStream getResourceFile( String domain, String subPath ) - { - IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); - try - { - return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream(); - } - catch( IOException ignored ) - { - return null; - } - } } diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 28f6d4e71..dcd2c5bdb 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -27,6 +27,7 @@ import dan200.computercraft.shared.wired.WiredNode; import net.minecraft.resources.IReloadableResourceManager; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; @@ -36,6 +37,8 @@ import net.minecraftforge.fml.server.ServerLifecycleHooks; import javax.annotation.Nonnull; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT; @@ -49,6 +52,19 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI { } + public static InputStream getResourceFile( String domain, String subPath ) + { + IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager(); + try + { + return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream(); + } + catch( IOException ignored ) + { + return null; + } + } + @Nonnull @Override public String getInstalledVersion() diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 3b2959ca6..6026eed98 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.computer.core; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.ComputerCraftAPIImpl; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -333,7 +334,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput @Override public InputStream createResourceFile( String domain, String subPath ) { - return ComputerCraft.getResourceFile( domain, subPath ); + return ComputerCraftAPIImpl.getResourceFile( domain, subPath ); } @Override From 31764f6d65be7f7f5b586cc5e71e52312efcb53d Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 11:14:04 +0100 Subject: [PATCH 287/711] Register various gold items as piglin_loved --- .../data/minecraft/tags/items/piglin_loved.json | 10 ++++++++++ src/main/java/dan200/computercraft/data/Tags.java | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/generated/resources/data/minecraft/tags/items/piglin_loved.json diff --git a/src/generated/resources/data/minecraft/tags/items/piglin_loved.json b/src/generated/resources/data/minecraft/tags/items/piglin_loved.json new file mode 100644 index 000000000..8eedcc427 --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/items/piglin_loved.json @@ -0,0 +1,10 @@ +{ + "replace": false, + "values": [ + "computercraft:computer_advanced", + "computercraft:turtle_advanced", + "computercraft:wireless_modem_advanced", + "computercraft:pocket_computer_advanced", + "computercraft:monitor_advanced" + ] +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java index a8f981b2e..2920548a4 100644 --- a/src/main/java/dan200/computercraft/data/Tags.java +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -20,6 +20,8 @@ import static dan200.computercraft.data.Tags.CCTags.*; public class Tags extends ItemTagsProvider { + private static final ITag.INamedTag PIGLIN_LOVED = ItemTags.field_232903_N_; + public static class CCTags { public static final ITag.INamedTag COMPUTER = item( "computer" ); @@ -44,6 +46,12 @@ public class Tags extends ItemTagsProvider func_240522_a_( TURTLE ).func_240534_a_( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() ); func_240522_a_( WIRED_MODEM ).func_240534_a_( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() ); func_240522_a_( MONITOR ).func_240534_a_( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() ); + + func_240522_a_( PIGLIN_LOVED ).func_240534_a_( + Registry.ModItems.COMPUTER_ADVANCED.get(), Registry.ModItems.TURTLE_ADVANCED.get(), + Registry.ModItems.WIRELESS_MODEM_ADVANCED.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(), + Registry.ModItems.MONITOR_ADVANCED.get() + ); } private static ITag.INamedTag item( String name ) From 087c305b0de6b6e3297dece3105b3ba03358c542 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 12:17:02 +0100 Subject: [PATCH 288/711] Fix non-inventory GUIs rendering labels --- .../java/dan200/computercraft/client/gui/GuiComputer.java | 6 ++++++ .../java/dan200/computercraft/client/gui/GuiPrintout.java | 6 ++++++ .../java/dan200/computercraft/client/gui/GuiTurtle.java | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index bd354e30c..65ef21bdd 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -150,4 +150,10 @@ public final class GuiComputer extends Containe return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); } + + @Override + protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + { + // Skip rendering labels. + } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index e60d997aa..6e2bc6ead 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -118,4 +118,10 @@ public class GuiPrintout extends ContainerScreen super.render( stack, mouseX, mouseY, partialTicks ); func_230459_a_( stack, mouseX, mouseY ); } + + @Override + protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + { + // Skip rendering labels. + } } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index f84902e6b..6399b0101 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -138,4 +138,10 @@ public class GuiTurtle extends ContainerScreen return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); } + + @Override + protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + { + // Skip rendering labels. + } } From 2f323f23d7acc9aeadcb5eb6872b4797b2f13261 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 12:23:36 +0100 Subject: [PATCH 289/711] Update changelog for release --- .../resources/data/computercraft/lua/rom/help/changelog.txt | 4 +++- .../resources/data/computercraft/lua/rom/help/whatsnew.txt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 9440b0f00..e12e9ebb7 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -3,6 +3,7 @@ * Add cc.image.nft module, for working with nft files. (JakobDev) * [experimental] Provide a generic peripheral for any tile entity without an existing one. We currently provide methods for working with inventories, fluid tanks and energy storage. This is disabled by default, and must be turned on in the config. * Add configuration to control the sizes of monitors and terminals. +* Add configuration to control maximum render distance of monitors. * Allow getting "detailed" information about an item, using `turtle.getItemDetail(slot, true)`. This will contain the same information that the generic peripheral supplies. And several bug fixes: @@ -10,8 +11,9 @@ And several bug fixes: * Fix write method missing from printers. * Fix dupe bug when killing an entity with a turtle. * Correctly supply port in the Host header (neumond). -* Fix turtle.craft failing when missing an argument. +* Fix `turtle.craft` failing when missing an argument. * Fix deadlock when mistakenly "watching" an unloaded chunk. +* Fix full path of files being leaked in some errors. Type "help changelog" to see the full version history. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 62a5aa8ca..b306fc690 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -3,6 +3,7 @@ New features in CC: Tweaked 1.90.0 * Add cc.image.nft module, for working with nft files. (JakobDev) * [experimental] Provide a generic peripheral for any tile entity without an existing one. We currently provide methods for working with inventories, fluid tanks and energy storage. This is disabled by default, and must be turned on in the config. * Add configuration to control the sizes of monitors and terminals. +* Add configuration to control maximum render distance of monitors. * Allow getting "detailed" information about an item, using `turtle.getItemDetail(slot, true)`. This will contain the same information that the generic peripheral supplies. And several bug fixes: @@ -10,7 +11,8 @@ And several bug fixes: * Fix write method missing from printers. * Fix dupe bug when killing an entity with a turtle. * Correctly supply port in the Host header (neumond). -* Fix turtle.craft failing when missing an argument. +* Fix `turtle.craft` failing when missing an argument. * Fix deadlock when mistakenly "watching" an unloaded chunk. +* Fix full path of files being leaked in some errors. Type "help changelog" to see the full version history. From a1dcd59d9507d0da5abb5b392c3e5cf3f33da2f5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 18 Jul 2020 15:11:43 +0100 Subject: [PATCH 290/711] Update to latest Forge Fixes #498 --- build.gradle | 6 +++--- gradle.properties | 4 ++-- .../shared/proxy/ComputerCraftProxyCommon.java | 6 +++--- src/main/resources/META-INF/mods.toml | 2 +- .../computercraft/lua/rom/help/changelog.txt | 4 ++++ .../computercraft/lua/rom/help/whatsnew.txt | 17 ++--------------- 6 files changed, 15 insertions(+), 24 deletions(-) diff --git a/build.gradle b/build.gradle index fbfe1da1b..1463198dd 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.179' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.181' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } @@ -409,7 +409,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'release' + releaseType = 'alpha' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { @@ -487,7 +487,7 @@ githubRelease { .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() } - prerelease false + prerelease true } def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] diff --git a/gradle.properties b/gradle.properties index 77974d726..22dac54ed 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Mod properties -mod_version=1.90.0 +mod_version=1.90.1 # Minecraft properties (update mods.toml when changing) mc_version=1.16.1 -forge_version=32.0.63 +forge_version=32.0.69 mappings_version=20200707-1.16.1 diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 5cf2699c3..d40956cf2 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -33,13 +33,13 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.registry.Registry; import net.minecraftforge.common.capabilities.CapabilityManager; import net.minecraftforge.event.LootTableLoadEvent; +import net.minecraftforge.event.RegisterCommandsEvent; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.event.server.FMLServerStartedEvent; -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; import java.util.Arrays; @@ -139,9 +139,9 @@ public final class ComputerCraftProxyCommon } @SubscribeEvent - public static void onServerStarting( FMLServerStartingEvent event ) + public static void onRegisterCommand( RegisterCommandsEvent event ) { - CommandComputerCraft.register( event.getCommandDispatcher() ); + CommandComputerCraft.register( event.getDispatcher() ); } @SubscribeEvent diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 7c0c1635c..cf05511a0 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[32.0.23,33)" + versionRange="[32.0.69,33)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index e12e9ebb7..cce69b46a 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.90.1 + +* Update to Forge 32.0.69 + # New features in CC: Tweaked 1.90.0 * Add cc.image.nft module, for working with nft files. (JakobDev) diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index b306fc690..101e226a5 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,18 +1,5 @@ -New features in CC: Tweaked 1.90.0 +New features in CC: Tweaked 1.90.1 -* Add cc.image.nft module, for working with nft files. (JakobDev) -* [experimental] Provide a generic peripheral for any tile entity without an existing one. We currently provide methods for working with inventories, fluid tanks and energy storage. This is disabled by default, and must be turned on in the config. -* Add configuration to control the sizes of monitors and terminals. -* Add configuration to control maximum render distance of monitors. -* Allow getting "detailed" information about an item, using `turtle.getItemDetail(slot, true)`. This will contain the same information that the generic peripheral supplies. - -And several bug fixes: -* Add back config for allowing interacting with command computers. -* Fix write method missing from printers. -* Fix dupe bug when killing an entity with a turtle. -* Correctly supply port in the Host header (neumond). -* Fix `turtle.craft` failing when missing an argument. -* Fix deadlock when mistakenly "watching" an unloaded chunk. -* Fix full path of files being leaked in some errors. +* Update to Forge 32.0.69 Type "help changelog" to see the full version history. From fb70a1a998357f718ea69b9632d01429c341f23b Mon Sep 17 00:00:00 2001 From: BlackDragon-B <59388636+BlackDragon-B@users.noreply.github.com> Date: Sat, 18 Jul 2020 19:59:52 +0200 Subject: [PATCH 291/711] Added Windows thing. (#500) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b9146d2e3..fdd97675e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ do use the issue templates - they provide a useful hint on what information to p ## Developing In order to develop CC: Tweaked, you'll need to download the source code and then run it. This is a pretty simple -process. +process. When building on Windows, Use `gradlew.bat` instead of `./gradlew`. - **Clone the repository:** `git clone https://github.com/SquidDev-CC/CC-Tweaked.git && cd CC-Tweaked` - **Setup Forge:** `./gradlew build` From d51851e7636034a4bf24dc998779a5068ca2095a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 23 Jul 2020 22:40:21 +0100 Subject: [PATCH 292/711] Use FML's scan data to gather annotations We can just scrape them from the @AutoService annotation, which saves us having to duplicate any work. Hopefully fixes #501, but I haven't tested in a non-dev environment yet. --- .../dan200/computercraft/ComputerCraft.java | 4 +- .../computercraft/core/asm/GenericSource.java | 31 +++++++-- .../shared/util/ServiceUtil.java | 63 +++++++++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 src/main/java/dan200/computercraft/shared/util/ServiceUtil.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 6332348c3..6a833d0fb 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -8,6 +8,7 @@ package dan200.computercraft; import dan200.computercraft.api.turtle.event.TurtleAction; import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRule; +import dan200.computercraft.core.asm.GenericSource; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ClientComputerRegistry; @@ -16,6 +17,7 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; import dan200.computercraft.shared.turtle.upgrades.*; +import dan200.computercraft.shared.util.ServiceUtil; import net.minecraftforge.fml.common.Mod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -133,6 +135,6 @@ public final class ComputerCraft { Config.setup(); Registry.setup(); + GenericSource.setup( () -> ServiceUtil.loadServicesForge( GenericSource.class ) ); } - } diff --git a/src/main/java/dan200/computercraft/core/asm/GenericSource.java b/src/main/java/dan200/computercraft/core/asm/GenericSource.java index 77c4a0ca3..71cab0b26 100644 --- a/src/main/java/dan200/computercraft/core/asm/GenericSource.java +++ b/src/main/java/dan200/computercraft/core/asm/GenericSource.java @@ -9,6 +9,7 @@ package dan200.computercraft.core.asm; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider; +import dan200.computercraft.shared.util.ServiceUtil; import net.minecraft.util.ResourceLocation; import javax.annotation.Nonnull; @@ -16,11 +17,12 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.ServiceLoader; +import java.util.function.Supplier; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; +import java.util.stream.Stream; /** * A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own. @@ -42,6 +44,18 @@ public interface GenericSource @Nonnull ResourceLocation id(); + /** + * Register a stream of generic sources. + * + * @param sources The source of generic methods. + * @see ServiceUtil For ways to load this. Sadly {@link java.util.ServiceLoader} is broken under Forge, but we don't + * want to add a hard-dep on Forge within core either. + */ + static void setup( Supplier> sources ) + { + GenericMethod.sources = sources; + } + /** * A generic method is a method belonging to a {@link GenericSource} with a known target. */ @@ -51,6 +65,7 @@ public interface GenericSource final LuaFunction annotation; final Class target; + static Supplier> sources; private static List cache; GenericMethod( Method method, LuaFunction annotation, Class target ) @@ -68,10 +83,16 @@ public interface GenericSource static List all() { if( cache != null ) return cache; - return cache = StreamSupport - .stream( ServiceLoader.load( GenericSource.class, GenericSource.class.getClassLoader() ).spliterator(), false ) + if( sources == null ) + { + ComputerCraft.log.warn( "Getting GenericMethods without a provider" ); + return cache = Collections.emptyList(); + } + + return cache = sources.get() .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) - .map( method -> { + .map( method -> + { LuaFunction annotation = method.getAnnotation( LuaFunction.class ); if( annotation == null ) return null; diff --git a/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java b/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java new file mode 100644 index 000000000..6ff2d898e --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java @@ -0,0 +1,63 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.shared.util; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.ComputerCraftAPI; +import net.minecraftforge.fml.ModList; +import org.objectweb.asm.Type; + +import java.util.List; +import java.util.ServiceLoader; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public final class ServiceUtil +{ + private static final Type AUTO_SERVICE = Type.getType( "Lcom/google/auto/service/AutoService;" ); + + private ServiceUtil() + { + } + + public static Stream loadServices( Class target ) + { + return StreamSupport.stream( ServiceLoader.load( target, ServiceUtil.class.getClassLoader() ).spliterator(), false ); + } + + public static Stream loadServicesForge( Class target ) + { + Type type = Type.getType( target ); + ClassLoader loader = ComputerCraftAPI.class.getClassLoader(); + return ModList.get().getAllScanData().stream() + .flatMap( x -> x.getAnnotations().stream() ) + .filter( x -> x.getAnnotationType().equals( AUTO_SERVICE ) ) + .filter( x -> { + Object value = x.getAnnotationData().get( "value" ); + return value instanceof List && ((List) value).contains( type ); + } ) + .flatMap( x -> { + try + { + Class klass = loader.loadClass( x.getClassType().getClassName() ); + if( !target.isAssignableFrom( klass ) ) + { + ComputerCraft.log.error( "{} is not a subtype of {}", x.getClassType().getClassName(), target.getName() ); + return Stream.empty(); + } + + Class casted = klass.asSubclass( target ); + return Stream.of( casted.newInstance() ); + } + catch( ReflectiveOperationException e ) + { + ComputerCraft.log.error( "Cannot load {}", x.getClassType(), e ); + return Stream.empty(); + } + } ); + } +} From 9ce33f8a3fe375056163d6d7a9014f98ad3c2500 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 25 Jul 2020 10:56:50 +0100 Subject: [PATCH 293/711] Add back missing override of getPositionVec This was removed in the initial update (46595e73dfc08d75c542f7ac637111c6d917fa30) because I got terribly confused over mappings and I forgot to add it back. Fixes #505 --- .../computercraft/shared/turtle/core/TurtlePlayer.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 691079d1e..5e158e210 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -25,6 +25,7 @@ import net.minecraft.tileentity.SignTileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.FakePlayer; @@ -129,6 +130,12 @@ public final class TurtlePlayer extends FakePlayer return Registry.ModEntities.TURTLE_PLAYER.get(); } + @Override + public Vector3d getPositionVec() + { + return new Vector3d( getPosX(), getPosY(), getPosZ() ); + } + @Override public float getEyeHeight( @Nonnull Pose pose ) { From c8a6888a2ff39be2bc3a3f3cd048f2ff47619a41 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 25 Jul 2020 11:19:04 +0100 Subject: [PATCH 294/711] Fix styles not being saved Styles have been changed to be immutable, meaning that we were never updating them! Fixes #499. --- .../computercraft/shared/command/CommandCopy.java | 7 +++---- .../shared/command/text/ChatHelpers.java | 14 ++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java index adf102649..52143faee 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java @@ -12,6 +12,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.command.CommandSource; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.Style; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.event.ClickEvent; import net.minecraft.util.text.event.HoverEvent; @@ -57,10 +58,8 @@ public final class CommandCopy public static ITextComponent createCopyText( String text ) { - StringTextComponent name = new StringTextComponent( text ); - name.getStyle() + return new StringTextComponent( text ).func_230530_a_( Style.EMPTY .setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) ) - .setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) ); - return name; + .setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) ) ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index d060dc202..71eced8e5 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -21,14 +21,12 @@ public final class ChatHelpers public static IFormattableTextComponent coloured( String text, TextFormatting colour ) { - IFormattableTextComponent component = new StringTextComponent( text == null ? "" : text ); - component.getStyle().setFormatting( colour ); - return component; + return new StringTextComponent( text == null ? "" : text ).func_240699_a_( colour ); } public static T coloured( T component, TextFormatting colour ) { - component.getStyle().setFormatting( colour ); + component.func_240699_a_( colour ); return component; } @@ -74,11 +72,11 @@ public final class ChatHelpers { Style style = component.getStyle(); - if( style.getColor() == null ) style.setFormatting( TextFormatting.YELLOW ); - style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) ); - style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) ); + if( style.getColor() == null ) style = style.setFormatting( TextFormatting.YELLOW ); + style = style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) ); + style = style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) ); - return component; + return component.func_230530_a_( style ); } public static IFormattableTextComponent header( String text ) From ac7979fb46414250cdf4d34461542012e1f6e5cc Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 25 Jul 2020 11:53:46 +0100 Subject: [PATCH 295/711] Bump for 1.90.2 --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 4 ++++ .../computercraft/lua/rom/help/whatsnew.txt | 17 ++--------------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/gradle.properties b/gradle.properties index 08369c0f6..106c54e9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.90.0 +mod_version=1.90.2 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index e12e9ebb7..08e8327a3 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.90.2 + +* Fix generic peripherals not being registered outside a dev environment. + # New features in CC: Tweaked 1.90.0 * Add cc.image.nft module, for working with nft files. (JakobDev) diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index b306fc690..8135e4db6 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,18 +1,5 @@ -New features in CC: Tweaked 1.90.0 +New features in CC: Tweaked 1.90.2 -* Add cc.image.nft module, for working with nft files. (JakobDev) -* [experimental] Provide a generic peripheral for any tile entity without an existing one. We currently provide methods for working with inventories, fluid tanks and energy storage. This is disabled by default, and must be turned on in the config. -* Add configuration to control the sizes of monitors and terminals. -* Add configuration to control maximum render distance of monitors. -* Allow getting "detailed" information about an item, using `turtle.getItemDetail(slot, true)`. This will contain the same information that the generic peripheral supplies. - -And several bug fixes: -* Add back config for allowing interacting with command computers. -* Fix write method missing from printers. -* Fix dupe bug when killing an entity with a turtle. -* Correctly supply port in the Host header (neumond). -* Fix `turtle.craft` failing when missing an argument. -* Fix deadlock when mistakenly "watching" an unloaded chunk. -* Fix full path of files being leaked in some errors. +* Fix generic peripherals not being registered outside a dev environment. Type "help changelog" to see the full version history. From 053cb1b53c35bf15b419e95cd5283989a7c9b54b Mon Sep 17 00:00:00 2001 From: neumond Date: Sat, 18 Jul 2020 16:58:36 +0300 Subject: [PATCH 296/711] Fix JSON serialization of strings Control characters become escaped as JSON requires Non-ASCII characters get escaped as well for better interoperability We assume here that lua strings represent only first 256 code points of unicode --- .../computercraft/lua/rom/apis/textutils.lua | 29 +++++++++++++++++-- .../test-rom/spec/apis/textutils_spec.lua | 14 +++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 0e96a287d..0f191e522 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -335,6 +335,31 @@ empty_json_array = mk_tbl("[]", "empty_json_array") -- @see textutils.unserialiseJSON json_null = mk_tbl("null", "json_null") +local serializeJSONString +do + local function hexify(c) + return ("\\u00%02X"):format(c:byte()) + end + + local map = { + ["\""] = "\\\"", + ["\\"] = "\\\\", + ["\b"] = "\\b", + ["\f"] = "\\f", + ["\n"] = "\\n", + ["\r"] = "\\r", + ["\t"] = "\\t", + } + for i = 0, 0x1f do + local c = string.char(i) + if map[c] == nil then map[c] = hexify(c) end + end + + serializeJSONString = function(s) + return ('"%s"'):format(s:gsub("[\0-\x1f\"\\]", map):gsub("[\x7f-\xff]", hexify)) + end +end + local function serializeJSONImpl(t, tTracking, bNBTStyle) local sType = type(t) if t == empty_json_array then return "[]" @@ -361,7 +386,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) if bNBTStyle then sEntry = tostring(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) else - sEntry = string.format("%q", k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) + sEntry = serializeJSONString(k) .. ":" .. serializeJSONImpl(v, tTracking, bNBTStyle) end if nObjectSize == 0 then sObjectResult = sObjectResult .. sEntry @@ -390,7 +415,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) end elseif sType == "string" then - return string.format("%q", t) + return serializeJSONString(t) elseif sType == "number" or sType == "boolean" then return tostring(t) diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index 94e243afc..d60d30f47 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -78,6 +78,20 @@ describe("The textutils library", function() it("serializes null", function() expect(textutils.serializeJSON(textutils.json_null)):eq("null") end) + + it("serializes strings", function() + expect(textutils.serializeJSON('a')):eq('"a"') + expect(textutils.serializeJSON('"')):eq('"\\""') + expect(textutils.serializeJSON('\\')):eq('"\\\\"') + expect(textutils.serializeJSON('/')):eq('"/"') + expect(textutils.serializeJSON('\b')):eq('"\\b"') + expect(textutils.serializeJSON('\n')):eq('"\\n"') + expect(textutils.serializeJSON(string.char(0))):eq('"\\u0000"') + expect(textutils.serializeJSON(string.char(0x0A))):eq('"\\n"') + expect(textutils.serializeJSON(string.char(0x1D))):eq('"\\u001D"') + expect(textutils.serializeJSON(string.char(0x81))):eq('"\\u0081"') + expect(textutils.serializeJSON(string.char(0xFF))):eq('"\\u00FF"') + end) end) describe("textutils.unserializeJSON", function() From e5cf0d1c61c1816eb8d4a56ca21d8d76cbb5a3ce Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 27 Jul 2020 18:26:42 +0100 Subject: [PATCH 297/711] Update mappings --- gradle.properties | 2 +- .../computercraft/ComputerCraftAPIImpl.java | 4 ++-- .../computercraft/client/gui/GuiComputer.java | 16 ++++++++-------- .../computercraft/client/gui/GuiDiskDrive.java | 2 +- .../computercraft/client/gui/GuiPrinter.java | 2 +- .../computercraft/client/gui/GuiPrintout.java | 7 ++----- .../computercraft/client/gui/GuiTurtle.java | 16 ++++++++-------- .../java/dan200/computercraft/data/Tags.java | 10 +++++----- .../shared/command/CommandComputerCraft.java | 14 +++++++------- .../shared/command/CommandCopy.java | 2 +- .../command/builder/HelpingArgumentBuilder.java | 16 ++++++++-------- .../shared/command/text/ChatHelpers.java | 8 ++++---- .../shared/command/text/TableFormatter.java | 16 ++++++++-------- .../shared/computer/items/ItemComputerBase.java | 2 +- .../shared/media/items/ItemDisk.java | 2 +- .../shared/peripheral/generic/data/ItemData.java | 2 +- .../modem/wired/TileWiredModemFull.java | 4 ++-- .../shared/peripheral/printer/TilePrinter.java | 2 +- .../shared/pocket/core/PocketServerComputer.java | 2 +- .../shared/pocket/items/ItemPocketComputer.java | 2 +- .../shared/proxy/ComputerCraftProxyCommon.java | 2 +- .../shared/turtle/upgrades/TurtleTool.java | 2 +- .../computercraft/shared/util/DropConsumer.java | 2 +- .../computercraft/shared/util/RecordUtil.java | 2 +- 24 files changed, 68 insertions(+), 71 deletions(-) diff --git a/gradle.properties b/gradle.properties index ccb81d88c..2b9a3c95a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,4 +4,4 @@ mod_version=1.90.2 # Minecraft properties (update mods.toml when changing) mc_version=1.16.1 forge_version=32.0.75 -mappings_version=20200707-1.16.1 +mappings_version=20200723-1.16.1 diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index 2c8d0a683..e294a7ac1 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -54,7 +54,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI public static InputStream getResourceFile( String domain, String subPath ) { - IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().func_240970_h_(); + IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager(); try { return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream(); @@ -97,7 +97,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI @Override public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath ) { - IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().func_240970_h_(); + IReloadableResourceManager manager = (IReloadableResourceManager) ServerLifecycleHooks.getCurrentServer().getDataPackRegistries().getResourceManager(); ResourceMount mount = ResourceMount.get( domain, subPath, manager ); return mount.exists( "" ) ? mount : null; } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 65ef21bdd..ed46daf49 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -91,13 +91,13 @@ public final class GuiComputer extends Containe terminalWrapper = new WidgetWrapper( terminal, MARGIN + BORDER + guiLeft, MARGIN + BORDER + guiTop, termPxWidth, termPxHeight ); children.add( terminalWrapper ); - setFocused( terminalWrapper ); + setListener( terminalWrapper ); } @Override - public void removed() + public void onClose() { - super.removed(); + super.onClose(); children.remove( terminal ); terminal = null; minecraft.keyboardListener.enableRepeatEvents( false ); @@ -114,16 +114,16 @@ public final class GuiComputer extends Containe public boolean keyPressed( int key, int scancode, int modifiers ) { // Forward the tab key to the terminal, rather than moving between controls. - if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper ) + if( key == GLFW.GLFW_KEY_TAB && getListener() != null && getListener() == terminalWrapper ) { - return getFocused().keyPressed( key, scancode, modifiers ); + return getListener().keyPressed( key, scancode, modifiers ); } return super.keyPressed( key, scancode, modifiers ); } @Override - public void func_230450_a_( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY ) + public void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack stack, float partialTicks, int mouseX, int mouseY ) { // Draw terminal terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); @@ -147,12 +147,12 @@ public final class GuiComputer extends Containe @Override public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY ) { - return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) + return (getListener() != null && getListener().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); } @Override - protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + protected void drawGuiContainerForegroundLayer( @Nonnull MatrixStack transform, int mouseX, int mouseY ) { // Skip rendering labels. } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index e4d2ab06c..0eb36af5a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -25,7 +25,7 @@ public class GuiDiskDrive extends ContainerScreen } @Override - protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( BACKGROUND ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index a6c14aea3..a111a6e6a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -33,7 +33,7 @@ public class GuiPrinter extends ContainerScreen }*/ @Override - protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); minecraft.getTextureManager().bindTexture( BACKGROUND ); diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 6e2bc6ead..e340894ef 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -15,7 +15,6 @@ import net.minecraft.client.gui.screen.inventory.ContainerScreen; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.math.vector.Matrix4f; -import net.minecraft.util.math.vector.TransformationMatrix; import net.minecraft.util.text.ITextComponent; import org.lwjgl.glfw.GLFW; @@ -25,8 +24,6 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*; public class GuiPrintout extends ContainerScreen { - private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix(); - private final boolean m_book; private final int m_pages; private final TextBuffer[] m_text; @@ -94,7 +91,7 @@ public class GuiPrintout extends ContainerScreen } @Override - protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { // Draw the printout RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f ); @@ -120,7 +117,7 @@ public class GuiPrintout extends ContainerScreen } @Override - protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + protected void drawGuiContainerForegroundLayer( @Nonnull MatrixStack transform, int mouseX, int mouseY ) { // Skip rendering labels. } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 6399b0101..945e7d1f9 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -64,13 +64,13 @@ public class GuiTurtle extends ContainerScreen terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + guiLeft, 2 + 8 + guiTop, termPxWidth, termPxHeight ); children.add( terminalWrapper ); - setFocused( terminalWrapper ); + setListener( terminalWrapper ); } @Override - public void removed() + public void onClose() { - super.removed(); + super.onClose(); children.remove( terminal ); terminal = null; minecraft.keyboardListener.enableRepeatEvents( false ); @@ -87,9 +87,9 @@ public class GuiTurtle extends ContainerScreen public boolean keyPressed( int key, int scancode, int modifiers ) { // Forward the tab key to the terminal, rather than moving between controls. - if( key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminalWrapper ) + if( key == GLFW.GLFW_KEY_TAB && getListener() != null && getListener() == terminalWrapper ) { - return getFocused().keyPressed( key, scancode, modifiers ); + return getListener().keyPressed( key, scancode, modifiers ); } return super.keyPressed( key, scancode, modifiers ); @@ -110,7 +110,7 @@ public class GuiTurtle extends ContainerScreen } @Override - protected void func_230450_a_( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) + protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { // Draw term boolean advanced = m_family == ComputerFamily.ADVANCED; @@ -135,12 +135,12 @@ public class GuiTurtle extends ContainerScreen @Override public boolean mouseDragged( double x, double y, int button, double deltaX, double deltaY ) { - return (getFocused() != null && getFocused().mouseDragged( x, y, button, deltaX, deltaY )) + return (getListener() != null && getListener().mouseDragged( x, y, button, deltaX, deltaY )) || super.mouseDragged( x, y, button, deltaX, deltaY ); } @Override - protected void func_230451_b_( @Nonnull MatrixStack transform, int mouseX, int mouseY ) + protected void drawGuiContainerForegroundLayer( @Nonnull MatrixStack transform, int mouseX, int mouseY ) { // Skip rendering labels. } diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java index 2920548a4..587c1b506 100644 --- a/src/main/java/dan200/computercraft/data/Tags.java +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -38,16 +38,16 @@ public class Tags extends ItemTagsProvider @Override protected void registerTags() { - func_240522_a_( COMPUTER ).func_240534_a_( + getOrCreateBuilder( COMPUTER ).add( Registry.ModItems.COMPUTER_NORMAL.get(), Registry.ModItems.COMPUTER_ADVANCED.get(), Registry.ModItems.COMPUTER_COMMAND.get() ); - func_240522_a_( TURTLE ).func_240534_a_( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() ); - func_240522_a_( WIRED_MODEM ).func_240534_a_( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() ); - func_240522_a_( MONITOR ).func_240534_a_( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() ); + getOrCreateBuilder( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() ); + getOrCreateBuilder( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() ); + getOrCreateBuilder( MONITOR ).add( Registry.ModItems.MONITOR_NORMAL.get(), Registry.ModItems.MONITOR_ADVANCED.get() ); - func_240522_a_( PIGLIN_LOVED ).func_240534_a_( + getOrCreateBuilder( PIGLIN_LOVED ).add( Registry.ModItems.COMPUTER_ADVANCED.get(), Registry.ModItems.TURTLE_ADVANCED.get(), Registry.ModItems.WIRELESS_MODEM_ADVANCED.get(), Registry.ModItems.POCKET_COMPUTER_ADVANCED.get(), Registry.ModItems.MONITOR_ADVANCED.get() diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index c8afb9c44..dcde9c562 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -289,11 +289,11 @@ public final class CommandComputerCraft // Append the computer instance if( serverComputer == null ) { - out.func_230529_a_( text( "?" ) ); + out.append( text( "?" ) ); } else { - out.func_230529_a_( link( + out.append( link( text( Integer.toString( serverComputer.getInstanceID() ) ), "/computercraft dump " + serverComputer.getInstanceID(), translate( "commands.computercraft.dump.action" ) @@ -301,20 +301,20 @@ public final class CommandComputerCraft } // And ID - out.func_240702_b_( " (id " + computerId + ")" ); + out.appendString( " (id " + computerId + ")" ); // And, if we're a player, some useful links if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) ) { out - .func_240702_b_( " " ) - .func_230529_a_( link( + .appendString( " " ) + .append( link( text( "\u261b" ), "/computercraft tp " + serverComputer.getInstanceID(), translate( "commands.computercraft.tp.action" ) ) ) - .func_240702_b_( " " ) - .func_230529_a_( link( + .appendString( " " ) + .append( link( text( "\u20e2" ), "/computercraft view " + serverComputer.getInstanceID(), translate( "commands.computercraft.view.action" ) diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java index 52143faee..92b794109 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java @@ -58,7 +58,7 @@ public final class CommandCopy public static ITextComponent createCopyText( String text ) { - return new StringTextComponent( text ).func_230530_a_( Style.EMPTY + return new StringTextComponent( text ).mergeStyle( Style.EMPTY .setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) ) .setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) ) ); } diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index 48ba35e6c..0faf686fc 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -175,11 +175,11 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder child : node.getChildren() ) { @@ -188,16 +188,16 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder T coloured( T component, TextFormatting colour ) { - component.func_240699_a_( colour ); + component.mergeStyle( colour ); return component; } @@ -50,7 +50,7 @@ public final class ChatHelpers IFormattableTextComponent component = new StringTextComponent( "" ); for( ITextComponent child : children ) { - component.func_230529_a_( child ); + component.append( child ); } return component; } @@ -76,7 +76,7 @@ public final class ChatHelpers style = style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) ); style = style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) ); - return component.func_230530_a_( style ); + return component.setStyle( style ); } public static IFormattableTextComponent header( String text ) diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index 7d001f20c..c846cbce4 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -79,12 +79,12 @@ public interface TableFormatter StringTextComponent line = new StringTextComponent( "" ); for( int i = 0; i < columns - 1; i++ ) { - line.func_230529_a_( headers[i] ); + line.append( headers[i] ); ITextComponent padding = getPadding( headers[i], maxWidths[i] ); - if( padding != null ) line.func_230529_a_( padding ); - line.func_230529_a_( SEPARATOR ); + if( padding != null ) line.append( padding ); + line.append( SEPARATOR ); } - line.func_230529_a_( headers[columns - 1] ); + line.append( headers[columns - 1] ); writeLine( rowId++, line ); @@ -100,12 +100,12 @@ public interface TableFormatter StringTextComponent line = new StringTextComponent( "" ); for( int i = 0; i < columns - 1; i++ ) { - line.func_230529_a_( row[i] ); + line.append( row[i] ); ITextComponent padding = getPadding( row[i], maxWidths[i] ); - if( padding != null ) line.func_230529_a_( padding ); - line.func_230529_a_( SEPARATOR ); + if( padding != null ) line.append( padding ); + line.append( SEPARATOR ); } - line.func_230529_a_( row[columns - 1] ); + line.append( row[columns - 1] ); writeLine( rowId++, line ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 04d61c252..4bdd39642 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -43,7 +43,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte if( id >= 0 ) { list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id ) - .func_240699_a_( TextFormatting.GRAY ) ); + .mergeStyle( TextFormatting.GRAY ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 017781cba..5a067984f 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -69,7 +69,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem if( id >= 0 ) { list.add( new TranslationTextComponent( "gui.computercraft.tooltip.disk_id", id ) - .func_240699_a_( TextFormatting.GRAY ) ); + .mergeStyle( TextFormatting.GRAY ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index c20a91c85..005ff4e02 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -144,7 +144,7 @@ public class ItemData enchants.ensureCapacity( enchants.size() + rawEnchants.size() ); - for( Map.Entry entry : EnchantmentHelper.func_226652_a_( rawEnchants ).entrySet() ) + for( Map.Entry entry : EnchantmentHelper.deserializeEnchantments( rawEnchants ).entrySet() ) { Enchantment enchantment = entry.getKey(); Integer level = entry.getValue(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 459aa7277..2b9cd6278 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -217,8 +217,8 @@ public class TileWiredModemFull extends TileGeneric StringTextComponent base = new StringTextComponent( "" ); for( int i = 0; i < names.size(); i++ ) { - if( i > 0 ) base.func_240702_b_( ", " ); - base.func_230529_a_( CommandCopy.createCopyText( names.get( i ) ) ); + if( i > 0 ) base.appendString( ", " ); + base.append( CommandCopy.createCopyText( names.get( i ) ) ); } player.sendStatusMessage( new TranslationTextComponent( kind, base ), false ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index fc44c7dac..a647afe60 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -403,7 +403,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent setInventorySlotContents( i, ItemStack.EMPTY ); // Spawn the item in the world - WorldUtil.dropItemStack( stack, getWorld(), Vector3d.func_237491_b_( getPos() ).add( 0.5, 0.75, 0.5 ) ); + WorldUtil.dropItemStack( stack, getWorld(), Vector3d.copy( getPos() ).add( 0.5, 0.75, 0.5 ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index fdc21e23f..e165daf95 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -163,7 +163,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces if( entity != null ) { setWorld( entity.getEntityWorld() ); - setPosition( entity.func_233580_cy_() ); + setPosition( entity.getPosition() ); } // If a new entity has picked it up then rebroadcast the terminal to them diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 2c4979270..f284296b6 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -190,7 +190,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I if( id >= 0 ) { list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id ) - .func_240699_a_( TextFormatting.GRAY ) ); + .mergeStyle( TextFormatting.GRAY ) ); } } } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index d40956cf2..60103bd44 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -71,7 +71,7 @@ public final class ComputerCraftProxyCommon private static void registerCondition( String name, LootConditionType serializer ) { - Registry.register( Registry.field_239704_ba_, new ResourceLocation( ComputerCraft.MOD_ID, name ), serializer ); + Registry.register( Registry.LOOT_CONDITION_TYPE, new ResourceLocation( ComputerCraft.MOD_ID, name ), serializer ); } private static void registerProviders() diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 721fa4f64..cb322a37d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -149,7 +149,7 @@ public class TurtleTool extends AbstractTurtleUpgrade boolean attacked = false; if( !hitEntity.hitByEntity( turtlePlayer ) ) { - float damage = (float) turtlePlayer.func_233637_b_( Attributes.ATTACK_DAMAGE ); + float damage = (float) turtlePlayer.getAttributeValue( Attributes.ATTACK_DAMAGE ); damage *= getDamageMultiplier(); if( damage > 0.0f ) { diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 0378a620d..bf9086dc9 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -41,7 +41,7 @@ public final class DropConsumer remainingDrops = new ArrayList<>(); dropEntity = entity; dropWorld = entity.world; - dropBounds = new AxisAlignedBB( entity.func_233580_cy_() ).grow( 2, 2, 2 ); + dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); entity.captureDrops( new ArrayList<>() ); } diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index 66d3fef58..f583cd1ff 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -20,6 +20,6 @@ public final class RecordUtil public static void playRecord( SoundEvent record, String recordInfo, World world, BlockPos pos ) { NetworkMessage packet = record != null ? new PlayRecordClientMessage( pos, record, recordInfo ) : new PlayRecordClientMessage( pos ); - NetworkHandler.sendToAllAround( packet, world, Vector3d.func_237489_a_( pos ), 64 ); + NetworkHandler.sendToAllAround( packet, world, Vector3d.copyCentered( pos ), 64 ); } } From 3093f882d87b6a99d6c4cb8cf0b81846e27ac089 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 27 Jul 2020 18:37:07 +0100 Subject: [PATCH 298/711] Fix selected slot now showing in the turtle GUI --- .../computercraft/client/gui/GuiPrintout.java | 1 - .../computercraft/client/gui/GuiTurtle.java | 31 +++++++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index e340894ef..bb98d6999 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -113,7 +113,6 @@ public class GuiPrintout extends ContainerScreen setBlitOffset( getBlitOffset() + 1 ); super.render( stack, mouseX, mouseY, partialTicks ); - func_230459_a_( stack, mouseX, mouseY ); } @Override diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 945e7d1f9..4850ed4ad 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -95,33 +95,30 @@ public class GuiTurtle extends ContainerScreen return super.keyPressed( key, scancode, modifiers ); } - private void drawSelectionSlot( boolean advanced ) - { - // Draw selection slot - int slot = m_container.getSelectedSlot(); - if( slot >= 0 ) - { - RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); - int slotX = slot % 4; - int slotY = slot / 4; - minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); - // TODO: blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 ); - } - } - @Override protected void drawGuiContainerBackgroundLayer( @Nonnull MatrixStack transform, float partialTicks, int mouseX, int mouseY ) { // Draw term - boolean advanced = m_family == ComputerFamily.ADVANCED; + ResourceLocation texture = m_family == ComputerFamily.ADVANCED ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL; terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw border/inventory RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); - minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL ); + minecraft.getTextureManager().bindTexture( texture ); blit( transform, guiLeft, guiTop, 0, 0, xSize, ySize ); - drawSelectionSlot( advanced ); + // Draw selection slot + int slot = m_container.getSelectedSlot(); + if( slot >= 0 ) + { + int slotX = slot % 4; + int slotY = slot / 4; + blit( transform, + guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, + guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, + 0, 217, 24, 24 + ); + } } @Override From 50d2712581f646e795dc50a57286abfb2e3c6b12 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 27 Jul 2020 19:04:57 +0100 Subject: [PATCH 299/711] Resolve CC's save location to the world dir Fixes #509 --- .../java/dan200/computercraft/shared/util/IDAssigner.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 4456fe493..b49dd46fa 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -10,6 +10,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import dan200.computercraft.ComputerCraft; import net.minecraft.server.MinecraftServer; +import net.minecraft.world.storage.FolderName; import net.minecraftforge.fml.server.ServerLifecycleHooks; import java.io.File; @@ -25,6 +26,7 @@ import java.util.Map; public final class IDAssigner { + private static final FolderName FOLDER = new FolderName( ComputerCraft.MOD_ID ); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Type ID_TOKEN = new TypeToken>() { @@ -40,9 +42,7 @@ public final class IDAssigner public static File getDir() { - File root = ServerLifecycleHooks.getCurrentServer().getDataDirectory(); - // TODO: File worldDirectory = server.getWorld( World.field_234918_g_ ).getSaveHandler().getWorldDirectory(); - return new File( root, ComputerCraft.MOD_ID ); + return ServerLifecycleHooks.getCurrentServer().func_240776_a_( FOLDER ).toFile(); } private static MinecraftServer getCachedServer() From 29646a7f61c2736d4eb210b4fa3fcc2e20f7645f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 27 Jul 2020 19:07:06 +0100 Subject: [PATCH 300/711] Bump version to 1.90.3 --- gradle.properties | 2 +- .../data/computercraft/lua/rom/help/changelog.txt | 5 +++++ .../resources/data/computercraft/lua/rom/help/whatsnew.txt | 7 +++---- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2b9a3c95a..06da4d1ae 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.90.2 +mod_version=1.90.3 # Minecraft properties (update mods.toml when changing) mc_version=1.16.1 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 7c0810f50..f0301bcf8 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,8 @@ +# New features in CC: Tweaked 1.90.3 + +* Fix the selected slot indicator missing from the turtle GUI. +* Ensure we load/save computer data from the world directory, rather than a global one. + # New features in CC: Tweaked 1.90.2 * Fix generic peripherals not being registered outside a dev environment. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 838d728e4..3ca522752 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,7 +1,6 @@ -New features in CC: Tweaked 1.90.2 +New features in CC: Tweaked 1.90.3 -* Fix generic peripherals not being registered outside a dev environment. -* Fix `turtle.attack()` failing. -* Correctly set styles for the output of `/computercraft` commands. +* Fix the selected slot indicator missing from the turtle GUI. +* Ensure we load/save computer data from the world directory, rather than a global one. Type "help changelog" to see the full version history. From fe00e00537a21520934988e40a8960d49d6f5665 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 31 Jul 2020 18:30:53 +0100 Subject: [PATCH 301/711] Mention people should include logs --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 064fbc389..f9cee6d08 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,4 +12,5 @@ labels: bug ## Useful information to include: - Minecraft version - CC: Tweaked version + - Logs: These will be located in the `logs/` directory of your Minecraft instance. Please upload them as a gist or directly into this editor. - Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed. From 0e2ce3c63496dba032c5c5c65aa5f472e49bdab6 Mon Sep 17 00:00:00 2001 From: hydraz Date: Fri, 31 Jul 2020 14:39:09 -0300 Subject: [PATCH 302/711] Make the key for mtime "modified" in fs.attributes (#512) --- src/main/java/dan200/computercraft/core/apis/FSAPI.java | 1 + src/test/resources/test-rom/spec/apis/fs_spec.lua | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index fc909c683..4f122ae4c 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -479,6 +479,7 @@ public class FSAPI implements ILuaAPI BasicFileAttributes attributes = fileSystem.getAttributes( path ); Map result = new HashMap<>(); result.put( "modification", getFileTime( attributes.lastModifiedTime() ) ); + result.put( "modified", getFileTime( attributes.lastModifiedTime() ) ); result.put( "created", getFileTime( attributes.creationTime() ) ); result.put( "size", attributes.isDirectory() ? 0 : attributes.size() ); result.put( "isDir", attributes.isDirectory() ); diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index a593cfcd9..58db9e566 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -208,9 +208,11 @@ describe("The fs library", function() fail(("Expected created time (%d) to be within 1000ms of now (%d"):format(attributes.created, now)) end - if attributes.modification - now >= 1000 then - fail(("Expected modification time (%d) to be within 1000ms of now (%d"):format(attributes.modification, now)) + if attributes.modified - now >= 1000 then + fail(("Expected modified time (%d) to be within 1000ms of now (%d"):format(attributes.modified, now)) end + + expect(attributes.modification):eq(attributes.modified) end) end) end) From 3da3f16debaa3472c4f6f3699e980d0bf9999e2b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 4 Aug 2020 18:30:22 +0100 Subject: [PATCH 303/711] Fix link to logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3488c58b0..bab8a02e7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ![CC: Tweaked](logo.png) +# ![CC: Tweaked](doc/logo.png) [![Current build status](https://github.com/SquidDev-CC/CC-Tweaked/workflows/Build/badge.svg)](https://github.com/SquidDev-CC/CC-Tweaked/actions "Current build status") [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge") CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers, From 9f72448ecd960800caf48f343a8686033d5995f1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 4 Aug 2020 19:50:36 +0100 Subject: [PATCH 304/711] Properly deprecate colors.rgb8 --- illuaminate.sexp | 3 +++ src/main/resources/data/computercraft/lua/rom/apis/colors.lua | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index 2c2ebdc84..d28a3fd44 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -101,6 +101,9 @@ (linters -doc:unresolved-reference)) (at /src/test/resources/test-rom + ; We should still be able to test deprecated members. + (linters -var:deprecated) + (lint (globals :max sleep write diff --git a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua index b821c38d3..a941fa287 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua @@ -181,9 +181,6 @@ end --- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many -- arguments it receives. -- --- **Note:** This function is deprecated, and it is recommended you use the --- specific pack/unpack function directly. --- -- @tparam[1] number r The red channel, as an argument to @{colors.packRGB}. -- @tparam[1] number g The green channel, as an argument to @{colors.packRGB}. -- @tparam[1] number b The blue channel, as an argument to @{colors.packRGB}. @@ -192,6 +189,7 @@ end -- @treturn[2] number The red channel, as returned by @{colors.unpackRGB} -- @treturn[2] number The green channel, as returned by @{colors.unpackRGB} -- @treturn[2] number The blue channel, as returned by @{colors.unpackRGB} +-- @deprecated Use @{packRGB} or @{unpackRGB} directly. -- @usage -- ```lua -- colors.rgb(0xb23399) From e8e2ed9fe521b4b420c5eb93190fa3f1f6f58686 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 9 Aug 2020 21:50:58 +0100 Subject: [PATCH 305/711] Fix incorrect lower bound in mods.toml It appears I had failed to update this when last bumping the Forge version. Closes #521 - we're relying on a feature only added in Forge 31.1.16, and they're using 3.1.14. --- src/main/resources/META-INF/mods.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 94b6f2073..451828625 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -19,6 +19,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[31.0.13,32)" + versionRange="[31.1.41,32)" ordering="NONE" side="BOTH" From 99581e1f408ccc2057a464d1b749fe4e77e989b9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 14 Aug 2020 22:00:03 +0100 Subject: [PATCH 306/711] Initial update to 1.16.2 Seems to load fine, but not done any proper testing. --- gradle.properties | 4 ++-- .../shared/computer/blocks/BlockComputerBase.java | 10 ++++++---- .../shared/peripheral/modem/wired/BlockCable.java | 4 +--- .../peripheral/modem/wireless/BlockWirelessModem.java | 6 ++---- .../computercraft/shared/util/FakeNetHandler.java | 5 ----- src/main/resources/META-INF/accesstransformer.cfg | 3 +++ src/main/resources/META-INF/mods.toml | 5 +++-- src/main/resources/pack.mcmeta | 2 +- 8 files changed, 18 insertions(+), 21 deletions(-) diff --git a/gradle.properties b/gradle.properties index 06da4d1ae..d10123480 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.90.3 # Minecraft properties (update mods.toml when changing) -mc_version=1.16.1 -forge_version=32.0.75 +mc_version=1.16.2 +forge_version=33.0.3 mappings_version=20200723-1.16.1 diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index f990647c2..b2e20b72b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -25,6 +25,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; @@ -138,6 +139,7 @@ public abstract class BlockComputerBase extends Bloc public void onBlockHarvested( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player ) { if( !(world instanceof ServerWorld) ) return; + ServerWorld serverWorld = (ServerWorld) world; // We drop the item here instead of doing it in the harvest method, as we should // drop computers for creative players too. @@ -146,19 +148,19 @@ public abstract class BlockComputerBase extends Bloc if( tile instanceof TileComputerBase ) { TileComputerBase computer = (TileComputerBase) tile; - LootContext.Builder context = new LootContext.Builder( (ServerWorld) world ) + LootContext.Builder context = new LootContext.Builder( serverWorld ) .withRandom( world.rand ) - .withParameter( LootParameters.POSITION, pos ) + .withParameter( LootParameters.field_237457_g_, Vector3d.copyCentered( pos ) ) .withParameter( LootParameters.TOOL, player.getHeldItemMainhand() ) .withParameter( LootParameters.THIS_ENTITY, player ) - .withNullableParameter( LootParameters.BLOCK_ENTITY, tile ) + .withParameter( LootParameters.BLOCK_ENTITY, tile ) .withDynamicDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) ); for( ItemStack item : state.getDrops( context ) ) { spawnAsEntity( world, pos, item ); } - state.spawnAdditionalDrops( world, pos, player.getHeldItemMainhand() ); + state.spawnAdditionalDrops( serverWorld, pos, player.getHeldItemMainhand() ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index a9c5ea36e..99a08a5e0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -207,9 +207,7 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable Direction facing = state.get( MODEM ).getFacing(); if( facing == null ) return true; - BlockPos offsetPos = pos.offset( facing ); - BlockState offsetState = world.getBlockState( offsetPos ); - return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() ); + return hasEnoughSolidSide( world, pos.offset( facing ), facing.getOpposite() ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index 9c26780d3..531810ed8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -80,12 +80,10 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable @Override @Deprecated - public boolean isValidPosition( BlockState state, IWorldReader world, BlockPos pos ) + public boolean isValidPosition( BlockState state, @Nonnull IWorldReader world, BlockPos pos ) { Direction facing = state.get( FACING ); - BlockPos offsetPos = pos.offset( facing ); - BlockState offsetState = world.getBlockState( offsetPos ); - return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() ); + return hasEnoughSolidSide( world, pos.offset( facing ), facing.getOpposite() ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index 02fae31ab..03450d233 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -65,11 +65,6 @@ public class FakeNetHandler extends ServerPlayNetHandler { } - @Override - public void handleRecipeBookUpdate( @Nonnull CRecipeInfoPacket packet ) - { - } - @Override public void handleSeenAdvancements( @Nonnull CSeenAdvancementsPacket packet ) { diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 0db231ddd..6e87a36ff 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -2,3 +2,6 @@ public net.minecraft.client.renderer.FirstPersonRenderer func_178100_c(F)F # getMapAngleFromPitch public net.minecraft.client.renderer.FirstPersonRenderer func_228401_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;IFFLnet/minecraft/util/HandSide;)V # renderArmFirstPerson public net.minecraft.client.renderer.FirstPersonRenderer func_228403_a_(Lcom/mojang/blaze3d/matrix/MatrixStack;Lnet/minecraft/client/renderer/IRenderTypeBuffer;ILnet/minecraft/util/HandSide;)V # renderArm +# ClientTableFormatter +public net.minecraft.client.gui.NewChatGui func_146234_a(Lnet/minecraft/util/text/ITextComponent;I)V # printChatMessageWithOptionalDeletion +public net.minecraft.client.gui.NewChatGui func_146242_c(I)V # deleteChatLine diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index cf05511a0..29656100f 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[32,33)" +loaderVersion="[33,34)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -7,6 +7,7 @@ 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="computercraft" @@ -19,6 +20,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[32.0.69,33)" + versionRange="[33.0.3,34)" ordering="NONE" side="BOTH" diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index a0de516e0..59c3b8fab 100755 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 4, + "pack_format": 6, "description": "CC: Tweaked" } } From 0faf76e4bd2e2f43033984c49b0abedd8e403c24 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 22 Aug 2020 15:03:38 +0100 Subject: [PATCH 307/711] Fix if statement never being hit Let's been honest, this bit's probably never been tested, because it should never happen. Fixes #528. --- .../core/computer/ComputerThread.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java index ed6a903cb..66ea9e644 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java @@ -395,14 +395,7 @@ public final class ComputerThread executor.timeout.hardAbort(); executor.abort(); - if( afterHardAbort >= ABORT_TIMEOUT ) - { - // If we've hard aborted but we're still not dead, dump the stack trace and interrupt - // the task. - timeoutTask( executor, runner.owner, afterStart ); - runner.owner.interrupt(); - } - else if( afterHardAbort >= ABORT_TIMEOUT * 2 ) + if( afterHardAbort >= ABORT_TIMEOUT * 2 ) { // If we've hard aborted and interrupted, and we're still not dead, then mark the runner // as dead, finish off the task, and spawn a new runner. @@ -421,6 +414,13 @@ public final class ComputerThread } } } + else if( afterHardAbort >= ABORT_TIMEOUT ) + { + // If we've hard aborted but we're still not dead, dump the stack trace and interrupt + // the task. + timeoutTask( executor, runner.owner, afterStart ); + runner.owner.interrupt(); + } } } } From d5de39ebd47c6ec472104a0d8e72f4ec4516f3d5 Mon Sep 17 00:00:00 2001 From: R93950X <39017175+R93950X@users.noreply.github.com> Date: Sat, 22 Aug 2020 07:17:12 -0700 Subject: [PATCH 308/711] Fix time formatting (#527) Fixes #525. Co-authored-by: R93950X --- .../data/computercraft/lua/rom/apis/textutils.lua | 2 +- .../resources/test-rom/spec/apis/textutils_spec.lua | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 0f191e522..40de6924b 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -77,7 +77,7 @@ function formatTime(nTime, bTwentyFourHour) local nHour = math.floor(nTime) local nMinute = math.floor((nTime - nHour) * 60) if sTOD then - return string.format("%d:%02d %s", nHour, nMinute, sTOD) + return string.format("%d:%02d %s", nHour == 0 and 12 or nHour, nMinute, sTOD) else return string.format("%d:%02d", nHour, nMinute) end diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index d60d30f47..e83746ecf 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -12,6 +12,14 @@ describe("The textutils library", function() expect.error(textutils.formatTime, nil):eq("bad argument #1 (expected number, got nil)") expect.error(textutils.formatTime, 1, 1):eq("bad argument #2 (expected boolean, got number)") end) + + it("correctly formats 12 o'clock", function() + expect(textutils.formatTime(0, false)):eq("12:00 AM") + expect(textutils.formatTime(0.1, false)):eq("12:06 AM") + + expect(textutils.formatTime(0, true)):eq("0:00") + expect(textutils.formatTime(0.1, true)):eq("0:06") + end) end) describe("textutils.pagedPrint", function() @@ -49,7 +57,7 @@ describe("The textutils library", function() describe("textutils.empty_json_array", function() it("is immutable", function() expect.error(function() textutils.empty_json_array[1] = true end) - :str_match("^[^:]+:51: attempt to mutate textutils.empty_json_array$") + :str_match("^[^:]+:%d+: attempt to mutate textutils.empty_json_array$") end) end) From 29fb0baa09055653818c7e55be8138528ba1bc4c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 22 Aug 2020 15:31:48 +0100 Subject: [PATCH 309/711] Use Forge's packet methods for sending SoundEvents Doesn't fix #515 (arguably makes it worse in the sense that it's more likely to throw). However it should provide better error reporting, and make it more clear that it's not CC:T's fault. --- .../shared/network/client/PlayRecordClientMessage.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index 9ba8d2021..ce1851c85 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -13,10 +13,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkEvent; -import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; -import java.util.Objects; /** * Starts or stops a record on the client, depending on if {@link #soundEvent} is {@code null}. @@ -51,7 +49,7 @@ public class PlayRecordClientMessage implements NetworkMessage if( buf.readBoolean() ) { name = buf.readString( Short.MAX_VALUE ); - soundEvent = ForgeRegistries.SOUND_EVENTS.getValue( buf.readResourceLocation() ); + soundEvent = buf.readRegistryIdSafe( SoundEvent.class ); } else { @@ -72,7 +70,7 @@ public class PlayRecordClientMessage implements NetworkMessage { buf.writeBoolean( true ); buf.writeString( name ); - buf.writeResourceLocation( Objects.requireNonNull( soundEvent.getRegistryName(), "Sound is not registered" ) ); + buf.writeRegistryId( soundEvent ); } } From 9acfc0316fdb13b81bb4b63233d2db21f8a29ccd Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 22 Aug 2020 16:09:35 +0100 Subject: [PATCH 310/711] Expose NBT hashes of items to users This just uses the same approach as Plethora, so we should have aparity for .list() now. --- .../peripheral/generic/data/ItemData.java | 22 +++++++- .../shared/turtle/apis/TurtleAPI.java | 2 +- .../computercraft/shared/util/NBTUtil.java | 52 +++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 1a422487e..a2a39f599 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -7,6 +7,8 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.item.EnchantedBookItem; @@ -22,13 +24,29 @@ import javax.annotation.Nullable; import java.util.*; import java.util.stream.Collectors; +/** + * Data providers for items. + * + * We guard using {@link ComputerCraft#genericPeripheral} in several places, as advanced functionality should not be + * exposed for {@code turtle.getItemDetail} when generic peripehrals are disabled. + */ public class ItemData { @Nonnull - public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) + public static > T fillBasicSafe( @Nonnull T data, @Nonnull ItemStack stack ) { data.put( "name", DataHelpers.getId( stack.getItem() ) ); data.put( "count", stack.getCount() ); + + return data; + } + + @Nonnull + public static > T fillBasic( @Nonnull T data, @Nonnull ItemStack stack ) + { + fillBasicSafe( data, stack ); + String hash = NBTUtil.getNBTHash( stack.getTag() ); + if( hash != null ) data.put( "nbt", hash ); return data; } @@ -55,6 +73,8 @@ public class ItemData data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) ); + if( !ComputerCraft.genericPeripheral ) return data; + CompoundNBT tag = stack.getTag(); if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) ) { diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 260c9423f..57040804c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -605,7 +605,7 @@ public class TurtleAPI implements ILuaAPI Map table = detailed ? ItemData.fill( new HashMap<>(), stack ) - : ItemData.fillBasic( new HashMap<>(), stack ); + : ItemData.fillBasicSafe( new HashMap<>(), stack ); TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table, detailed ); if( MinecraftForge.EVENT_BUS.post( event ) ) return new Object[] { false, event.getFailureMessage() }; diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 4f4b9cfba..006effe07 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -5,9 +5,19 @@ */ package dan200.computercraft.shared.util; +import dan200.computercraft.ComputerCraft; import net.minecraft.nbt.*; import net.minecraftforge.common.util.Constants; +import org.apache.commons.codec.binary.Hex; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; @@ -159,4 +169,46 @@ public final class NBTUtil } return objects; } + + @Nullable + public static String getNBTHash( @Nullable CompoundNBT tag ) + { + if( tag == null ) return null; + + try + { + MessageDigest digest = MessageDigest.getInstance( "MD5" ); + DataOutput output = new DataOutputStream( new DigestOutputStream( digest ) ); + CompressedStreamTools.write( tag, output ); + byte[] hash = digest.digest(); + return new String( Hex.encodeHex( hash ) ); + } + catch( NoSuchAlgorithmException | IOException e ) + { + ComputerCraft.log.error( "Cannot hash NBT", e ); + return null; + } + } + + private static class DigestOutputStream extends OutputStream + { + private final MessageDigest digest; + + private DigestOutputStream( MessageDigest digest ) + { + this.digest = digest; + } + + @Override + public void write( @Nonnull byte[] b, int off, int len ) + { + digest.update( b, off, len ); + } + + @Override + public void write( int b ) + { + digest.update( (byte) b ); + } + } } From e8e9294fdf45bfbad372953bb2b7924044c21c2a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 22 Aug 2020 19:28:02 +0100 Subject: [PATCH 311/711] Correctly check for success or consume No, I don't really know what the difference is either :). Closes #518. --- .../shared/turtle/core/TurtlePlaceCommand.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 69b903cba..a400a2b50 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -238,7 +238,7 @@ public class TurtlePlaceCommand implements ITurtleCommand cancelResult = hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, Hand.MAIN_HAND ); } - if( cancelResult == ActionResultType.SUCCESS ) + if( cancelResult.isSuccessOrConsume() ) { placed = true; } @@ -246,7 +246,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { // See EntityPlayer.interactOn cancelResult = ForgeHooks.onInteractEntity( turtlePlayer, hitEntity, Hand.MAIN_HAND ); - if( cancelResult == ActionResultType.SUCCESS ) + if( cancelResult.isSuccessOrConsume() ) { placed = true; } @@ -353,17 +353,15 @@ public class TurtlePlaceCommand implements ITurtleCommand TileEntity existingTile = turtle.getWorld().getTileEntity( position ); // See PlayerInteractionManager.processRightClickBlock - // TODO: ^ Check we're still consistent. PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, Hand.MAIN_HAND, position, side ); if( !event.isCanceled() ) { - if( item.onItemUseFirst( stack, context ) == ActionResultType.SUCCESS ) + if( item.onItemUseFirst( stack, context ).isSuccessOrConsume() ) { placed = true; turtlePlayer.loadInventory( stackCopy ); } - else if( event.getUseItem() != Event.Result.DENY && - stackCopy.onItemUse( context ) == ActionResultType.SUCCESS ) + else if( event.getUseItem() != Event.Result.DENY && stackCopy.onItemUse( context ).isSuccessOrConsume() ) { placed = true; turtlePlayer.loadInventory( stackCopy ); @@ -373,14 +371,14 @@ public class TurtlePlaceCommand implements ITurtleCommand if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem) ) { ActionResultType actionResult = ForgeHooks.onItemRightClick( turtlePlayer, Hand.MAIN_HAND ); - if( actionResult == ActionResultType.SUCCESS ) + if( actionResult != null && actionResult.isSuccessOrConsume() ) { placed = true; } else if( actionResult == null ) { ActionResult result = stackCopy.useItemRightClick( turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND ); - if( result.getType() == ActionResultType.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) ) + if( result.getType().isSuccessOrConsume() && !ItemStack.areItemStacksEqual( stack, result.getResult() ) ) { placed = true; turtlePlayer.loadInventory( result.getResult() ); From 0bb5515055441e891adc133f4864a81dfde260ac Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 22 Aug 2020 19:31:49 +0100 Subject: [PATCH 312/711] Fix checkstyle problems --- src/main/java/dan200/computercraft/shared/util/NBTUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 006effe07..97879a497 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -190,11 +190,11 @@ public final class NBTUtil } } - private static class DigestOutputStream extends OutputStream + private static final class DigestOutputStream extends OutputStream { private final MessageDigest digest; - private DigestOutputStream( MessageDigest digest ) + DigestOutputStream( MessageDigest digest ) { this.digest = digest; } From 183b34207197df7118a751fb333efbe969a21ba1 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 23 Aug 2020 15:35:58 +0100 Subject: [PATCH 313/711] Bump for 1.91.0 --- gradle.properties | 2 +- .../computercraft/core/lua/VarargArguments.java | 8 ++++---- .../data/computercraft/lua/rom/help/changelog.txt | 12 ++++++++++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 12 ++++++++++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index 106c54e9c..6a2a622b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.90.2 +mod_version=1.91.0 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/java/dan200/computercraft/core/lua/VarargArguments.java b/src/main/java/dan200/computercraft/core/lua/VarargArguments.java index 4ad8d58a4..cedba0a80 100644 --- a/src/main/java/dan200/computercraft/core/lua/VarargArguments.java +++ b/src/main/java/dan200/computercraft/core/lua/VarargArguments.java @@ -83,9 +83,9 @@ class VarargArguments implements IArguments public ByteBuffer getBytes( int index ) throws LuaException { LuaValue value = varargs.arg( index + 1 ); - if( !(value instanceof LuaString) ) throw LuaValues.badArgument( index, "string", value.typeName() ); + if( !(value instanceof LuaBaseString) ) throw LuaValues.badArgument( index, "string", value.typeName() ); - LuaString str = (LuaString) value; + LuaString str = ((LuaBaseString) value).strvalue(); return ByteBuffer.wrap( str.bytes, str.offset, str.length ).asReadOnlyBuffer(); } @@ -94,9 +94,9 @@ class VarargArguments implements IArguments { LuaValue value = varargs.arg( index + 1 ); if( value.isNil() ) return Optional.empty(); - if( !(value instanceof LuaString) ) throw LuaValues.badArgument( index, "string", value.typeName() ); + if( !(value instanceof LuaBaseString) ) throw LuaValues.badArgument( index, "string", value.typeName() ); - LuaString str = (LuaString) value; + LuaString str = ((LuaBaseString) value).strvalue(); return Optional.of( ByteBuffer.wrap( str.bytes, str.offset, str.length ).asReadOnlyBuffer() ); } } diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 08e8327a3..fbb88d766 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,15 @@ +# New features in CC: Tweaked 1.91.0 + +* [Generic peripherals] Expose NBT hashes of items to inventory methods. +* Bump Cobalt version + * Optimise handling of string concatenation. + * Add string.{pack,unpack,packsize} (MCJack123) + +And several bug fixes: +* Escape non-ASCII characters in JSON strings (neumond) +* Make field names in fs.attributes more consistent (abby) +* Fix textutils.formatTime correctly handle 12 AM (R93950X) + # New features in CC: Tweaked 1.90.2 * Fix generic peripherals not being registered outside a dev environment. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 8135e4db6..1ad4527c2 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,5 +1,13 @@ -New features in CC: Tweaked 1.90.2 +New features in CC: Tweaked 1.91.0 -* Fix generic peripherals not being registered outside a dev environment. +* [Generic peripherals] Expose NBT hashes of items to inventory methods. +* Bump Cobalt version + * Optimise handling of string concatenation. + * Add string.{pack,unpack,packsize} (MCJack123) + +And several bug fixes: +* Escape non-ASCII characters in JSON strings (neumond) +* Make field names in fs.attributes more consistent (abby) +* Fix textutils.formatTime correctly handle 12 AM (R93950X) Type "help changelog" to see the full version history. From 74b9f5dcb0a2f441d87212af9fe0ce6d282ba7cf Mon Sep 17 00:00:00 2001 From: Bluenaxela Date: Mon, 24 Aug 2020 23:55:24 -0700 Subject: [PATCH 314/711] Fix FileSystemWrapperMount.isDirectory() Pretty sure FileSystemWrapperMount.isDirectory() should call Filesystem.isDir(), not Filesystem.exists() --- .../computercraft/core/filesystem/FileSystemWrapperMount.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java index 40e4634d8..f22e33654 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java @@ -124,7 +124,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.exists( path ); + return m_filesystem.isDir( path ); } catch( FileSystemException e ) { From 2c67849b354832ac32fc59b08db21c08699aadbf Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 27 Aug 2020 17:17:03 +0100 Subject: [PATCH 315/711] Fix NPE when turtles interact with an entity Closes #531 --- .../computercraft/shared/turtle/core/TurtlePlaceCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index a400a2b50..b47a17a66 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -246,7 +246,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { // See EntityPlayer.interactOn cancelResult = ForgeHooks.onInteractEntity( turtlePlayer, hitEntity, Hand.MAIN_HAND ); - if( cancelResult.isSuccessOrConsume() ) + if( cancelResult != null && cancelResult.isSuccessOrConsume() ) { placed = true; } From 26c12ac1a93692f027b3436b529a42c00176864c Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 4 Sep 2020 17:29:35 +0100 Subject: [PATCH 316/711] Bump version to 1.91.1 --- gradle.properties | 4 ++-- .../data/computercraft/lua/rom/help/changelog.txt | 4 ++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 14 ++------------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/gradle.properties b/gradle.properties index c48ee33c5..dc94a1f3d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # Mod properties -mod_version=1.91.0 +mod_version=1.91.1 # Minecraft properties (update mods.toml when changing) mc_version=1.16.2 -forge_version=33.0.20 +forge_version=33.0.37 mappings_version=20200723-1.16.1 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 38cdcdd99..23584df62 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,7 @@ +# New features in CC: Tweaked 1.91.1 + +* Fix crash when turtles interact with an entity. + # New features in CC: Tweaked 1.91.0 * [Generic peripherals] Expose NBT hashes of items to inventory methods. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index aac3f89de..2b24ff7ee 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,15 +1,5 @@ -New features in CC: Tweaked 1.91.0 +New features in CC: Tweaked 1.91.1 -* [Generic peripherals] Expose NBT hashes of items to inventory methods. -* Bump Cobalt version - * Optimise handling of string concatenation. - * Add string.{pack,unpack,packsize} (MCJack123) -* Update to 1.16.2 - -And several bug fixes: -* Escape non-ASCII characters in JSON strings (neumond) -* Make field names in fs.attributes more consistent (abby) -* Fix textutils.formatTime correctly handle 12 AM (R93950X) -* Fix turtles placing buckets multiple times. +* Fix crash when turtles interact with an entity. Type "help changelog" to see the full version history. From d5368d07194106ccad407f09e1838cf91faeffe3 Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Fri, 4 Sep 2020 12:35:46 -0400 Subject: [PATCH 317/711] Add date-specific MOTDs (like Minecraft) (#533) --- .../computercraft/lua/rom/programs/motd.lua | 29 ++++++++++++------- .../test-rom/spec/programs/motd_spec.lua | 28 ++++++++++++++++-- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua index c8c75a40b..57ab7b916 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua @@ -1,15 +1,24 @@ -local tMotd = {} +local date = os.date("*t") +if date.month == 1 and date.day == 1 then + print("Happy new year!") +elseif date.month == 12 and date.day == 24 then + print("Merry X-mas!") +elseif date.month == 10 and date.day == 31 then + print("OOoooOOOoooo! Spooky!") +else + local tMotd = {} -for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do - if fs.exists(sPath) then - for sLine in io.lines(sPath) do - table.insert(tMotd, sLine) + for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do + if fs.exists(sPath) then + for sLine in io.lines(sPath) do + table.insert(tMotd, sLine) + end end end -end -if #tMotd == 0 then - print("missingno") -else - print(tMotd[math.random(1, #tMotd)]) + if #tMotd == 0 then + print("missingno") + else + print(tMotd[math.random(1, #tMotd)]) + end end diff --git a/src/test/resources/test-rom/spec/programs/motd_spec.lua b/src/test/resources/test-rom/spec/programs/motd_spec.lua index 72becbf30..d426fb6e7 100644 --- a/src/test/resources/test-rom/spec/programs/motd_spec.lua +++ b/src/test/resources/test-rom/spec/programs/motd_spec.lua @@ -1,14 +1,36 @@ local capture = require "test_helpers".capture_program describe("The motd program", function() + local function setup_date(month, day) + stub(os, "date", function() return { month = month, day = day } end) + end - it("displays MODT", function() - local file = fs.open("/modt_check.txt", "w") + it("displays MOTD", function() + setup_date(0, 0) + local file = fs.open("/motd_check.txt", "w") file.write("Hello World!") file.close() - settings.set("motd.path", "/modt_check.txt") + settings.set("motd.path", "/motd_check.txt") expect(capture(stub, "motd")) :matches { ok = true, output = "Hello World!\n", error = "" } end) + + it("displays date-specific MOTD (1/1)", function() + setup_date(1, 1) + expect(capture(stub, "motd")) + :matches { ok = true, output = "Happy new year!\n", error = "" } + end) + + it("displays date-specific MOTD (10/31)", function() + setup_date(10, 31) + expect(capture(stub, "motd")) + :matches { ok = true, output = "OOoooOOOoooo! Spooky!\n", error = "" } + end) + + it("displays date-specific MOTD (12/24)", function() + setup_date(12, 24) + expect(capture(stub, "motd")) + :matches { ok = true, output = "Merry X-mas!\n", error = "" } + end) end) From 73657410888ba9fadcbeae67c3180c99aee62f9a Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 5 Sep 2020 10:59:39 +0100 Subject: [PATCH 318/711] Don't use entity.captureDrops at all. This really should have been removed in 9e2232d24045af46b57162f3c3213e622e67bfe9. Otherwise we don't drop these items into the world at all. Fixes #537. --- .../java/dan200/computercraft/shared/util/DropConsumer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 14200f0eb..477ad73de 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -42,8 +42,6 @@ public final class DropConsumer dropEntity = entity; dropWorld = entity.world; dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 ); - - entity.captureDrops( new ArrayList<>() ); } public static void set( World world, BlockPos pos, Function consumer ) @@ -86,7 +84,7 @@ public final class DropConsumer } } - @SubscribeEvent + @SubscribeEvent( priority = EventPriority.LOW ) public static void onLivingDrops( LivingDropsEvent drops ) { if( dropEntity == null || drops.getEntity() != dropEntity ) return; From 5155e18de279a193c558aa029963486fd1294769 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 7 Sep 2020 03:33:36 +0000 Subject: [PATCH 319/711] Added translation for Vietnamese Co-authored-by: Boom --- src/main/resources/assets/computercraft/lang/vi.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/main/resources/assets/computercraft/lang/vi.json diff --git a/src/main/resources/assets/computercraft/lang/vi.json b/src/main/resources/assets/computercraft/lang/vi.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/src/main/resources/assets/computercraft/lang/vi.json @@ -0,0 +1 @@ +{} From 7e121ff72f2b1504cd6af47b57500876682bac45 Mon Sep 17 00:00:00 2001 From: Weblate Date: Mon, 7 Sep 2020 06:37:58 +0000 Subject: [PATCH 320/711] Translations for Vietnamese Co-authored-by: Boom --- .../assets/computercraft/lang/vi.json | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lang/vi.json b/src/main/resources/assets/computercraft/lang/vi.json index 0967ef424..3983a91ae 100644 --- a/src/main/resources/assets/computercraft/lang/vi.json +++ b/src/main/resources/assets/computercraft/lang/vi.json @@ -1 +1,39 @@ -{} +{ + "gui.computercraft.tooltip.disk_id": "ID đĩa: %s", + "upgrade.computercraft.speaker.adjective": "á»’n ào", + "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", + "upgrade.computercraft.wireless_modem_normal.adjective": "Không dây", + "upgrade.minecraft.crafting_table.adjective": "Chế tạo", + "upgrade.minecraft.diamond_hoe.adjective": "Trồng trá»t", + "upgrade.minecraft.diamond_axe.adjective": "Äốn", + "upgrade.minecraft.diamond_pickaxe.adjective": "Khai thác", + "upgrade.minecraft.diamond_shovel.adjective": "Äào", + "item.computercraft.pocket_computer_advanced.upgraded": "Máy tính bá» túi tiên tiến %s", + "item.computercraft.pocket_computer_advanced": "Máy tính bá» túi tiên tiến", + "item.computercraft.pocket_computer_normal.upgraded": "Máy tính bá» túi %s", + "item.computercraft.pocket_computer_normal": "Máy tính bá» túi", + "item.computercraft.printed_book": "Sách in", + "item.computercraft.printed_page": "Trang in", + "item.computercraft.treasure_disk": "ÄÄ©a má»m", + "item.computercraft.disk": "ÄÄ©a má»m", + "block.computercraft.turtle_advanced.upgraded_twice": "Rùa tiên tiến %s %s", + "block.computercraft.turtle_advanced.upgraded": "Rùa tiên tiến %s", + "block.computercraft.turtle_advanced": "Rùa tiên tiến", + "block.computercraft.turtle_normal.upgraded_twice": "Rùa %s %s", + "block.computercraft.turtle_normal.upgraded": "Rùa %s", + "block.computercraft.turtle_normal": "Rùa", + "block.computercraft.wired_modem_full": "Modem có dây", + "block.computercraft.cable": "Dây cáp mạng", + "block.computercraft.wired_modem": "Modem có dây", + "block.computercraft.wireless_modem_advanced": "Modem Ender", + "block.computercraft.wireless_modem_normal": "Modem không dây", + "block.computercraft.monitor_advanced": "Màn hình tiên tiếng", + "block.computercraft.monitor_normal": "Màn hình", + "block.computercraft.speaker": "Loa", + "block.computercraft.printer": "Máy in", + "block.computercraft.disk_drive": "á»– đĩa", + "block.computercraft.computer_command": "Máy tính Ä‘iá»u khiển", + "block.computercraft.computer_normal": "Máy tính", + "itemGroup.computercraft": "ComputerCraft", + "block.computercraft.computer_advanced": "Máy tính tiên tiến" +} From ae6124d1f477487abab1858abde8c4ec49dfee3c Mon Sep 17 00:00:00 2001 From: Weblate Date: Tue, 8 Sep 2020 03:57:52 +0000 Subject: [PATCH 321/711] Translations for Vietnamese Co-authored-by: Boom --- .../resources/assets/computercraft/lang/vi.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/resources/assets/computercraft/lang/vi.json b/src/main/resources/assets/computercraft/lang/vi.json index 3983a91ae..b4261b8cb 100644 --- a/src/main/resources/assets/computercraft/lang/vi.json +++ b/src/main/resources/assets/computercraft/lang/vi.json @@ -1,5 +1,5 @@ { - "gui.computercraft.tooltip.disk_id": "ID đĩa: %s", + "gui.computercraft.tooltip.disk_id": "ID cá»§a đĩa: %s", "upgrade.computercraft.speaker.adjective": "á»’n ào", "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender", "upgrade.computercraft.wireless_modem_normal.adjective": "Không dây", @@ -35,5 +35,14 @@ "block.computercraft.computer_command": "Máy tính Ä‘iá»u khiển", "block.computercraft.computer_normal": "Máy tính", "itemGroup.computercraft": "ComputerCraft", - "block.computercraft.computer_advanced": "Máy tính tiên tiến" + "block.computercraft.computer_advanced": "Máy tính tiên tiến", + "tracking_field.computercraft.websocket_incoming.name": "Websocket đến", + "tracking_field.computercraft.websocket_outgoing.name": "Websocket Ä‘i", + "gui.computercraft.tooltip.computer_id": "ID cá»§a máy tính: %s", + "tracking_field.computercraft.coroutines_dead.name": "Coroutine bá» Ä‘i", + "tracking_field.computercraft.coroutines_created.name": "Coroutine đã tạo", + "tracking_field.computercraft.http_download.name": "HTTP tải xuống", + "tracking_field.computercraft.http_upload.name": "HTTP tải lên", + "tracking_field.computercraft.http.name": "Yêu cầu HTTP", + "gui.computercraft.tooltip.copy": "Sao chép vào clipboard" } From cefde3f0037925ed59c531305986163f1cde8530 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 8 Sep 2020 18:11:20 +0100 Subject: [PATCH 322/711] Also block 0.0.0.0/8 See MightyPirates/OpenComputers#3356 --- src/main/java/dan200/computercraft/ComputerCraft.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 6a833d0fb..ab89ba49d 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -39,6 +39,7 @@ public final class ComputerCraft public static final String[] DEFAULT_HTTP_ALLOW = new String[] { "*" }; public static final String[] DEFAULT_HTTP_DENY = new String[] { "127.0.0.0/8", + "0.0.0.0/8", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", From 37f925de0a48478cc24d42f39bb9431d49e6dbee Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 8 Sep 2020 18:37:40 +0100 Subject: [PATCH 323/711] Remove references to cc.crzd.me's maven As CC only exists on 1.12.2, it's a bit meaningless to talk about it on 1.15+! --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bab8a02e7..71692f985 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,9 @@ I'd generally recommend you don't contact me directly (email, DM, etc...) unless report exploits). You'll get a far quicker response if you ask the whole community! ## Using -If you want to depend on CC: Tweaked, we have a maven repo. However, you should be wary that some functionality is only -exposed by CC:T's API and not vanilla ComputerCraft. If you wish to support all variations of ComputerCraft, I recommend -using [cc.crzd.me's maven](https://cc.crzd.me/maven/) instead. +CC: Tweaked is hosted on my maven repo, and so is relatively simple to depend on. You may wish to add a soft (or hard) +dependency in your `mods.toml` file, with the appropriate version bounds, to ensure that API functionality you depend +on is present. ```groovy dependencies { From 50473afea88421871ab0a7f8b08ecbe710fc1345 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 9 Sep 2020 08:39:28 +0100 Subject: [PATCH 324/711] Fix Gradle example for depending on CC:T See #405 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71692f985..d344fb157 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ dependency in your `mods.toml` file, with the appropriate version bounds, to ens on is present. ```groovy -dependencies { +repositories { maven { url 'https://squiddev.cc/maven/' } } From 59de21eae29849988e77fad6bc335f5ce78dfec7 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 11 Sep 2020 18:02:23 +0100 Subject: [PATCH 325/711] Handle tabs when parsing JSON Fixes #539 --- .../resources/data/computercraft/lua/rom/apis/textutils.lua | 4 ++-- .../test-rom/data/json-parsing/y_tab_whitespace.json | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 40de6924b..576c6755e 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -432,7 +432,7 @@ do --- Skip any whitespace local function skip(str, pos) - local _, last = find(str, "^[ \n\r\v]+", pos) + local _, last = find(str, "^[ \n\r\t]+", pos) if last then return last + 1 else return pos end end @@ -472,7 +472,7 @@ do buf[n], n, pos = utf8.char(tonumber(num_str, 16)), n + 1, pos + 6 else local unesc = escapes[c] - if not unesc then error_at(pos + 1, "Unknown escape character %q.", unesc) end + if not unesc then error_at(pos + 1, "Unknown escape character %q.", c) end buf[n], n, pos = unesc, n + 1, pos + 2 end elseif c >= '\x20' then diff --git a/src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json b/src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json new file mode 100644 index 000000000..d9a9c8b4d --- /dev/null +++ b/src/test/resources/test-rom/data/json-parsing/y_tab_whitespace.json @@ -0,0 +1 @@ +[ ] From 748ebbe66bf0a4239bde34f557e4b4b75d61d990 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 12 Sep 2020 09:27:47 +0100 Subject: [PATCH 326/711] Bump to 1.92.0 A tiny release, but there's new features so it's technically a minor bump. --- gradle.properties | 2 +- .../data/computercraft/lua/rom/help/changelog.txt | 11 +++++++++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 15 +++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index 6a2a622b9..2e9a93b9f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.91.0 +mod_version=1.92.0 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index fbb88d766..38cc9f6dd 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,14 @@ +# New features in CC: Tweaked 1.92.0 + +* Bump Cobalt version: + * Add support for the __pairs metamethod. + * string.format now uses the __tostring metamethod. +* Add date-specific MOTDs (MCJack123). + +And several bug fixes: +* Correctly handle tabs within textutils.unserailizeJSON. +* Fix sheep not dropping items when sheered by turtles. + # New features in CC: Tweaked 1.91.0 * [Generic peripherals] Expose NBT hashes of items to inventory methods. diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 1ad4527c2..9a79e5602 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,13 +1,12 @@ -New features in CC: Tweaked 1.91.0 +New features in CC: Tweaked 1.92.0 -* [Generic peripherals] Expose NBT hashes of items to inventory methods. -* Bump Cobalt version - * Optimise handling of string concatenation. - * Add string.{pack,unpack,packsize} (MCJack123) +* Bump Cobalt version: + * Add support for the __pairs metamethod. + * string.format now uses the __tostring metamethod. +* Add date-specific MOTDs (MCJack123). And several bug fixes: -* Escape non-ASCII characters in JSON strings (neumond) -* Make field names in fs.attributes more consistent (abby) -* Fix textutils.formatTime correctly handle 12 AM (R93950X) +* Correctly handle tabs within textutils.unserailizeJSON. +* Fix sheep not dropping items when sheered by turtles. Type "help changelog" to see the full version history. From 8b4a01df27ff7f6fa9ffd9c2188c6e3166edd515 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 12 Sep 2020 10:45:59 +0100 Subject: [PATCH 327/711] Update to Minecraft 1.16.3 I hope the Fabric folks now realise this is gonna be a race of who can update first :p. Either way, this was a very easy update - only changes were due to unrelated Forge changes. --- gradle.properties | 4 ++-- src/main/java/dan200/computercraft/data/Generators.java | 3 +-- src/main/java/dan200/computercraft/data/Tags.java | 5 +++-- src/main/resources/META-INF/mods.toml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gradle.properties b/gradle.properties index 53c207977..e2da35a53 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,6 +2,6 @@ mod_version=1.92.0 # Minecraft properties (update mods.toml when changing) -mc_version=1.16.2 -forge_version=33.0.37 +mc_version=1.16.3 +forge_version=34.0.1 mappings_version=20200723-1.16.1 diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java index 6fb250c19..f95de8086 100644 --- a/src/main/java/dan200/computercraft/data/Generators.java +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -7,7 +7,6 @@ package dan200.computercraft.data; import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; -import net.minecraft.data.BlockTagsProvider; import net.minecraft.data.DataGenerator; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -24,6 +23,6 @@ public class Generators DataGenerator generator = event.getGenerator(); generator.addProvider( new Recipes( generator ) ); generator.addProvider( new LootTables( generator ) ); - generator.addProvider( new Tags( generator, new BlockTagsProvider( generator ) ) ); + generator.addProvider( new Tags( generator, event.getExistingFileHelper() ) ); } } diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java index 587c1b506..1dc5692d2 100644 --- a/src/main/java/dan200/computercraft/data/Tags.java +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -15,6 +15,7 @@ import net.minecraft.item.Item; import net.minecraft.tags.ITag; import net.minecraft.tags.ItemTags; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.data.ExistingFileHelper; import static dan200.computercraft.data.Tags.CCTags.*; @@ -30,9 +31,9 @@ public class Tags extends ItemTagsProvider public static final ITag.INamedTag MONITOR = item( "monitor" ); } - public Tags( DataGenerator generator, BlockTagsProvider tags ) + public Tags( DataGenerator generator, ExistingFileHelper helper ) { - super( generator, tags ); + super( generator, new BlockTagsProvider( generator, ComputerCraft.MOD_ID, helper ), ComputerCraft.MOD_ID, helper ); } @Override diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 2c02b708a..200610b0a 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[33,34)" +loaderVersion="[34,35)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -20,6 +20,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[33.0.20,34)" + versionRange="[34.0.1,35)" ordering="NONE" side="BOTH" From 72c1d451fe63bfa756a5dbadd99f28dae27b5f1f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 12 Sep 2020 10:47:19 +0100 Subject: [PATCH 328/711] Mark the release as beta-quality --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1463198dd..9e46d21c3 100644 --- a/build.gradle +++ b/build.gradle @@ -409,7 +409,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'alpha' + releaseType = 'beta' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { From 86bf57e3cd4114cc8ed003fde318064fdfc316bd Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 12 Sep 2020 11:03:18 +0100 Subject: [PATCH 329/711] My inability to spell will be immortalsied in the changelog --- .../resources/data/computercraft/lua/rom/help/changelog.txt | 2 +- src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 38cc9f6dd..0c381c83d 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -7,7 +7,7 @@ And several bug fixes: * Correctly handle tabs within textutils.unserailizeJSON. -* Fix sheep not dropping items when sheered by turtles. +* Fix sheep not dropping items when sheared by turtles. # New features in CC: Tweaked 1.91.0 diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 9a79e5602..099b912c1 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -7,6 +7,6 @@ New features in CC: Tweaked 1.92.0 And several bug fixes: * Correctly handle tabs within textutils.unserailizeJSON. -* Fix sheep not dropping items when sheered by turtles. +* Fix sheep not dropping items when sheared by turtles. Type "help changelog" to see the full version history. From 87393e8aef9ddfaca465d626ee7cff5ff499a7e8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 13 Sep 2020 17:56:12 +0100 Subject: [PATCH 330/711] Fix additional `-` in docs Why isn't this automatically stripped! Bad squid. --- src/main/resources/data/computercraft/lua/rom/apis/window.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/window.lua b/src/main/resources/data/computercraft/lua/rom/apis/window.lua index d93533f03..ec112a991 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/window.lua @@ -440,7 +440,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end --- Get the buffered contents of a line in this window. - --- + -- -- @tparam number y The y position of the line to get. -- @treturn string The textual content of this line. -- @treturn string The text colours of this line, suitable for use with @{term.blit}. From 275ca58a82c627128a145a8754cbe32568536bd9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 15 Sep 2020 22:05:27 +0100 Subject: [PATCH 331/711] HTTP rules now allow filtering by port The HTTP filtering system becomes even more complex! Though in this case, it's pretty minimal, and definitely worth doing. For instance, the following rule will allow connecting to localhost on port :8080. [[http.rules]] host = "127.0.0.1" port = 8080 action = "allow" # Other rules as before. Closes #540 --- .../dan200/computercraft/ComputerCraft.java | 4 +-- .../core/apis/http/CheckUrl.java | 9 ++--- .../core/apis/http/NetworkUtils.java | 18 +++++++++- .../core/apis/http/options/AddressRule.java | 26 +++++++++----- .../apis/http/options/AddressRuleConfig.java | 7 ++-- .../core/apis/http/request/HttpRequest.java | 2 +- .../core/apis/http/websocket/Websocket.java | 3 +- .../apis/http/options/AddressRuleTest.java | 34 +++++++++++++++++++ 8 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index ab89ba49d..d31e1e41f 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -63,10 +63,10 @@ public final class ComputerCraft public static boolean httpWebsocketEnabled = true; public static List httpRules = Collections.unmodifiableList( Stream.concat( Stream.of( DEFAULT_HTTP_DENY ) - .map( x -> AddressRule.parse( x, Action.DENY.toPartial() ) ) + .map( x -> AddressRule.parse( x, null, Action.DENY.toPartial() ) ) .filter( Objects::nonNull ), Stream.of( DEFAULT_HTTP_ALLOW ) - .map( x -> AddressRule.parse( x, Action.ALLOW.toPartial() ) ) + .map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial() ) ) .filter( Objects::nonNull ) ).collect( Collectors.toList() ) ); diff --git a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java index a2b9f896d..41ddc9390 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java +++ b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java @@ -24,14 +24,14 @@ public class CheckUrl extends Resource private final IAPIEnvironment environment; private final String address; - private final String host; + private final URI uri; public CheckUrl( ResourceGroup limiter, IAPIEnvironment environment, String address, URI uri ) { super( limiter ); this.environment = environment; this.address = address; - host = uri.getHost(); + this.uri = uri; } public void run() @@ -47,8 +47,9 @@ public class CheckUrl extends Resource try { - InetSocketAddress netAddress = NetworkUtils.getAddress( host, 80, false ); - NetworkUtils.getOptions( host, netAddress ); + boolean ssl = uri.getScheme().equalsIgnoreCase( "https" ); + InetSocketAddress netAddress = NetworkUtils.getAddress( uri, ssl ); + NetworkUtils.getOptions( uri.getHost(), netAddress ); if( tryClose() ) environment.queueEvent( EVENT, address, true ); } diff --git a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java index aa2a9a6be..9dc2309a9 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -19,6 +19,7 @@ import io.netty.handler.ssl.SslContextBuilder; import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; import java.net.InetSocketAddress; +import java.net.URI; import java.security.KeyStore; import java.util.concurrent.ExecutorService; import java.util.concurrent.SynchronousQueue; @@ -99,6 +100,21 @@ public final class NetworkUtils } } + /** + * Create a {@link InetSocketAddress} from a {@link java.net.URI}. + * + * Note, this may require a DNS lookup, and so should not be executed on the main CC thread. + * + * @param uri The URI to fetch. + * @param ssl Whether to connect with SSL. This is used to find the default port if not otherwise specified. + * @return The resolved address. + * @throws HTTPRequestException If the host is not malformed. + */ + public static InetSocketAddress getAddress( URI uri, boolean ssl ) throws HTTPRequestException + { + return getAddress( uri.getHost(), uri.getPort(), ssl ); + } + /** * Create a {@link InetSocketAddress} from the resolved {@code host} and port. * @@ -128,7 +144,7 @@ public final class NetworkUtils */ public static Options getOptions( String host, InetSocketAddress address ) throws HTTPRequestException { - Options options = AddressRule.apply( ComputerCraft.httpRules, host, address.getAddress() ); + Options options = AddressRule.apply( ComputerCraft.httpRules, host, address ); if( options.action == Action.DENY ) throw new HTTPRequestException( "Domain not permitted" ); return options; } diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java index 03bf372ba..c7498f269 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java @@ -12,6 +12,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.util.regex.Pattern; /** @@ -52,17 +53,23 @@ public final class AddressRule private final HostRange ip; private final Pattern domainPattern; + private final Integer port; private final PartialOptions partial; - private AddressRule( @Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial ) + private AddressRule( + @Nullable HostRange ip, + @Nullable Pattern domainPattern, + @Nullable Integer port, + @Nonnull PartialOptions partial ) { this.ip = ip; this.domainPattern = domainPattern; this.partial = partial; + this.port = port; } @Nullable - public static AddressRule parse( String filter, @Nonnull PartialOptions partial ) + public static AddressRule parse( String filter, @Nullable Integer port, @Nonnull PartialOptions partial ) { int cidr = filter.indexOf( '/' ); if( cidr >= 0 ) @@ -117,24 +124,27 @@ public final class AddressRule size -= 8; } - return new AddressRule( new HostRange( minBytes, maxBytes ), null, partial ); + return new AddressRule( new HostRange( minBytes, maxBytes ), null, port, partial ); } else { Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ); - return new AddressRule( null, pattern, partial ); + return new AddressRule( null, pattern, port, partial ); } } /** * Determine whether the given address matches a series of patterns. * - * @param domain The domain to match - * @param address The address to check. + * @param domain The domain to match + * @param socketAddress The address to check. * @return Whether it matches any of these patterns. */ - private boolean matches( String domain, InetAddress address ) + private boolean matches( String domain, InetSocketAddress socketAddress ) { + InetAddress address = socketAddress.getAddress(); + if( port != null && port != socketAddress.getPort() ) return false; + if( domainPattern != null ) { if( domainPattern.matcher( domain ).matches() ) return true; @@ -155,7 +165,7 @@ public final class AddressRule return ip != null && ip.contains( address ); } - public static Options apply( Iterable rules, String domain, InetAddress address ) + public static Options apply( Iterable rules, String domain, InetSocketAddress address ) { PartialOptions options = null; boolean hasMany = false; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java index 4f0bc5647..db82c06ef 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java @@ -49,12 +49,14 @@ public class AddressRuleConfig public static boolean checkRule( UnmodifiableConfig builder ) { String hostObj = get( builder, "host", String.class ).orElse( null ); + Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null ); return hostObj != null && checkEnum( builder, "action", Action.class ) + && check( builder, "port", Number.class ) && check( builder, "timeout", Number.class ) && check( builder, "max_upload", Number.class ) && check( builder, "max_download", Number.class ) && check( builder, "websocket_message", Number.class ) - && AddressRule.parse( hostObj, PartialOptions.DEFAULT ) != null; + && AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null; } @Nullable @@ -64,6 +66,7 @@ public class AddressRuleConfig if( hostObj == null ) return null; Action action = getEnum( builder, "action", Action.class ).orElse( null ); + Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null ); Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null ); Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null ); Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null ); @@ -77,7 +80,7 @@ public class AddressRuleConfig websocketMessage ); - return AddressRule.parse( hostObj, options ); + return AddressRule.parse( hostObj, port, options ); } private static boolean check( UnmodifiableConfig config, String field, Class klass ) diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index ebd21a655..115d8ab04 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -136,7 +136,7 @@ public class HttpRequest extends Resource try { boolean ssl = uri.getScheme().equalsIgnoreCase( "https" ); - InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl ); + InetSocketAddress socketAddress = NetworkUtils.getAddress( uri, ssl ); Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress ); SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index 1841a3df9..0407a198a 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -129,8 +129,7 @@ public class Websocket extends Resource try { boolean ssl = uri.getScheme().equalsIgnoreCase( "wss" ); - - InetSocketAddress socketAddress = NetworkUtils.getAddress( uri.getHost(), uri.getPort(), ssl ); + InetSocketAddress socketAddress = NetworkUtils.getAddress( uri, ssl ); Options options = NetworkUtils.getOptions( uri.getHost(), socketAddress ); SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null; diff --git a/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java new file mode 100644 index 000000000..690cb37f5 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java @@ -0,0 +1,34 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis.http.options; + +import org.junit.jupiter.api.Test; + +import java.net.InetSocketAddress; +import java.util.Collections; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class AddressRuleTest +{ + @Test + public void matchesPort() + { + Iterable rules = Collections.singletonList( AddressRule.parse( + "127.0.0.1", 8080, + new PartialOptions( Action.ALLOW, null, null, null, null ) + ) ); + + assertEquals( apply( rules, "localhost", 8080 ).action, Action.ALLOW ); + assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY ); + } + + private Options apply( Iterable rules, String host, int port ) + { + return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) ); + } +} From 6f868849ab2f264508e12c184cc56f2632aaf5bc Mon Sep 17 00:00:00 2001 From: SquidDev Date: Wed, 16 Sep 2020 21:27:59 +0100 Subject: [PATCH 332/711] Use tags to check if something is a dye We half did this already, just needed to change a couple of checks. Closes #541. --- .../shared/peripheral/printer/ContainerPrinter.java | 3 +-- .../shared/peripheral/printer/TilePrinter.java | 10 +++++----- .../dan200/computercraft/shared/util/ColourUtils.java | 2 ++ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index 9f0666645..8ab37fef9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -13,7 +13,6 @@ import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Inventory; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Slot; -import net.minecraft.item.DyeItem; import net.minecraft.item.ItemStack; import net.minecraft.util.IIntArray; import net.minecraft.util.IntArray; @@ -95,7 +94,7 @@ public class ContainerPrinter extends Container else { // Transfer from inventory to printer - if( stack.getItem() instanceof DyeItem ) + if( TilePrinter.isInk( stack ) ) { if( !mergeItemStack( stack, 0, 1, false ) ) return ItemStack.EMPTY; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index ac560c8b4..f704c2484 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -300,9 +300,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } } - private static boolean isInk( @Nonnull ItemStack stack ) + static boolean isInk( @Nonnull ItemStack stack ) { - return stack.getItem() instanceof DyeItem; + return ColourUtils.getStackColour( stack ) != null; } private static boolean isPaper( @Nonnull ItemStack stack ) @@ -321,7 +321,8 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private boolean inputPage() { ItemStack inkStack = m_inventory.get( 0 ); - if( !isInk( inkStack ) ) return false; + DyeColor dye = ColourUtils.getStackColour( inkStack ); + if( dye == null ) return false; for( int i = 1; i < 7; i++ ) { @@ -329,8 +330,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent if( paperStack.isEmpty() || !isPaper( paperStack ) ) continue; // Setup the new page - DyeColor dye = ColourUtils.getStackColour( inkStack ); - m_page.setTextColour( dye != null ? dye.getId() : 15 ); + m_page.setTextColour( dye.getId() ); m_page.clear(); if( paperStack.getItem() instanceof ItemPrintout ) diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 3c776d1bd..7a595f3c2 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -40,6 +40,8 @@ public final class ColourUtils public static DyeColor getStackColour( ItemStack stack ) { + if( stack.isEmpty() ) return null; + for( int i = 0; i < DYES.length; i++ ) { Tag dye = DYES[i]; From 6cee4efcd3610536ee74330cd728f7371011e5a8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 24 Sep 2020 17:47:30 +0100 Subject: [PATCH 333/711] Fix incorrect open container check Was this always broken, or did it happen in a Minecraft update? Don't know, but it's a very silly mistake either way. Fixes #544 --- .../computercraft/shared/turtle/core/TurtlePlayer.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index a9480bc40..86e5f76ad 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -55,11 +55,10 @@ public final class TurtlePlayer extends FakePlayer private void setState( ITurtleAccess turtle ) { - if( openContainer != null ) + if( openContainer != container ) { ComputerCraft.log.warn( "Turtle has open container ({})", openContainer ); - openContainer.onContainerClosed( this ); - openContainer = null; + closeContainer(); } BlockPos position = turtle.getPosition(); From 0832974725b2478c5227b81f82c35bbf03cf6aba Mon Sep 17 00:00:00 2001 From: Weblate Date: Wed, 30 Sep 2020 08:25:57 +0000 Subject: [PATCH 334/711] Translations for Swedish Co-authored-by: David Isaksson --- .../assets/computercraft/lang/sv_se.json | 77 ++++++++++++++++++- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/src/main/resources/assets/computercraft/lang/sv_se.json b/src/main/resources/assets/computercraft/lang/sv_se.json index b71e4fecb..1afe76b56 100644 --- a/src/main/resources/assets/computercraft/lang/sv_se.json +++ b/src/main/resources/assets/computercraft/lang/sv_se.json @@ -1,14 +1,14 @@ { "block.computercraft.computer_normal": "Dator", "block.computercraft.computer_advanced": "Avancerad Dator", - "block.computercraft.computer_command": "Kommando Dator", + "block.computercraft.computer_command": "Kommandodator", "block.computercraft.disk_drive": "Diskettläsare", "block.computercraft.printer": "Skrivare", "block.computercraft.speaker": "Högtalare", "block.computercraft.monitor_normal": "Skärm", "block.computercraft.monitor_advanced": "Avancerad Skärm", "block.computercraft.wireless_modem_normal": "TrÃ¥dlöst Modem", - "block.computercraft.wireless_modem_advanced": "Ender Modem", + "block.computercraft.wireless_modem_advanced": "Endermodem", "block.computercraft.wired_modem": "TrÃ¥dat Modem", "block.computercraft.cable": "Nätverkskabel", "block.computercraft.wired_modem_full": "TrÃ¥dat Modem", @@ -38,5 +38,76 @@ "upgrade.computercraft.speaker.adjective": "Högljudd", "chat.computercraft.wired_modem.peripheral_connected": "Kringutrustning \"%s\" är kopplad till nätverket", "chat.computercraft.wired_modem.peripheral_disconnected": "Kringutrustning \"%s\" är frÃ¥nkopplad frÃ¥n nätverket", - "gui.computercraft.tooltip.copy": "Kopiera till urklipp" + "gui.computercraft.tooltip.copy": "Kopiera till urklipp", + "gui.computercraft.tooltip.disk_id": "Diskett-ID: %s", + "gui.computercraft.tooltip.computer_id": "Dator-ID: %s", + "tracking_field.computercraft.coroutines_dead.name": "Coroutines borttagna", + "tracking_field.computercraft.coroutines_created.name": "Coroutines skapade", + "tracking_field.computercraft.websocket_outgoing.name": "Websocket utgÃ¥ende", + "tracking_field.computercraft.websocket_incoming.name": "Websocket ingÃ¥ende", + "tracking_field.computercraft.http_download.name": "HTTP-nedladdning", + "tracking_field.computercraft.http_upload.name": "HTTP-uppladdning", + "tracking_field.computercraft.http.name": "HTTP-förfrÃ¥gningar", + "tracking_field.computercraft.turtle.name": "Turtle-operationer", + "tracking_field.computercraft.fs.name": "Filsystemoperationer", + "tracking_field.computercraft.peripheral.name": "Samtal till kringutrustning", + "tracking_field.computercraft.server_time.name": "Serveraktivitetstid", + "tracking_field.computercraft.server_count.name": "Antal serveruppgifter", + "tracking_field.computercraft.max.name": "Max tid", + "tracking_field.computercraft.average.name": "Genomsnittlig tid", + "tracking_field.computercraft.total.name": "Total tid", + "tracking_field.computercraft.tasks.name": "Uppgifter", + "argument.computercraft.argument_expected": "Argument förväntas", + "argument.computercraft.tracking_field.no_field": "Okänt fält '%s'", + "argument.computercraft.computer.many_matching": "Flera datorer matchar '%s' (%s träffar)", + "argument.computercraft.computer.no_matching": "Inga datorer matchar '%s'", + "commands.computercraft.generic.additional_rows": "%d ytterligare rader…", + "commands.computercraft.generic.exception": "Ohanterat felfall (%s)", + "commands.computercraft.generic.no": "N", + "commands.computercraft.generic.yes": "J", + "commands.computercraft.generic.position": "%s, %s, %s", + "commands.computercraft.generic.no_position": "", + "commands.computercraft.queue.desc": "Skicka ett computer_command event till en kommandodator, skicka vidare ytterligare argument. Detta är mestadels utformat för kartmarkörer som fungerar som en mer datorvänlig version av /trigger. Alla spelare kan köra kommandot, vilket sannolikt skulle göras genom en textkomponents klick-event.", + "commands.computercraft.queue.synopsis": "Skicka ett computer_command event till en kommandodator", + "commands.computercraft.reload.done": "Konfiguration omladdad", + "commands.computercraft.reload.desc": "Ladda om ComputerCrafts konfigurationsfil", + "commands.computercraft.reload.synopsis": "Ladda om ComputerCrafts konfigurationsfil", + "commands.computercraft.track.dump.computer": "Dator", + "commands.computercraft.track.dump.no_timings": "Inga tidtagningar tillgängliga", + "commands.computercraft.track.dump.desc": "Dumpa de senaste resultaten av datorspÃ¥rning.", + "commands.computercraft.track.dump.synopsis": "Dumpa de senaste spÃ¥rningsresultaten", + "commands.computercraft.track.stop.not_enabled": "SpÃ¥rar för tillfället inga datorer", + "commands.computercraft.track.stop.action": "Klicka för att stoppa spÃ¥rning", + "commands.computercraft.track.stop.desc": "Stoppa spÃ¥rning av alla datorers körtider och eventräkningar", + "commands.computercraft.track.stop.synopsis": "Stoppa spÃ¥rning för alla datorer", + "commands.computercraft.track.start.stop": "Kör %s för att stoppa spÃ¥rning och visa resultaten", + "commands.computercraft.track.start.desc": "Börja spÃ¥ra alla dators körtider och eventräkningar. Detta kommer Ã¥terställa resultaten frÃ¥n tidigare körningar.", + "commands.computercraft.track.start.synopsis": "Starta spÃ¥rning för alla datorer", + "commands.computercraft.track.desc": "SpÃ¥ra hur länge datorer exekverar, och även hur mÃ¥nga event de hanterar. Detta presenterar information pÃ¥ liknande sätt som /forge track och kan vara användbart för att undersöka lagg.", + "commands.computercraft.track.synopsis": "SpÃ¥ra körningstider för denna dator.", + "commands.computercraft.view.not_player": "Kan inte öppna terminalen för en ickespelare", + "commands.computercraft.view.action": "Titta pÃ¥ denna dator", + "commands.computercraft.view.desc": "Öppna datorns terminal för att möjligöra fjärrstyrning. Detta ger inte tillgÃ¥ng till turtlens inventory. Du kan ange en dators instans-id (t.ex. 123) eller dator-id (t.ex. #123).", + "commands.computercraft.view.synopsis": "Titta pÃ¥ datorns terminal.", + "commands.computercraft.tp.not_there": "Kan inte hitta datorn i världen", + "commands.computercraft.tp.not_player": "Kan inte öppna terminalen för en ickespelare", + "commands.computercraft.tp.action": "Teleportera till den här datorn", + "commands.computercraft.tp.desc": "Teleportera till datorns position. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").", + "commands.computercraft.tp.synopsis": "Teleportera till en specifik dator.", + "commands.computercraft.turn_on.done": "Startade %s/%s datorer", + "commands.computercraft.turn_on.desc": "Starta de listade datorerna eller alla om ingen anges. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").", + "commands.computercraft.turn_on.synopsis": "Starta pÃ¥ datorer pÃ¥ distans.", + "commands.computercraft.shutdown.done": "Stängde av %s/%s datorer", + "commands.computercraft.dump.desc": "Visa status för alla datorer eller specifik information för en dator. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").", + "commands.computercraft.shutdown.desc": "Stäng av de listade datorerna eller alla om ingen anges. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").", + "commands.computercraft.shutdown.synopsis": "Stäng av datorer pÃ¥ distans.", + "commands.computercraft.dump.action": "Visa mer information om den här datorn", + "commands.computercraft.dump.synopsis": "Visa status för datorer.", + "commands.computercraft.help.no_command": "Inget sÃ¥dant kommando '%s'", + "commands.computercraft.help.no_children": "%s har inget underkommando", + "commands.computercraft.help.desc": "Visa detta hjälpmeddelande", + "commands.computercraft.help.synopsis": "TillhandahÃ¥ll hjälp för ett specifikt kommando", + "commands.computercraft.desc": "/computercraft kommandot tillhandahÃ¥ller olika debugging- och administrationsverktyg för att kontrollera och interagera med datorer.", + "commands.computercraft.synopsis": "Olika kommandon för att kontrollera datorer.", + "itemGroup.computercraft": "ComputerCraft" } From 84036d97d99efd8762e0170002060ae3471508bf Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 2 Oct 2020 21:21:53 +0100 Subject: [PATCH 335/711] Fix io.open documentation Well, that was silly. --- src/main/resources/data/computercraft/lua/rom/apis/io.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/io.lua b/src/main/resources/data/computercraft/lua/rom/apis/io.lua index 917faef7f..5ecbdf652 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/io.lua @@ -289,7 +289,7 @@ end -- The `mode` string can be any of the following: -- - **"r"**: Read mode -- - **"w"**: Write mode --- - **"w"**: Append mode +-- - **"a"**: Append mode -- -- The mode may also have a `b` at the end, which opens the file in "binary -- mode". This allows you to read binary files, as well as seek within a file. From 8472112fc1eaad18ed6ed2c6c62b040fe421e81a Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 4 Oct 2020 11:14:22 +0100 Subject: [PATCH 336/711] Don't propagate adjacent redstone signals for computers (#549) Minecraft propagates "strong" redstone signals (such as those directly from comparators or repeaters) through solid blocks. This includes computers, which is a little annoying as it means one cannot feed redstone wire from one side and a repeater from another. This changes computers to not propagate strong redstone signals, in the same way transparent blocks like glass do. Closes #548. --- .../shared/computer/blocks/BlockComputerBase.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index 0bf82c8e2..ac164df1f 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -24,6 +24,7 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; import net.minecraft.world.storage.loot.LootContext; @@ -180,4 +181,10 @@ public abstract class BlockComputerBase extends Bloc if( label != null ) computer.setLabel( label ); } } + + @Override + public boolean shouldCheckWeakPower( BlockState state, IWorldReader world, BlockPos pos, Direction side ) + { + return false; + } } From 334ca65482b428821de83070f7b8e0f8a950a7fe Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Oct 2020 11:19:20 +0100 Subject: [PATCH 337/711] Bump to 1.93.0 --- gradle.properties | 2 +- .../data/computercraft/lua/rom/help/changelog.txt | 10 ++++++++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 13 ++++++------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/gradle.properties b/gradle.properties index 2e9a93b9f..57fa71a25 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.92.0 +mod_version=1.93.0 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 0c381c83d..23414de05 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,13 @@ +# New features in CC: Tweaked 1.93.0 + +* Update Swedish translations (Granddave). +* Printers use item tags to check dyes. +* HTTP rules may now be targetted for a specific port. +* Don't propagate adjacent redstone signals through computers. + +And several bug fixes: +* Fix NPEs when turtles interact with containers. + # New features in CC: Tweaked 1.92.0 * Bump Cobalt version: diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 099b912c1..3143088aa 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,12 +1,11 @@ -New features in CC: Tweaked 1.92.0 +New features in CC: Tweaked 1.93.0 -* Bump Cobalt version: - * Add support for the __pairs metamethod. - * string.format now uses the __tostring metamethod. -* Add date-specific MOTDs (MCJack123). +* Update Swedish translations (Granddave). +* Printers use item tags to check dyes. +* HTTP rules may now be targetted for a specific port. +* Don't propagate adjacent redstone signals through computers. And several bug fixes: -* Correctly handle tabs within textutils.unserailizeJSON. -* Fix sheep not dropping items when sheared by turtles. +* Fix NPEs when turtles interact with containers. Type "help changelog" to see the full version history. From 71563a52ff9628fe243ac36171426492ff06d2dc Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sun, 4 Oct 2020 11:31:06 +0100 Subject: [PATCH 338/711] Let's make this a proper release --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 9e46d21c3..9d55e09a2 100644 --- a/build.gradle +++ b/build.gradle @@ -409,7 +409,7 @@ curseforge { apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : '' project { id = '282001' - releaseType = 'beta' + releaseType = 'release' changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})." relations { @@ -487,7 +487,7 @@ githubRelease { .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() } - prerelease true + prerelease false } def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"] From 30d35883b83831900b34040f0131c7e06f5c3e52 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Thu, 8 Oct 2020 09:48:36 +0100 Subject: [PATCH 339/711] Fix my docs Thanks @plt-hokusai. Kinda embarrassing this slipped through - I evidently need to lint examples too. --- .../data/computercraft/lua/rom/modules/main/cc/pretty.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua index b934aa995..a62a6f9f1 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -13,7 +13,7 @@ -- @module cc.pretty -- @usage Print a table to the terminal -- local pretty = require "cc.pretty" --- pretty.write(pretty.dump({ 1, 2, 3 })) +-- pretty.write(pretty.pretty({ 1, 2, 3 })) -- -- @usage Build a custom document and display it -- local pretty = require "cc.pretty" From 34a2c835d412c0d9e1fb20a42b7f2cd2738289c7 Mon Sep 17 00:00:00 2001 From: Drew Lemmy Date: Sun, 11 Oct 2020 21:37:56 +0100 Subject: [PATCH 340/711] Add color table to docs (#553) --- doc/styles.css | 12 +- .../computercraft/lua/rom/apis/colors.lua | 159 ++++++++++++++++-- 2 files changed, 153 insertions(+), 18 deletions(-) diff --git a/doc/styles.css b/doc/styles.css index 2bcc830cc..da9fbec6a 100644 --- a/doc/styles.css +++ b/doc/styles.css @@ -111,7 +111,7 @@ footer { } /* The definition lists at the top of each page */ -table.definition-list { +table.definition-list, table.pretty-table { border-collapse: collapse; width: 100%; } @@ -130,6 +130,16 @@ table.definition-list th { table.definition-list td { width: 100%; } +/* Pretty tables, mostly inherited from table.definition-list */ +table.pretty-table td, table.pretty-table th { + border: 1px solid #cccccc; + padding: 2px 4px; +} + +table.pretty-table th { + background-color: #f0f0f0; +} + dl.definition dt { border-top: 1px solid #ccc; padding-top: 1em; diff --git a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua index a941fa287..1edb47bce 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua @@ -1,15 +1,137 @@ ---- The Colors API allows you to manipulate sets of colors. --- --- This is useful in conjunction with Bundled Cables from the RedPower mod, --- RedNet Cables from the MineFactory Reloaded mod, and colors on Advanced --- Computers and Advanced Monitors. --- --- For the non-American English version just replace @{colors} with @{colours} --- and it will use the other API, colours which is exactly the same, except in --- British English (e.g. @{colors.gray} is spelt @{colours.grey}). --- --- @see colours --- @module colors +--[[- The Colors API allows you to manipulate sets of colors. + +This is useful in conjunction with Bundled Cables from the RedPower mod, RedNet +Cables from the MineFactory Reloaded mod, and colors on Advanced Computers and +Advanced Monitors. + +For the non-American English version just replace @{colors} with @{colours} and +it will use the other API, colours which is exactly the same, except in British +English (e.g. @{colors.gray} is spelt @{colours.grey}). + +On basic terminals (such as the Computer and Monitor), all the colors are +converted to grayscale. This means you can still use all 16 colors on the +screen, but they will appear as the nearest tint of gray. You can check if a +terminal supports color by using the function @{term.isColor}. + +Grayscale colors are calculated by taking the average of the three components, +i.e. `(red + green + blue) / 3`. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Default Colors
ColorValueDefault Palette Color
DecHexPaint/BlitPreviewHexRGBGrayscale
colors.white10x10#F0F0F0240, 240, 240
colors.orange20x21#F2B233242, 178, 51
colors.magenta40x42#E57FD8229, 127, 216
colors.lightBlue80x83#99B2F2153, 178, 242
colors.yellow160x104#DEDE6C222, 222, 108
colors.lime320x205#7FCC19127, 204, 25
colors.pink640x406#F2B2CC242, 178, 204
colors.gray1280x807#4C4C4C76, 76, 76
colors.lightGray2560x1008#999999153, 153, 153
colors.cyan5120x2009#4C99B276, 153, 178
colors.purple10240x400a#B266E5178, 102, 229
colors.blue20480x800b#3366CC51, 102, 204
colors.brown40960x1000c#7F664C127, 102, 76
colors.green81920x2000d#57A64E87, 166, 78
colors.red163840x4000e#CC4C4C204, 76, 76
colors.black327680x8000f#11111117, 17, 17
+ +@see colours +@module colors +]] local expect = dofile("rom/modules/main/cc/expect.lua").expect @@ -37,7 +159,7 @@ yellow = 0x10 -- terminal colour of #7FCC19. lime = 0x20 ---- Pink. Written as `6` in paint files and @{term.blit}, has a default +--- Pink: Written as `6` in paint files and @{term.blit}, has a default -- terminal colour of #F2B2CC. pink = 0x40 @@ -74,10 +196,11 @@ green = 0x2000 red = 0x4000 --- Black: Written as `f` in paint files and @{term.blit}, has a default --- terminal colour of #191919. +-- terminal colour of #111111. black = 0x8000 ---- Combines a set of colors (or sets of colors) into a larger set. +--- Combines a set of colors (or sets of colors) into a larger set. Useful for +-- Bundled Cables. -- -- @tparam number ... The colors to combine. -- @treturn number The union of the color sets given in `...` @@ -96,7 +219,8 @@ function combine(...) return r end ---- Removes one or more colors (or sets of colors) from an initial set. +--- Removes one or more colors (or sets of colors) from an initial set. Useful +-- for Bundled Cables. -- -- Each parameter beyond the first may be a single color or may be a set of -- colors (in the latter case, all colors in the set are removed from the @@ -121,7 +245,8 @@ function subtract(colors, ...) return r end ---- Tests whether `color` is contained within `colors`. +--- Tests whether `color` is contained within `colors`. Useful for Bundled +-- Cables. -- -- @tparam number colors A color, or color set -- @tparam number color A color or set of colors that `colors` should contain. From 93068402a2ffec00eedb8fe2d859ebdc005a1989 Mon Sep 17 00:00:00 2001 From: Drew Lemmy Date: Sun, 11 Oct 2020 22:38:18 +0100 Subject: [PATCH 341/711] Document remaining OS functions (#554) --- doc/stub/global.lua | 55 +++++++++ doc/stub/os.lua | 115 ++++++++++++++++++ doc/styles.css | 16 ++- illuaminate.sexp | 7 +- .../dan200/computercraft/core/apis/OSAPI.java | 19 ++- 5 files changed, 205 insertions(+), 7 deletions(-) create mode 100644 doc/stub/global.lua diff --git a/doc/stub/global.lua b/doc/stub/global.lua new file mode 100644 index 000000000..c0609a1c3 --- /dev/null +++ b/doc/stub/global.lua @@ -0,0 +1,55 @@ +--[[- +Global functions defined by `bios.lua`. This does not include standard Lua +functions. + +@module _G +]] + +--[[- Pauses execution for the specified number of seconds. + +As it waits for a fixed amount of world ticks, `time` will automatically be +rounded up to the nearest multiple of 0.05 seconds. If you are using coroutines +or the @{parallel|parallel API}, it will only pause execution of the current +thread, not the whole program. + +**Note** Because sleep internally uses timers, it is a function that yields. +This means that you can use it to prevent "Too long without yielding" errors, +however, as the minimum sleep time is 0.05 seconds, it will slow your program +down. + +**Warning** Internally, this function queues and waits for a timer event (using +@{os.startTimer}), however it does not listen for any other events. This means +that any event that occurs while sleeping will be entirely discarded. If you +need to receive events while sleeping, consider using @{os.startTimer|timers}, +or the @{parallel|parallel API}. + +@tparam number time The number of seconds to sleep for, rounded up to the +nearest multiple of 0.05. + +@see os.startTimer +]] +function sleep(time) end + +function write(text) end +function print(...) end +function printError(...) end + +function read(replaceChar, history, completeFn, default) end + +--- The ComputerCraft and Minecraft version of the current computer environment. +-- +-- For example, `ComputerCraft 1.93.0 (Minecraft 1.15.2)`. +_HOST = _HOST + +--[[- The default computer settings as defined in the ComputerCraft +configuration. + +This is a comma-separated list of settings pairs defined by the mod +configuration or server owner. By default, it is empty. + +An example value to disable autocompletion: + + shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false + +]] +_CC_DEFAULT_SETTINGS = _CC_DEFAULT_SETTINGS diff --git a/doc/stub/os.lua b/doc/stub/os.lua index 2c9f730f4..7da3ea0c3 100644 --- a/doc/stub/os.lua +++ b/doc/stub/os.lua @@ -1,6 +1,121 @@ -- Defined in bios.lua + +--[[- Loads the given API into the global environment. + +**Warning** This function is deprecated. Use of this function will pollute the +global table, use @{require} instead. + +This function loads and executes the file at the given path, and all global +variables and functions exported by it will by available through the use of +`myAPI.`, where `myAPI` is the base name of the API file. + +@tparam string path The path of the API to load. +@treturn boolean Whether or not the API was successfully loaded. + +@deprecated Use @{require}. +]] function loadAPI(path) end + +--- Unloads an API which was loaded by @{os.loadAPI}. +-- +-- This effectively removes the specified table from `_G`. +-- +-- @tparam string name The name of the API to unload. +-- @deprecated Use @{require}. +function unloadAPI(name) end + +--[[- Pause execution of the current thread and waits for any events matching +`filter`. + +This function @{coroutine.yield|yields} the current process and waits for it +to be resumed with a vararg list where the first element matches `filter`. +If no `filter` is supplied, this will match all events. + +Unlike @{os.pullEventRaw}, it will stop the application upon a "terminate" +event, printing the error "Terminated". + +@tparam[opt] string filter Event to filter for. +@treturn string event The name of the event that fired. +@treturn any param... Optional additional parameters of the event. +@usage Listen for `mouse_click` events. + + while true do + local event, button, x, y = os.pullEvent("mouse_click") + print("Button", button, "was clicked at", x, ",", y) + end + +@usage Listen for multiple events. + + while true do + local eventData = {os.pullEvent()} + local event = eventData[1] + + if event == "mouse_click" then + print("Button", eventData[2], "was clicked at", eventData[3], ",", eventData[4]) + elseif event == "key" then + print("Key code", eventData[2], "was pressed") + end + end + +@see os.pullEventRaw To pull the terminate event. +]] function pullEvent(filter) end + +--[[- Pause execution of the current thread and waits for events, including the +`terminate` event. + +This behaves almost the same as @{os.pullEvent}, except it allows you to handle +the `terminate` event yourself - the program will not stop execution when +Ctrl+T is pressed. + +@tparam[opt] string filter Event to filter for. +@treturn string event The name of the event that fired. +@treturn any param... Optional additional parameters of the event. +@usage Listen for `terminate` events. + + while true do + local event = os.pullEventRaw() + if event == "terminate" then + print("Caught terminate event!") + end + end + +@see os.pullEvent To pull events normally. +]] function pullEventRaw(filter) end + +--- Pauses execution for the specified number of seconds, alias of @{_G.sleep}. +function sleep(time) end + +--- Get the current CraftOS version (for example, `CraftOS 1.8`). +-- +-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this +-- should return `CraftOS 1.8`. +-- +-- @treturn string The current CraftOS version. function version() end + +--[[- Run the program at the given path with the specified environment and +arguments. + +This function does not resolve program names like the shell does. This means +that, for example, `os.run("edit")` will not work. As well as this, it does not +provide access to the @{shell} API in the environment. For this behaviour, use +@{shell.run} instead. + +If the program cannot be found, or failed to run, it will print the error and +return `false`. If you want to handle this more gracefully, use an alternative +such as @{loadfile}. + +@tparam table env The environment to run the program with. +@tparam string path The exact path of the program to run. +@param ... The arguments to pass to the program. +@treturn boolean Whether or not the program ran successfully. +@usage Run the default shell from within your program: + + os.run({}, "/rom/programs/shell") + +@see shell.run +@see loadfile +]] function run(env, path, ...) end diff --git a/doc/styles.css b/doc/styles.css index da9fbec6a..41f8fe05b 100644 --- a/doc/styles.css +++ b/doc/styles.css @@ -23,7 +23,7 @@ body { "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } -code, pre, .parameter, .type, .definition-name, .reference-code { +code, pre, kbd, .parameter, .type, .definition-name, .reference-code { font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; } @@ -183,6 +183,20 @@ span.parameter:after { content:":"; padding-left: 0.3em; } vertical-align: middle; } +/** Fancy keyboard shortcut styling, inspired by GitHub markdown. */ +kbd { + display: inline-block; + padding: 4px 5px; + font-size: 0.8em; + line-height: 10px; + color: #444d56; + vertical-align: middle; + background-color: #fafbfc; + border: 1px solid #d1d5da; + border-radius: 3px; + box-shadow: inset 0 -1px 0 #d1d5da; +} + /* styles for prettification of source */ .highlight .comment { color: #558817; } .highlight .constant { color: #a8660d; } diff --git a/illuaminate.sexp b/illuaminate.sexp index d28a3fd44..b06417843 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -50,7 +50,7 @@ ;; colours imports from colors, and we don't handle that right now. ;; keys is entirely dynamic, so we skip it. - (dynamic-modules colours keys) + (dynamic-modules colours keys _G) (globals :max @@ -79,6 +79,7 @@ /doc/stub/http.lua /doc/stub/os.lua /doc/stub/turtle.lua + /doc/stub/global.lua ; Java generated APIs /doc/javadoc/turtle.lua ; Peripherals @@ -100,6 +101,10 @@ /doc/stub/fs.lua) (linters -doc:unresolved-reference)) +;; Suppress warnings for the BIOS using its own deprecated members for now. +(at /src/main/resources/*/computercraft/lua/bios.lua + (linters -var:deprecated)) + (at /src/test/resources/test-rom ; We should still be able to test deprecated members. (linters -var:deprecated) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 43a5c473f..be5dbb2dd 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -171,12 +171,18 @@ public class OSAPI implements ILuaAPI /** * Starts a timer that will run for the specified number of seconds. Once - * the timer fires, a timer event will be added to the queue with the ID - * returned from this function as the first parameter. + * the timer fires, a {@code timer} event will be added to the queue with + * the ID returned from this function as the first parameter. + * + * As with @{os.sleep|sleep}, {@code timer} will automatically be rounded up + * to the nearest multiple of 0.05 seconds, as it waits for a fixed amount + * of world ticks. * * @param timer The number of seconds until the timer fires. - * @return The ID of the new timer. + * @return The ID of the new timer. This can be used to filter the + * {@code timer} event, or {@link #cancelTimer cancel the timer}. * @throws LuaException If the time is below zero. + * @see #cancelTimer To cancel a timer. */ @LuaFunction public final int startTimer( double timer ) throws LuaException @@ -199,11 +205,14 @@ public class OSAPI implements ILuaAPI /** * Sets an alarm that will fire at the specified world time. When it fires, - * an alarm event will be added to the event queue. + * an {@code alarm} event will be added to the event queue with the ID + * returned from this function as the first parameter. * * @param time The time at which to fire the alarm, in the range [0.0, 24.0). - * @return The ID of the alarm that was set. + * @return The ID of the new alarm. This can be used to filter the + * {@code alarm} event, or {@link #cancelAlarm cancel the alarm}. * @throws LuaException If the time is out of range. + * @see #cancelAlarm To cancel an alarm. */ @LuaFunction public final int setAlarm( double time ) throws LuaException From 01d81cb91da938836f953b290ad6b8fc87cb7e35 Mon Sep 17 00:00:00 2001 From: Drew Lemmy Date: Wed, 14 Oct 2020 22:05:56 +0100 Subject: [PATCH 342/711] Update illuaminate CSS for deprecation (#556) --- doc/styles.css | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/styles.css b/doc/styles.css index 41f8fe05b..178e5daf2 100644 --- a/doc/styles.css +++ b/doc/styles.css @@ -128,6 +128,11 @@ table.definition-list th { text-align: right; } +/* Deprecated definitions */ +table.definition-list tr.definition-deprecated th { + text-decoration: line-through; +} + table.definition-list td { width: 100%; } /* Pretty tables, mostly inherited from table.definition-list */ @@ -152,6 +157,10 @@ dl.definition dt .definition-name { flex-grow: 1; } +/* Deprecated definitions */ +dl.definition dt .definition-name.definition-deprecated { + text-decoration: line-through; +} dl.definition dd { padding-bottom: 1em; From 4766833cf2d041ed179529eecb9402ad09b2b79b Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 20 Oct 2020 17:38:59 +0100 Subject: [PATCH 343/711] Bump JEI/crafttweaker versions In my defence, they weren't out when I started the 1.15 update. --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 9d55e09a2..3c9226198 100644 --- a/build.gradle +++ b/build.gradle @@ -106,10 +106,10 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3:api") - compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.15.2:6.0.0.9") + compileOnly fg.deobf("mezz.jei:jei-1.16.3:7.6.0.49:api") + compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.16.3:7.0.0.48") - // runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3") + runtimeOnly fg.deobf("mezz.jei:jei-1.16.3:7.6.0.49") compileOnly 'com.google.auto.service:auto-service:1.0-rc7' annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' From bf6053906dc6a3c7b0d40d5b097e745dce1f33bc Mon Sep 17 00:00:00 2001 From: Drew Lemmy Date: Wed, 21 Oct 2020 10:28:12 +0100 Subject: [PATCH 344/711] Fix TBO norm issues on old GPUs --- .../shared/peripheral/monitor/ClientMonitor.java | 2 +- .../resources/assets/computercraft/shaders/monitor.frag | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 856210908..6cb024469 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -69,7 +69,7 @@ public final class ClientMonitor extends ClientTerminal GL15.glBufferData( GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW ); tboTexture = GlStateManager.genTexture(); GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture ); - GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8, tboBuffer ); + GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, tboBuffer ); GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 ); GlStateManager.bindBuffer( GL31.GL_TEXTURE_BUFFER, 0 ); diff --git a/src/main/resources/assets/computercraft/shaders/monitor.frag b/src/main/resources/assets/computercraft/shaders/monitor.frag index b0b7b49ed..f19a6a9eb 100644 --- a/src/main/resources/assets/computercraft/shaders/monitor.frag +++ b/src/main/resources/assets/computercraft/shaders/monitor.frag @@ -6,7 +6,7 @@ uniform sampler2D u_font; uniform int u_width; uniform int u_height; -uniform samplerBuffer u_tbo; +uniform usamplerBuffer u_tbo; uniform vec3 u_palette[16]; in vec2 f_pos; @@ -30,9 +30,9 @@ void main() { vec2 outside = step(vec2(0.0, 0.0), vec2(cell)) * step(vec2(cell), vec2(float(u_width) - 1.0, float(u_height) - 1.0)); float mult = outside.x * outside.y; - int character = int(texelFetch(u_tbo, index).r * 255.0); - int fg = int(texelFetch(u_tbo, index + 1).r * 255.0); - int bg = int(texelFetch(u_tbo, index + 2).r * 255.0); + int character = int(texelFetch(u_tbo, index).r); + int fg = int(texelFetch(u_tbo, index + 1).r); + int bg = int(texelFetch(u_tbo, index + 2).r); vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT); vec4 img = texture(u_font, (texture_corner(character) + pos) / 256.0); From 61fb4caaad51b83ac4a8a5999e50d439f94c71bf Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 23 Oct 2020 17:44:52 +0100 Subject: [PATCH 345/711] Bump to 1.93.1 --- gradle.properties | 2 +- .../data/computercraft/lua/rom/help/changelog.txt | 5 +++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 11 +++-------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index 57fa71a25..ff1289383 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.93.0 +mod_version=1.93.1 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 23414de05..3bba36e69 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,8 @@ +# New features in CC: Tweaked 1.93.1 + +* Various documentation improvements (Lemmmy). +* Fix TBO monitor renderer on some older graphics cards (Lemmmy). + # New features in CC: Tweaked 1.93.0 * Update Swedish translations (Granddave). diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 3143088aa..3354c403b 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,11 +1,6 @@ -New features in CC: Tweaked 1.93.0 +New features in CC: Tweaked 1.93.1 -* Update Swedish translations (Granddave). -* Printers use item tags to check dyes. -* HTTP rules may now be targetted for a specific port. -* Don't propagate adjacent redstone signals through computers. - -And several bug fixes: -* Fix NPEs when turtles interact with containers. +* Various documentation improvements (Lemmmy). +* Fix TBO monitor renderer on some older graphics cards (Lemmmy). Type "help changelog" to see the full version history. From 113b560a201dbdea9de2a2ef536bcce1d6e51978 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 27 Oct 2020 22:19:28 +0000 Subject: [PATCH 346/711] Update configuration to match latest illuaminate Ooooooh, it's all fancy now. Well, that or horrifically broken. --- .github/workflows/make-doc.sh | 2 +- .gitignore | 3 +- doc/styles.css | 214 +--------------------------------- illuaminate.sexp | 3 + 4 files changed, 7 insertions(+), 215 deletions(-) diff --git a/.github/workflows/make-doc.sh b/.github/workflows/make-doc.sh index e447c3046..f7446f84c 100755 --- a/.github/workflows/make-doc.sh +++ b/.github/workflows/make-doc.sh @@ -12,5 +12,5 @@ chmod 600 "$HOME/.ssh/key" # And upload rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \ - "$GITHUB_WORKSPACE/doc/" \ + "$GITHUB_WORKSPACE/doc/out/" \ "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST" diff --git a/.gitignore b/.gitignore index 63cc1d148..84f17aee8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,9 +3,8 @@ /logs /build /out -/doc/**/*.html +/doc/out/ /doc/javadoc/ -/doc/index.json # Runtime directories /run diff --git a/doc/styles.css b/doc/styles.css index 178e5daf2..a21b9ac34 100644 --- a/doc/styles.css +++ b/doc/styles.css @@ -1,141 +1,9 @@ -/* Basic reset on elements */ -h1, h2, h3, h4, p, table, div, body { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* Make the page a little more airy */ -body { - margin: 20px auto; - max-width: 1200px; - padding: 0 10px; - line-height: 1.6; - color: #222; - background: #fff; -} - -/* Try to use system default fonts. */ -body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", - "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; -} - -code, pre, kbd, .parameter, .type, .definition-name, .reference-code { - font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; -} - -/* Some definitions of basic tags */ -code { - color: #c7254e; - background-color: #f9f2f4; -} - -p { - margin: 0.9em 0; -} - -h1 { - font-size: 1.5em; - font-weight: lighter; - border-bottom: solid 1px #aaa; -} - -h2, h3, h4 { margin: 1.4em 0 0.3em;} -h2 { font-size: 1.25em; } -h3 { font-size: 1.15em; font-weight: bold; } -h4 { font-size: 1.06em; } - -a, a:visited, a:active { font-weight: bold; color: #004080; text-decoration: none; } -a:hover { text-decoration: underline; } - -blockquote { - padding: 0.3em; - margin: 1em 0; - background: #f0f0f0; - border-left: solid 0.5em #ccc; -} - -/* Stop sublists from having initial vertical space */ -ul ul { margin-top: 0px; } -ol ul { margin-top: 0px; } -ol ol { margin-top: 0px; } -ul ol { margin-top: 0px; } - -/* Make the target distinct; helps when we're navigating to a function */ -a:target + * { background-color: #FFFF99; } - -/* Allow linking to any subsection */ -a[name]::before { content: "#"; } - -/* Layout */ -#main { - display: flex; - flex-wrap: nowrap; - justify-content: space-between; - min-height: calc(100vh - 100px); -} - -#main > nav { - flex-basis: 30%; - min-width: 150px; - max-width: 250px; - background-color: #f0f0f0; -} - -nav h1, nav ul { padding: 0em 10px; } - -nav h2 { - background-color:#e7e7e7; - font-size: 1.1em; - color:#000000; - padding: 5px 10px; -} - -nav ul { - list-style-type: none; - margin: 0; -} - -#content { - flex-shrink: 1; - flex-basis: 80%; - padding: 0px 10px; -} - -footer { - text-align: right; - font-size: 0.8em; -} - -/* The definition lists at the top of each page */ -table.definition-list, table.pretty-table { +/* Pretty tables, mostly inherited from table.definition-list */ +table.pretty-table { border-collapse: collapse; width: 100%; } -table.definition-list td, table.definition-list th { - border: 1px solid #cccccc; - padding: 5px; -} - -table.definition-list th { - background-color: #f0f0f0; - min-width: 200px; - white-space: nowrap; - text-align: right; -} - -/* Deprecated definitions */ -table.definition-list tr.definition-deprecated th { - text-decoration: line-through; -} - -table.definition-list td { width: 100%; } - -/* Pretty tables, mostly inherited from table.definition-list */ table.pretty-table td, table.pretty-table th { border: 1px solid #cccccc; padding: 2px 4px; @@ -144,81 +12,3 @@ table.pretty-table td, table.pretty-table th { table.pretty-table th { background-color: #f0f0f0; } - -dl.definition dt { - border-top: 1px solid #ccc; - padding-top: 1em; - display: flex; -} - -dl.definition dt .definition-name { - padding: 0 0.1em; - margin: 0 0.1em; - flex-grow: 1; -} - -/* Deprecated definitions */ -dl.definition dt .definition-name.definition-deprecated { - text-decoration: line-through; -} - -dl.definition dd { - padding-bottom: 1em; - margin: 10px 0 0 20px; -} - -dl.definition h3 { - font-size: .95em; -} - -/* Links to source-code */ -.source-link { font-size: 0.8em; } -.source-link::before { content: '[' } -.source-link::after { content: ']' } -a.source-link, a.source-link:visited, a.source-link:active { color: #505050; } - -/* Method definitions */ -span.parameter:after { content:":"; padding-left: 0.3em; } -.optional { text-decoration: underline dotted; } - -/** Fancy colour display. */ -.colour-ref { - display: inline-block; - width: 0.8em; - height: 0.8em; - margin: 0.1em 0.1em 0.3em 0.1em; /* Terrrible hack to force vertical alignment. */ - border: solid 1px black; - box-sizing: border-box; - vertical-align: middle; -} - -/** Fancy keyboard shortcut styling, inspired by GitHub markdown. */ -kbd { - display: inline-block; - padding: 4px 5px; - font-size: 0.8em; - line-height: 10px; - color: #444d56; - vertical-align: middle; - background-color: #fafbfc; - border: 1px solid #d1d5da; - border-radius: 3px; - box-shadow: inset 0 -1px 0 #d1d5da; -} - -/* styles for prettification of source */ -.highlight .comment { color: #558817; } -.highlight .constant { color: #a8660d; } -.highlight .escape { color: #844631; } -.highlight .keyword { color: #aa5050; font-weight: bold; } -.highlight .library { color: #0e7c6b; } -.highlight .marker { color: #512b1e; background: #fedc56; font-weight: bold; } -.highlight .string { color: #8080ff; } -.highlight .literal-kw { color: #8080ff; } -.highlight .number { color: #f8660d; } -.highlight .operator { color: #2239a8; font-weight: bold; } -.highlight .preprocessor, pre .prepro { color: #a33243; } -.highlight .global { color: #800080; } -.highlight .user-keyword { color: #800080; } -.highlight .prompt { color: #558817; } -.highlight .url { color: #272fc2; text-decoration: underline; } diff --git a/illuaminate.sexp b/illuaminate.sexp index b06417843..558028975 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -10,7 +10,10 @@ (doc (title "CC: Tweaked") + (destination doc/out) + (logo src/main/resources/pack.png) (index doc/index.md) + (styles doc/styles.css) (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) (module-kinds From c334423d42ba3b653ac3a8c27bce7970457f8f96 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 31 Oct 2020 09:54:38 +0000 Subject: [PATCH 347/711] Add function to get window visibility Closes #562 Co-authored-by: devomaa --- .../data/computercraft/lua/rom/apis/window.lua | 8 ++++++++ .../resources/test-rom/spec/apis/window_spec.lua | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/window.lua b/src/main/resources/data/computercraft/lua/rom/apis/window.lua index ec112a991..850ec18e2 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/window.lua @@ -474,6 +474,14 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) end end + --- Get whether this window is visible. Invisible windows will not be + -- drawn to the screen until they are made visible again. + -- + -- @treturn boolean Whether this window is visible. + -- @see Window:setVisible + function window.isVisible() + return bVisible + end --- Draw this window. This does nothing if the window is not visible. -- -- @see Window:setVisible diff --git a/src/test/resources/test-rom/spec/apis/window_spec.lua b/src/test/resources/test-rom/spec/apis/window_spec.lua index cb2905951..6b5e7fdf7 100644 --- a/src/test/resources/test-rom/spec/apis/window_spec.lua +++ b/src/test/resources/test-rom/spec/apis/window_spec.lua @@ -157,4 +157,17 @@ describe("The window library", function() expect({ w.getLine(1) }):same { "test ", "aaaa0", "4444f" } end) end) + describe("Window.setVisible", function() + it("validates arguments", function() + local w = mk() + expect.error(w.setVisible, nil):eq("bad argument #1 (expected boolean, got nil)") + end) + end) + describe("Window.isVisible", function() + it("gets window visibility", function() + local w = mk() + w.setVisible(false) + expect(w.isVisible()):same(false) + end) + end) end) From 84a6bb1cf3b0668ddc7d8c409a2477a42390e3f7 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 31 Oct 2020 10:03:09 +0000 Subject: [PATCH 348/711] Make generic peripherals on by default This is a long way away from "feature complete" as it were. However, it's definitely at a point where it's suitable for general usage - I'm happy with the API, and don't think I'm going to be breaking things any time soon. That said, things aren't exposed yet for Java-side public consumption. I was kinda waiting until working on Plethora to actually do that, but not sure if/when that'll happen. If someone else wants to work on an integration mod (or just adding integrations for their own mod), do get in touch and I can work out how to expose this. Closes #452 --- .../java/dan200/computercraft/ComputerCraft.java | 2 -- .../java/dan200/computercraft/shared/Config.java | 16 ---------------- .../generic/GenericPeripheralProvider.java | 2 -- .../shared/peripheral/generic/data/ItemData.java | 5 ----- 4 files changed, 25 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index d31e1e41f..d510ab65b 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -90,8 +90,6 @@ public final class ComputerCraft public static boolean turtlesCanPush = true; public static EnumSet turtleDisabledActions = EnumSet.noneOf( TurtleAction.class ); - public static boolean genericPeripheral = false; - public static int computerTermWidth = 51; public static int computerTermHeight = 19; diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index f93bc5a0a..a39f513f6 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -82,8 +82,6 @@ public final class Config private static final ConfigValue monitorWidth; private static final ConfigValue monitorHeight; - private static final ConfigValue genericPeripheral; - private static final ConfigValue monitorRenderer; private static final ConfigValue monitorDistance; @@ -294,17 +292,6 @@ public final class Config builder.pop(); } - { - builder.comment( "Options for various experimental features. These are not guaranteed to be stable, and may change or be removed across versions." ); - builder.push( "experimental" ); - - genericPeripheral = builder - .comment( "Attempt to make any existing block (or tile entity) a peripheral.\n" + - "This provides peripheral methods for any inventory, fluid tank or energy storage block. It will" + - "_not_ provide methods which have an existing peripheral provider." ) - .define( "generic_peripherals", false ); - } - serverSpec = builder.build(); Builder clientBuilder = new Builder(); @@ -379,9 +366,6 @@ public final class Config ComputerCraft.monitorWidth = monitorWidth.get(); ComputerCraft.monitorHeight = monitorHeight.get(); - // Experimental - ComputerCraft.genericPeripheral = genericPeripheral.get(); - // Client ComputerCraft.monitorRenderer = monitorRenderer.get(); ComputerCraft.monitorDistanceSq = monitorDistance.get() * monitorDistance.get(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index 09041c4f8..e0528afa6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -35,8 +35,6 @@ public class GenericPeripheralProvider @Nonnull public static LazyOptional getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) { - if( !ComputerCraft.genericPeripheral ) return LazyOptional.empty(); - TileEntity tile = world.getTileEntity( pos ); if( tile == null ) return LazyOptional.empty(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index a2a39f599..7973fb107 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -26,9 +26,6 @@ import java.util.stream.Collectors; /** * Data providers for items. - * - * We guard using {@link ComputerCraft#genericPeripheral} in several places, as advanced functionality should not be - * exposed for {@code turtle.getItemDetail} when generic peripehrals are disabled. */ public class ItemData { @@ -73,8 +70,6 @@ public class ItemData data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) ); - if( !ComputerCraft.genericPeripheral ) return data; - CompoundNBT tag = stack.getTag(); if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) ) { From 6aae4e576621090840724e094aa25e51696530fc Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 31 Oct 2020 10:09:26 +0000 Subject: [PATCH 349/711] Remove superfluous imports Hah, this is embarassing --- .../shared/peripheral/generic/GenericPeripheralProvider.java | 1 - .../computercraft/shared/peripheral/generic/data/ItemData.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index e0528afa6..149179b84 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -6,7 +6,6 @@ package dan200.computercraft.shared.peripheral.generic; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.asm.NamedMethod; import dan200.computercraft.core.asm.PeripheralMethod; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index 7973fb107..a2e049d9b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; From f6160bdc57b3d9850607c2c7c2ce9734b4963478 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 31 Oct 2020 10:59:24 +0000 Subject: [PATCH 350/711] Fix players not getting advancements when they own turtles When we construct a new ServerPlayerEntity (and thus TurtlePlayer), we get the current (global) advancement state and call .setPlayer() on it. As grantCriterion blocks FakePlayers from getting advancements, this means a player will no longer receive any advancements, as the "wrong" player object is being consulted. As a temporary work around, we attempt to restore the previous player to the advancement store. I'll try to upstream something into Forge to resolve this properly. Fixes #564 --- build.gradle | 2 +- .../api/turtle/ITurtleAccess.java | 2 +- .../shared/turtle/core/TurtleBrain.java | 3 +- .../shared/turtle/core/TurtlePlayer.java | 32 +++++++++++++++---- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index eab59f562..77998bae4 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.179' + classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.187' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 53b176dbf..85752b15a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -139,7 +139,7 @@ public interface ITurtleAccess * * @return This turtle's owner. */ - @Nonnull + @Nullable GameProfile getOwningPlayer(); /** diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 31b363aa3..373d0787c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -45,6 +45,7 @@ import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.TimeUnit; @@ -598,7 +599,7 @@ public class TurtleBrain implements ITurtleAccess m_owningPlayer = profile; } - @Nonnull + @Nullable @Override public GameProfile getOwningPlayer() { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 86e5f76ad..4b60932e3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -17,6 +17,7 @@ import net.minecraft.entity.EntitySize; import net.minecraft.entity.EntityType; import net.minecraft.entity.Pose; import net.minecraft.entity.passive.horse.AbstractHorseEntity; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; @@ -41,11 +42,30 @@ public final class TurtlePlayer extends FakePlayer "[ComputerCraft]" ); - private TurtlePlayer( ITurtleAccess turtle ) + private TurtlePlayer( ServerWorld world, GameProfile name ) { - super( (ServerWorld) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); - this.connection = new FakeNetHandler( this ); - setState( turtle ); + super( world, name ); + } + + private static TurtlePlayer create( ITurtleAccess turtle ) + { + ServerWorld world = (ServerWorld) turtle.getWorld(); + GameProfile profile = turtle.getOwningPlayer(); + + TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) ); + player.connection = new FakeNetHandler( player ); + player.setState( turtle ); + + if( profile != null && profile.getId() != null ) + { + // Constructing a player overrides the "active player" variable in advancements. As fake players cannot + // get advancements, this prevents a normal player who has placed a turtle from getting advancements. + // We try to locate the "actual" player and restore them. + ServerPlayerEntity actualPlayer = world.getServer().getPlayerList().getPlayerByUUID( profile.getId() ); + if( actualPlayer != null ) player.getAdvancements().setPlayer( actualPlayer ); + } + + return player; } private static GameProfile getProfile( @Nullable GameProfile profile ) @@ -72,14 +92,14 @@ public final class TurtlePlayer extends FakePlayer public static TurtlePlayer get( ITurtleAccess access ) { - if( !(access instanceof TurtleBrain) ) return new TurtlePlayer( access ); + if( !(access instanceof TurtleBrain) ) return create( access ); TurtleBrain brain = (TurtleBrain) access; TurtlePlayer player = brain.m_cachedPlayer; if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getEntityWorld() != access.getWorld() ) { - player = brain.m_cachedPlayer = new TurtlePlayer( brain ); + player = brain.m_cachedPlayer = create( brain ); } else { From 17a932920711a5c0361a5048c9e0a5e7a58e6364 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 31 Oct 2020 12:50:03 +0000 Subject: [PATCH 351/711] Bump cct-javadoc version Documentation will now be sorted (somewhat) correctly! --- build.gradle | 2 +- doc/stub/http.lua | 2 -- .../dan200/computercraft/shared/computer/apis/CommandAPI.java | 1 - .../shared/peripheral/diskdrive/DiskDrivePeripheral.java | 3 ++- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 77998bae4..33a414ab9 100644 --- a/build.gradle +++ b/build.gradle @@ -122,7 +122,7 @@ dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" - cctJavadoc 'cc.tweaked:cct-javadoc:1.1.0' + cctJavadoc 'cc.tweaked:cct-javadoc:1.2.1' } // Compile tasks diff --git a/doc/stub/http.lua b/doc/stub/http.lua index 4be7a4180..6854ac9ea 100644 --- a/doc/stub/http.lua +++ b/doc/stub/http.lua @@ -1,8 +1,6 @@ --- The http library allows communicating with web servers, sending and -- receiving data from them. -- --- #### `http_check` event --- -- @module http --- Asynchronously make a HTTP request to the given url. diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index fd310da23..ad85cbe79 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -116,7 +116,6 @@ public class CommandAPI implements ILuaAPI * @param command The command to execute. * @return The "task id". When this command has been executed, it will queue a `task_complete` event with a matching id. * @throws LuaException (hidden) If the task cannot be created. - * @cc.tparam string command The command to execute. * @cc.usage Asynchronously sets the block above the computer to stone. *
      * commands.execAsync("~ ~1 ~ minecraft:stone")
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java
index dd15192db..bcf7dc82e 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java
@@ -140,7 +140,8 @@ public class DiskDrivePeripheral implements IPeripheral
     /**
      * Returns the title of the inserted audio disk.
      *
-     * @return The title of the audio, or {@code nil} if no audio disk is inserted.
+     * @return The title of the audio, or {@code false} if no audio disk is inserted.
+     * @cc.treturn string|nil|false The title of the audio, {@code false} if no disk is inserted, or {@code nil} if the disk has no audio.
      */
     @LuaFunction
     @Nullable

From a6fcfb6af2fc1bef8ca3a19122c9267549202424 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Sun, 1 Nov 2020 11:12:28 +0000
Subject: [PATCH 352/711] Draw in-hand pocket computers with blending

It might be worth switching to RenderTypes here, rather than a pure
Tesselator, but this'll do for now.

Fixes Zundrel/cc-tweaked-fabric#20.
---
 .../dan200/computercraft/client/render/ItemPocketRenderer.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java
index 157250d56..661effe15 100644
--- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java
@@ -115,6 +115,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
 
     private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height )
     {
+        RenderSystem.enableBlend();
         Minecraft.getInstance().getTextureManager()
             .bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) );
 
@@ -133,7 +134,6 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
 
     private static void renderLight( Matrix4f transform, int colour, int width, int height )
     {
-        RenderSystem.enableBlend();
         RenderSystem.disableTexture();
 
         float r = ((colour >>> 16) & 0xFF) / 255.0f;

From c58441b29c3715f092e7f3747bb3ec65ae5a3d29 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Sun, 1 Nov 2020 11:36:48 +0000
Subject: [PATCH 353/711] Various SNBT parsing improvements

Correctly handle:
 - Typed arrays ([I; 1, 2, 3])
 - All suffixed numbers (1.2d)
 - Single-quoted strings

Fixes #559
---
 .../computercraft/lua/rom/apis/textutils.lua  | 17 +++++++++++-----
 .../test-rom/spec/apis/textutils_spec.lua     | 20 +++++++++++++++++--
 2 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua
index 576c6755e..e8e999677 100644
--- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua
+++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua
@@ -453,13 +453,13 @@ do
         error_at(pos, "Unexpected %s, expected %s.", actual, exp)
     end
 
-    local function parse_string(str, pos)
+    local function parse_string(str, pos, terminate)
         local buf, n = {}, 1
 
         while true do
             local c = sub(str, pos, pos)
             if c == "" then error_at(pos, "Unexpected end of input, expected '\"'.") end
-            if c == '"' then break end
+            if c == terminate then break end
 
             if c == '\\' then
                 -- Handle the various escapes
@@ -485,13 +485,13 @@ do
         return concat(buf, "", 1, n - 1), pos + 1
     end
 
-    local valid = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true }
+    local num_types = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true }
     local function parse_number(str, pos, opts)
         local _, last, num_str = find(str, '^(-?%d+%.?%d*[eE]?[+-]?%d*)', pos)
         local val = tonumber(num_str)
         if not val then error_at(pos, "Malformed number %q.", num_str) end
 
-        if opts.nbt_style and valid[sub(str, pos + 1, pos + 1)] then return val, last + 2 end
+        if opts.nbt_style and num_types[sub(str, last + 1, last + 1)] then return val, last + 2 end
 
         return val, last + 1
     end
@@ -501,9 +501,11 @@ do
         return val, last + 1
     end
 
+    local arr_types = { I = true, L = true, B = true }
     local function decode_impl(str, pos, opts)
         local c = sub(str, pos, pos)
-        if c == '"' then return parse_string(str, pos + 1)
+        if c == '"' then return parse_string(str, pos + 1, '"')
+        elseif c == "'" and opts.nbt_style then return parse_string(str, pos + 1, "\'")
         elseif c == "-" or c >= "0" and c <= "9" then return parse_number(str, pos, opts)
         elseif c == "t" then
             if sub(str, pos + 1, pos + 3) == "rue" then return true, pos + 4 end
@@ -560,6 +562,11 @@ do
             pos = skip(str, pos + 1)
             c = sub(str, pos, pos)
 
+            if arr_types[c] and sub(str, pos + 1, pos + 1) == ";" and opts.nbt_style then
+                pos = skip(str, pos + 2)
+                c = sub(str, pos, pos)
+            end
+
             if c == "" then return expected(pos, c, "']'") end
             if c == "]" then return empty_json_array, pos + 1 end
 
diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua
index e83746ecf..486bf6118 100644
--- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua
+++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua
@@ -126,12 +126,28 @@ describe("The textutils library", function()
         end)
 
         describe("parses using NBT-style syntax", function()
+            local function exp(x)
+                local res, err = textutils.unserializeJSON(x, { nbt_style = true })
+                if not res then error(err, 2) end
+                return expect(res)
+            end
             it("basic objects", function()
-                expect(textutils.unserializeJSON([[{ a: 1, b:2 }]], { nbt_style = true })):same { a = 1, b = 2 }
+                exp([[{ a: 1, b:2 }]]):same { a = 1, b = 2 }
             end)
 
             it("suffixed numbers", function()
-                expect(textutils.unserializeJSON("1b", { nbt_style = true })):eq(1)
+                exp("1b"):eq(1)
+                exp("1.1d"):eq(1.1)
+            end)
+
+            it("strings", function()
+                exp("'123'"):eq("123")
+                exp("\"123\""):eq("123")
+            end)
+
+            it("typed arrays", function()
+                exp("[B; 1, 2, 3]"):same { 1, 2, 3 }
+                exp("[B;]"):same {}
             end)
         end)
 

From e2a635b6e5f5942f999213434054e06833c5cb06 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Sun, 1 Nov 2020 11:36:53 +0000
Subject: [PATCH 354/711] Don't fail when codecov is being finicky

---
 .github/workflows/main-ci.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml
index a24e965bf..51895fcec 100644
--- a/.github/workflows/main-ci.yml
+++ b/.github/workflows/main-ci.yml
@@ -34,6 +34,7 @@ jobs:
 
     - name: Upload Coverage
       run: bash <(curl -s https://codecov.io/bash)
+      continue-on-error: true
 
     - name: Generate Java documentation stubs
       run: ./gradlew luaJavadoc --no-daemon

From 666e83cf4fd0eb327f465d5b919a708790f99b00 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Sun, 1 Nov 2020 11:48:19 +0000
Subject: [PATCH 355/711] Fix JSON objects failing to pass

Maybe I should run the whole test suite, not just the things I think
matter? Nah....
---
 .../resources/data/computercraft/lua/rom/apis/textutils.lua     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua
index e8e999677..e6156d3b0 100644
--- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua
+++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua
@@ -530,7 +530,7 @@ do
 
             while true do
                 local key, value
-                if c == "\"" then key, pos = parse_string(str, pos + 1)
+                if c == "\"" then key, pos = parse_string(str, pos + 1, "\"")
                 elseif opts.nbt_style then key, pos = parse_ident(str, pos)
                 else return expected(pos, c, "object key")
                 end

From 741adfa7bb2b950d2851c3f0072d6a4769f22773 Mon Sep 17 00:00:00 2001
From: Drew Lemmy 
Date: Sun, 1 Nov 2020 19:28:18 +0000
Subject: [PATCH 356/711] Use blit to draw boxes, add colors.toBlit (#570)

---
 .../computercraft/lua/rom/apis/colors.lua     |  18 +++
 .../computercraft/lua/rom/apis/paintutils.lua |  98 ++++++++---------
 .../test-rom/spec/apis/colors_spec.lua        |  16 +++
 .../test-rom/spec/apis/paintutils_spec.lua    | 103 ++++++++++++++++++
 4 files changed, 184 insertions(+), 51 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua
index 1edb47bce..83c8e0f21 100644
--- a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua
+++ b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua
@@ -332,3 +332,21 @@ function rgb8(r, g, b)
         return packRGB(r, g, b)
     end
 end
+
+-- Colour to hex lookup table for toBlit
+local color_hex_lookup = {}
+for i = 0, 15 do
+    color_hex_lookup[2 ^ i] = string.format("%x", i)
+end
+
+--- Converts the given color to a paint/blit hex character (0-9a-f).
+--
+-- This is equivalent to converting floor(log_2(color)) to hexadecimal.
+--
+-- @tparam number color The color to convert.
+-- @treturn string The blit hex code of the color.
+function toBlit(color)
+    expect(1, color, "number")
+    return color_hex_lookup[color] or
+        string.format("%x", math.floor(math.log(color) / math.log(2)))
+end
diff --git a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua
index 1af17ee6c..7ae1006b8 100644
--- a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua
+++ b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua
@@ -23,6 +23,25 @@ local function parseLine(tImageArg, sLine)
     table.insert(tImageArg, tLine)
 end
 
+-- Sorts pairs of startX/startY/endX/endY such that the start is always the min
+local function sortCoords(startX, startY, endX, endY)
+    local minX, maxX, minY, maxY
+
+    if startX <= endX then
+        minX, maxX = startX, endX
+    else
+        minX, maxX = endX, startX
+    end
+
+    if startY <= endY then
+        minY, maxY = startY, endY
+    else
+        minY, maxY = endY, startY
+    end
+
+    return minX, maxX, minY, maxY
+end
+
 --- Parses an image from a multi-line string
 --
 -- @tparam string image The string containing the raw-image data.
@@ -71,9 +90,6 @@ function drawPixel(xPos, yPos, colour)
     expect(2, yPos, "number")
     expect(3, colour, "number", "nil")
 
-    if type(xPos) ~= "number" then error("bad argument #1 (expected number, got " .. type(xPos) .. ")", 2) end
-    if type(yPos) ~= "number" then error("bad argument #2 (expected number, got " .. type(yPos) .. ")", 2) end
-    if colour ~= nil and type(colour) ~= "number" then error("bad argument #3 (expected number, got " .. type(colour) .. ")", 2) end
     if colour then
         term.setBackgroundColor(colour)
     end
@@ -111,17 +127,7 @@ function drawLine(startX, startY, endX, endY, colour)
         return
     end
 
-    local minX = math.min(startX, endX)
-    local maxX, minY, maxY
-    if minX == startX then
-        minY = startY
-        maxX = endX
-        maxY = endY
-    else
-        minY = endY
-        maxX = startX
-        maxY = startY
-    end
+    local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)
 
     -- TODO: clip to screen rectangle?
 
@@ -177,37 +183,33 @@ function drawBox(startX, startY, endX, endY, nColour)
     endY = math.floor(endY)
 
     if nColour then
-        term.setBackgroundColor(nColour)
+        term.setBackgroundColor(nColour) -- Maintain legacy behaviour
+    else
+        nColour = term.getBackgroundColour()
     end
+    local colourHex = colours.toBlit(nColour)
+
     if startX == endX and startY == endY then
         drawPixelInternal(startX, startY)
         return
     end
 
-    local minX = math.min(startX, endX)
-    local maxX, minY, maxY
-    if minX == startX then
-        minY = startY
-        maxX = endX
-        maxY = endY
-    else
-        minY = endY
-        maxX = startX
-        maxY = startY
-    end
+    local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)
+    local width = maxX - minX + 1
 
-    for x = minX, maxX do
-        drawPixelInternal(x, minY)
-        drawPixelInternal(x, maxY)
-    end
-
-    if maxY - minY >= 2 then
-        for y = minY + 1, maxY - 1 do
-            drawPixelInternal(minX, y)
-            drawPixelInternal(maxX, y)
+    for y = minY, maxY do
+        if y == minY or y == maxY then
+            term.setCursorPos(minX, y)
+            term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width))
+        else
+            term.setCursorPos(minX, y)
+            term.blit(" ", colourHex, colourHex)
+            term.setCursorPos(maxX, y)
+            term.blit(" ", colourHex, colourHex)
         end
     end
 end
+
 --- Draws a filled box on the current term from the specified start position to
 -- the specified end position.
 --
@@ -233,29 +235,23 @@ function drawFilledBox(startX, startY, endX, endY, nColour)
     endY = math.floor(endY)
 
     if nColour then
-        term.setBackgroundColor(nColour)
+        term.setBackgroundColor(nColour) -- Maintain legacy behaviour
+    else
+        nColour = term.getBackgroundColour()
     end
+    local colourHex = colours.toBlit(nColour)
+
     if startX == endX and startY == endY then
         drawPixelInternal(startX, startY)
         return
     end
 
-    local minX = math.min(startX, endX)
-    local maxX, minY, maxY
-    if minX == startX then
-        minY = startY
-        maxX = endX
-        maxY = endY
-    else
-        minY = endY
-        maxX = startX
-        maxY = startY
-    end
+    local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY)
+    local width = maxX - minX + 1
 
-    for x = minX, maxX do
-        for y = minY, maxY do
-            drawPixelInternal(x, y)
-        end
+    for y = minY, maxY do
+        term.setCursorPos(minX, y)
+        term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width))
     end
 end
 
diff --git a/src/test/resources/test-rom/spec/apis/colors_spec.lua b/src/test/resources/test-rom/spec/apis/colors_spec.lua
index 86b8adfe9..c7505ca5a 100644
--- a/src/test/resources/test-rom/spec/apis/colors_spec.lua
+++ b/src/test/resources/test-rom/spec/apis/colors_spec.lua
@@ -73,4 +73,20 @@ describe("The colors library", function()
         expect(colors.rgb8(0.3, 0.5, 0.6)):equals(0x4c7f99)
         expect({ colors.rgb8(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 }
     end)
+
+    describe("colors.toBlit", function()
+        it("validates arguments", function()
+            expect.error(colors.toBlit, nil):eq("bad argument #1 (expected number, got nil)")
+        end)
+
+        it("converts all colors", function()
+            for i = 0, 15 do
+                expect(colors.toBlit(2 ^ i)):eq(string.format("%x", i))
+            end
+        end)
+
+        it("floors colors", function()
+            expect(colors.toBlit(16385)):eq("e")
+        end)
+    end)
 end)
diff --git a/src/test/resources/test-rom/spec/apis/paintutils_spec.lua b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua
index fc72eece2..fc2b6008c 100644
--- a/src/test/resources/test-rom/spec/apis/paintutils_spec.lua
+++ b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua
@@ -1,4 +1,19 @@
+local with_window = require "test_helpers".with_window
+
 describe("The paintutils library", function()
+    -- Verifies that a window's lines are equal to the given table of blit
+    -- strings ({{"text", "fg", "bg"}, {"text", "fg", "bg"}...})
+    local function window_eq(w, state)
+        -- Verification of the size isn't really important in the tests, but
+        -- better safe than sorry.
+        local _, height = w.getSize()
+        expect(#state):eq(height)
+
+        for line = 1, height do
+            expect({ w.getLine(line) }):same(state[line])
+        end
+    end
+
     describe("paintutils.parseImage", function()
         it("validates arguments", function()
             paintutils.parseImage("")
@@ -28,6 +43,30 @@ describe("The paintutils library", function()
             expect.error(paintutils.drawLine, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)")
             expect.error(paintutils.drawLine, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)")
         end)
+
+        it("draws a line going across with custom colour", function()
+            local w = with_window(3, 2, function()
+                paintutils.drawLine(1, 1, 3, 1, colours.red)
+            end)
+
+            window_eq(w, {
+                { "   ", "000", "eee" },
+                { "   ", "000", "fff" },
+            })
+        end)
+
+        it("draws a line going diagonally with term colour", function()
+            local w = with_window(3, 3, function()
+                term.setBackgroundColour(colours.red)
+                paintutils.drawLine(1, 1, 3, 3)
+            end)
+
+            window_eq(w, {
+                { "   ", "000", "eff" },
+                { "   ", "000", "fef" },
+                { "   ", "000", "ffe" },
+            })
+        end)
     end)
 
     describe("paintutils.drawBox", function()
@@ -38,6 +77,45 @@ describe("The paintutils library", function()
             expect.error(paintutils.drawBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)")
             expect.error(paintutils.drawBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)")
         end)
+
+        it("draws a box with term colour", function()
+            local w = with_window(3, 3, function()
+                term.setBackgroundColour(colours.red)
+                paintutils.drawBox(1, 1, 3, 3)
+            end)
+
+            window_eq(w, {
+                { "   ", "eee", "eee" },
+                { "   ", "e0e", "efe" },
+                { "   ", "eee", "eee" },
+            })
+        end)
+
+        it("draws a box with custom colour", function()
+            local w = with_window(3, 3, function()
+                paintutils.drawBox(1, 1, 3, 3, colours.red)
+            end)
+
+            window_eq(w, {
+                { "   ", "eee", "eee" },
+                { "   ", "e0e", "efe" },
+                { "   ", "eee", "eee" },
+            })
+        end)
+
+        it("draws a box without overwriting existing content", function()
+            local w = with_window(3, 3, function()
+                term.setCursorPos(2, 2)
+                term.write("a")
+                paintutils.drawBox(1, 1, 3, 3, colours.red)
+            end)
+
+            window_eq(w, {
+                { "   ", "eee", "eee" },
+                { " a ", "e0e", "efe" },
+                { "   ", "eee", "eee" },
+            })
+        end)
     end)
 
     describe("paintutils.drawFilledBox", function()
@@ -48,6 +126,31 @@ describe("The paintutils library", function()
             expect.error(paintutils.drawFilledBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)")
             expect.error(paintutils.drawFilledBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)")
         end)
+
+        it("draws a filled box with term colour", function()
+            local w = with_window(3, 3, function()
+                term.setBackgroundColour(colours.red)
+                paintutils.drawFilledBox(1, 1, 3, 3)
+            end)
+
+            window_eq(w, {
+                { "   ", "eee", "eee" },
+                { "   ", "eee", "eee" },
+                { "   ", "eee", "eee" },
+            })
+        end)
+
+        it("draws a filled box with custom colour", function()
+            local w = with_window(3, 3, function()
+                paintutils.drawFilledBox(1, 1, 3, 3, colours.red)
+            end)
+
+            window_eq(w, {
+                { "   ", "eee", "eee" },
+                { "   ", "eee", "eee" },
+                { "   ", "eee", "eee" },
+            })
+        end)
     end)
 
     describe("paintutils.drawImage", function()

From cc96e41d3eacc8ae1f797ac506737a0a6f5aef0d Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Sun, 1 Nov 2020 16:02:29 +0000
Subject: [PATCH 357/711] Remove stray copy-paste error from changelog

---
 .../resources/data/computercraft/lua/rom/help/changelog.txt     | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
index 3bba36e69..e22cae04e 100644
--- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
+++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
@@ -57,8 +57,6 @@ And several bug fixes:
 * Fix deadlock when mistakenly "watching" an unloaded chunk.
 * Fix full path of files being leaked in some errors.
 
-Type "help changelog" to see the full version history.
-
 # New features in CC: Tweaked 1.89.1
 
 * Fix crashes when rendering monitors of varying sizes.

From ab232bd6897728cf8f47d3985ba8b5803a1175a4 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Tue, 3 Nov 2020 15:33:10 +0000
Subject: [PATCH 358/711] Update to MC 1.16.4

Just some mapping changes really
---
 gradle.properties                                           | 6 +++---
 .../dan200/computercraft/client/ClientTableFormatter.java   | 4 ++--
 .../java/dan200/computercraft/client/gui/GuiComputer.java   | 2 +-
 .../java/dan200/computercraft/client/gui/GuiDiskDrive.java  | 2 +-
 .../java/dan200/computercraft/client/gui/GuiPrinter.java    | 2 +-
 .../java/dan200/computercraft/client/gui/GuiTurtle.java     | 2 +-
 .../client/proxy/ComputerCraftProxyClient.java              | 2 +-
 .../computercraft/client/render/TurtleMultiModel.java       | 4 ++--
 .../computercraft/client/render/TurtleSmartItemModel.java   | 6 +++---
 .../java/dan200/computercraft/data/LootTableProvider.java   | 2 +-
 src/main/java/dan200/computercraft/data/Tags.java           | 2 +-
 .../shared/data/ConstantLootConditionSerializer.java        | 4 ++--
 .../dan200/computercraft/shared/network/NetworkHandler.java | 2 +-
 .../shared/peripheral/diskdrive/TileDiskDrive.java          | 2 +-
 .../shared/peripheral/generic/data/ItemData.java            | 2 +-
 .../shared/peripheral/printer/TilePrinter.java              | 2 +-
 .../shared/peripheral/speaker/SpeakerPeripheral.java        | 2 +-
 .../computercraft/shared/turtle/upgrades/TurtleTool.java    | 2 +-
 .../dan200/computercraft/shared/util/FakeNetHandler.java    | 6 ------
 src/main/resources/META-INF/mods.toml                       | 4 ++--
 20 files changed, 27 insertions(+), 33 deletions(-)

diff --git a/gradle.properties b/gradle.properties
index 34e53b70c..fbac2d266 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -2,6 +2,6 @@
 mod_version=1.93.1
 
 # Minecraft properties (update mods.toml when changing)
-mc_version=1.16.3
-forge_version=34.0.1
-mappings_version=20200723-1.16.1
+mc_version=1.16.4
+forge_version=35.0.1
+mappings_version=20201028-1.16.3
diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java
index 14c471faa..4054f5fc9 100644
--- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java
+++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java
@@ -23,7 +23,7 @@ public class ClientTableFormatter implements TableFormatter
 {
     public static final ClientTableFormatter INSTANCE = new ClientTableFormatter();
 
-    private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap();
+    private static final Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap();
 
     private static FontRenderer renderer()
     {
@@ -55,7 +55,7 @@ public class ClientTableFormatter implements TableFormatter
     @Override
     public int getWidth( ITextComponent component )
     {
-        return renderer().func_238414_a_( component );
+        return renderer().getStringPropertyWidth( component );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java
index ed46daf49..a1c5babfa 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java
@@ -141,7 +141,7 @@ public final class GuiComputer extends Containe
     public void render( @Nonnull MatrixStack stack, int mouseX, int mouseY, float partialTicks )
     {
         super.render( stack, mouseX, mouseY, partialTicks );
-        func_230459_a_( stack, mouseX, mouseY );
+        renderHoveredTooltip( stack, mouseX, mouseY );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java
index 0eb36af5a..27bd997d2 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java
@@ -37,6 +37,6 @@ public class GuiDiskDrive extends ContainerScreen
     {
         renderBackground( transform );
         super.render( transform, mouseX, mouseY, partialTicks );
-        func_230459_a_( transform, mouseX, mouseY );
+        renderHoveredTooltip( transform, mouseX, mouseY );
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java
index a111a6e6a..dd555e85d 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java
@@ -47,6 +47,6 @@ public class GuiPrinter extends ContainerScreen
     {
         renderBackground( stack );
         super.render( stack, mouseX, mouseY, partialTicks );
-        func_230459_a_( stack, mouseX, mouseY );
+        renderHoveredTooltip( stack, mouseX, mouseY );
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java
index 4850ed4ad..0c01f2f6a 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java
@@ -126,7 +126,7 @@ public class GuiTurtle extends ContainerScreen
     {
         renderBackground( stack );
         super.render( stack, mouseX, mouseY, partialTicks );
-        func_230459_a_( stack, mouseX, mouseY );
+        renderHoveredTooltip( stack, mouseX, mouseY );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
index 79facbaaf..413383e55 100644
--- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
+++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
@@ -75,7 +75,7 @@ public final class ComputerCraftProxyClient
         ResourceLocation id = new ResourceLocation( ComputerCraft.MOD_ID, name );
         for( Supplier item : items )
         {
-            ItemModelsProperties.func_239418_a_( item.get(), id, getter );
+            ItemModelsProperties.registerProperty( item.get(), id, getter );
         }
     }
 
diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java
index 256c53544..8729bdfdd 100644
--- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java
+++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java
@@ -108,9 +108,9 @@ public class TurtleMultiModel implements IBakedModel
     }
 
     @Override
-    public boolean func_230044_c_()
+    public boolean isSideLit()
     {
-        return m_baseModel.func_230044_c_();
+        return m_baseModel.isSideLit();
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java
index 3272b6f50..38208c46d 100644
--- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java
+++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java
@@ -109,7 +109,7 @@ public class TurtleSmartItemModel implements IBakedModel
         {
             @Nonnull
             @Override
-            public IBakedModel func_239290_a_( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity )
+            public IBakedModel getOverrideModel( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable ClientWorld world, @Nullable LivingEntity entity )
             {
                 ItemTurtle turtle = (ItemTurtle) stack.getItem();
                 int colour = turtle.getColour( stack );
@@ -184,9 +184,9 @@ public class TurtleSmartItemModel implements IBakedModel
     }
 
     @Override
-    public boolean func_230044_c_()
+    public boolean isSideLit()
     {
-        return familyModel.func_230044_c_();
+        return familyModel.isSideLit();
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java
index 16be3be38..5ee2b6502 100644
--- a/src/main/java/dan200/computercraft/data/LootTableProvider.java
+++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java
@@ -51,7 +51,7 @@ public abstract class LootTableProvider implements IDataProvider
             tables.put( id, table );
         } );
 
-        tables.forEach( ( key, value ) -> LootTableManager.func_227508_a_( validation, key, value ) );
+        tables.forEach( ( key, value ) -> LootTableManager.validateLootTable( validation, key, value ) );
 
         Multimap problems = validation.getProblems();
         if( !problems.isEmpty() )
diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java
index 1dc5692d2..484c3db29 100644
--- a/src/main/java/dan200/computercraft/data/Tags.java
+++ b/src/main/java/dan200/computercraft/data/Tags.java
@@ -21,7 +21,7 @@ import static dan200.computercraft.data.Tags.CCTags.*;
 
 public class Tags extends ItemTagsProvider
 {
-    private static final ITag.INamedTag PIGLIN_LOVED = ItemTags.field_232903_N_;
+    private static final ITag.INamedTag PIGLIN_LOVED = ItemTags.PIGLIN_LOVED;
 
     public static class CCTags
     {
diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java
index 87182f010..4d2364fc5 100644
--- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java
+++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java
@@ -29,13 +29,13 @@ public final class ConstantLootConditionSerializer imp
     }
 
     @Override
-    public void func_230424_a_( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context )
+    public void serialize( @Nonnull JsonObject json, @Nonnull T object, @Nonnull JsonSerializationContext context )
     {
     }
 
     @Nonnull
     @Override
-    public T func_230423_a_( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context )
+    public T deserialize( @Nonnull JsonObject json, @Nonnull JsonDeserializationContext context )
     {
         return instance;
     }
diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java
index ca391be00..819e4ddfc 100644
--- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java
+++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java
@@ -78,7 +78,7 @@ public final class NetworkHandler
 
     public static void sendToAllAround( NetworkMessage packet, World world, Vector3d pos, double range )
     {
-        PacketDistributor.TargetPoint target = new PacketDistributor.TargetPoint( pos.x, pos.y, pos.z, range, world.func_234923_W_() );
+        PacketDistributor.TargetPoint target = new PacketDistributor.TargetPoint( pos.x, pos.y, pos.z, range, world.getDimensionKey() );
         network.send( PacketDistributor.NEAR.with( () -> target ), packet );
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
index 0ade6c201..92700f2c1 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
@@ -125,7 +125,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
     public void read( @Nonnull BlockState state, @Nonnull CompoundNBT nbt )
     {
         super.read( state, nbt );
-        customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.func_240643_a_( nbt.getString( NBT_NAME ) ) : null;
+        customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.getComponentFromJson( nbt.getString( NBT_NAME ) ) : null;
         if( nbt.contains( NBT_ITEM ) )
         {
             CompoundNBT item = nbt.getCompound( NBT_ITEM );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java
index 36d689cf4..c3647d6d8 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java
@@ -113,7 +113,7 @@ public class ItemData
     {
         try
         {
-            return ITextComponent.Serializer.func_240643_a_( x.getString() );
+            return ITextComponent.Serializer.getComponentFromJson( x.getString() );
         }
         catch( JsonParseException e )
         {
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
index f89c842fe..5386e2b3e 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
@@ -95,7 +95,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
     {
         super.read( state, nbt );
 
-        customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.func_240643_a_( nbt.getString( NBT_NAME ) ) : null;
+        customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.getComponentFromJson( nbt.getString( NBT_NAME ) ) : null;
 
         // Read page
         synchronized( m_page )
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
index 2e6202ac6..9e83f208a 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
@@ -152,7 +152,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
 
             float adjVolume = Math.min( volume, 3.0f );
             server.getPlayerList().sendToAllNearExcept(
-                null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.func_234923_W_(),
+                null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.getDimensionKey(),
                 new SPlaySoundPacket( name, SoundCategory.RECORDS, pos, adjVolume, pitch )
             );
             return null;
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
index cb322a37d..47d61d033 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
@@ -100,7 +100,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
     protected boolean canBreakBlock( BlockState state, World world, BlockPos pos, TurtlePlayer player )
     {
         Block block = state.getBlock();
-        return !state.isAir( world, pos )
+        return !state.isAir()
             && block != Blocks.BEDROCK
             && state.getPlayerRelativeBlockHardness( player, world, pos ) > 0
             && block.canEntityDestroy( state, world, pos, player );
diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java
index 03450d233..b28e557e7 100644
--- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java
+++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java
@@ -16,7 +16,6 @@ import net.minecraftforge.common.util.FakePlayer;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import javax.crypto.SecretKey;
 
 public class FakeNetHandler extends ServerPlayNetHandler
 {
@@ -322,11 +321,6 @@ public class FakeNetHandler extends ServerPlayNetHandler
             this.closeReason = message;
         }
 
-        @Override
-        public void enableEncryption( @Nonnull SecretKey key )
-        {
-        }
-
         @Nonnull
         @Override
         public INetHandler getNetHandler()
diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml
index 200610b0a..49042e1d8 100644
--- a/src/main/resources/META-INF/mods.toml
+++ b/src/main/resources/META-INF/mods.toml
@@ -1,5 +1,5 @@
 modLoader="javafml"
-loaderVersion="[34,35)"
+loaderVersion="[35,36)"
 
 issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues"
 displayURL="https://github.com/SquidDev-CC/CC-Tweaked"
@@ -20,6 +20,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
 [[dependencies.computercraft]]
     modId="forge"
     mandatory=true
-    versionRange="[34.0.1,35)"
+    versionRange="[35.0.1,36)"
     ordering="NONE"
     side="BOTH"

From d13bd2cce8d102ad7f61f557e707d6fe3731bc37 Mon Sep 17 00:00:00 2001
From: Lupus590 
Date: Wed, 4 Nov 2020 14:03:08 +0000
Subject: [PATCH 359/711] use arg[0] in all usage printouts (#571)

---
 .../data/computercraft/lua/rom/programs/alias.lua   |  3 ++-
 .../data/computercraft/lua/rom/programs/cd.lua      |  3 ++-
 .../computercraft/lua/rom/programs/command/exec.lua |  3 ++-
 .../data/computercraft/lua/rom/programs/copy.lua    |  3 ++-
 .../data/computercraft/lua/rom/programs/delete.lua  |  3 ++-
 .../data/computercraft/lua/rom/programs/edit.lua    |  3 ++-
 .../data/computercraft/lua/rom/programs/eject.lua   |  3 ++-
 .../lua/rom/programs/fun/advanced/paint.lua         |  3 ++-
 .../data/computercraft/lua/rom/programs/fun/dj.lua  |  7 ++++---
 .../data/computercraft/lua/rom/programs/gps.lua     |  7 ++++---
 .../lua/rom/programs/http/pastebin.lua              |  7 ++++---
 .../computercraft/lua/rom/programs/http/wget.lua    |  5 +++--
 .../data/computercraft/lua/rom/programs/label.lua   | 13 +++++++------
 .../data/computercraft/lua/rom/programs/mkdir.lua   |  3 ++-
 .../data/computercraft/lua/rom/programs/monitor.lua |  3 ++-
 .../data/computercraft/lua/rom/programs/move.lua    |  3 ++-
 .../computercraft/lua/rom/programs/rednet/chat.lua  |  5 +++--
 .../computercraft/lua/rom/programs/redstone.lua     |  9 +++++----
 .../data/computercraft/lua/rom/programs/rename.lua  |  3 ++-
 .../computercraft/lua/rom/programs/turtle/craft.lua |  3 ++-
 .../computercraft/lua/rom/programs/turtle/equip.lua |  3 ++-
 .../lua/rom/programs/turtle/excavate.lua            |  3 ++-
 .../computercraft/lua/rom/programs/turtle/go.lua    |  3 ++-
 .../lua/rom/programs/turtle/refuel.lua              |  3 ++-
 .../lua/rom/programs/turtle/tunnel.lua              |  3 ++-
 .../computercraft/lua/rom/programs/turtle/turn.lua  |  3 ++-
 .../lua/rom/programs/turtle/unequip.lua             |  3 ++-
 .../data/computercraft/lua/rom/programs/type.lua    |  3 ++-
 .../test-rom/spec/programs/command/exec_spec.lua    |  2 +-
 .../resources/test-rom/spec/programs/copy_spec.lua  |  2 +-
 .../resources/test-rom/spec/programs/move_spec.lua  |  2 +-
 .../test-rom/spec/programs/turtle/craft_spec.lua    |  2 +-
 .../test-rom/spec/programs/turtle/equip_spec.lua    |  2 +-
 .../test-rom/spec/programs/turtle/refuel_spec.lua   |  2 +-
 .../test-rom/spec/programs/turtle/unequip_spec.lua  |  2 +-
 35 files changed, 79 insertions(+), 51 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/programs/alias.lua b/src/main/resources/data/computercraft/lua/rom/programs/alias.lua
index 79ebedc1f..c3471a723 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/alias.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/alias.lua
@@ -1,6 +1,7 @@
 local tArgs = { ... }
 if #tArgs > 2 then
-    print("Usage: alias  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/cd.lua b/src/main/resources/data/computercraft/lua/rom/programs/cd.lua
index d1a3e86c1..f127ea88b 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/cd.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/cd.lua
@@ -1,6 +1,7 @@
 local tArgs = { ... }
 if #tArgs < 1 then
-    print("Usage: cd ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua b/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua
index 67c9446f9..1591b579d 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/command/exec.lua
@@ -4,7 +4,8 @@ if not commands then
     return
 end
 if #tArgs == 0 then
-    printError("Usage: exec ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    printError("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/copy.lua b/src/main/resources/data/computercraft/lua/rom/programs/copy.lua
index 49d58a0b9..0977d3f8f 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/copy.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/copy.lua
@@ -1,6 +1,7 @@
 local tArgs = { ... }
 if #tArgs < 2 then
-    print("Usage: cp  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/delete.lua b/src/main/resources/data/computercraft/lua/rom/programs/delete.lua
index 620cdd629..1d071619c 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/delete.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/delete.lua
@@ -1,7 +1,8 @@
 local args = table.pack(...)
 
 if args.n < 1 then
-    print("Usage: rm ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
index 007f37a24..8f0af9356 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
@@ -1,7 +1,8 @@
 -- Get file to edit
 local tArgs = { ... }
 if #tArgs == 0 then
-    print("Usage: edit ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/eject.lua b/src/main/resources/data/computercraft/lua/rom/programs/eject.lua
index b15e2f20f..3deb9c2a2 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/eject.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/eject.lua
@@ -1,7 +1,8 @@
 -- Get arguments
 local tArgs = { ... }
 if #tArgs == 0 then
-    print("Usage: eject ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua
index b7c44526a..cb9de4153 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua
@@ -34,7 +34,8 @@ end
 -- Determines if the file exists, and can be edited on this computer
 local tArgs = { ... }
 if #tArgs == 0 then
-    print("Usage: paint ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 local sPath = shell.resolve(tArgs[1])
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua
index 322b4a887..48b4aa06c 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/dj.lua
@@ -1,10 +1,11 @@
 local tArgs = { ... }
 
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usages:")
-    print("dj play")
-    print("dj play ")
-    print("dj stop")
+    print(programName .. " play")
+    print(programName .. " play ")
+    print(programName .. " stop")
 end
 
 if #tArgs > 2 then
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/gps.lua b/src/main/resources/data/computercraft/lua/rom/programs/gps.lua
index c0194443b..3e0590e9b 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/gps.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/gps.lua
@@ -1,8 +1,9 @@
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usages:")
-    print("gps host")
-    print("gps host   ")
-    print("gps locate")
+    print(programName .. " host")
+    print(programName .. " host   ")
+    print(programName .. " locate")
 end
 
 local tArgs = { ... }
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua b/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua
index 15ad89f36..807ef603f 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/http/pastebin.lua
@@ -1,8 +1,9 @@
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usages:")
-    print("pastebin put ")
-    print("pastebin get  ")
-    print("pastebin run  ")
+    print(programName .. " put ")
+    print(programName .. " get  ")
+    print(programName .. " run  ")
 end
 
 local tArgs = { ... }
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua b/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua
index 7b5c7654e..ac5fc4fc0 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/http/wget.lua
@@ -1,7 +1,8 @@
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usage:")
-    print("wget  [filename]")
-    print("wget run ")
+    print(programName .. "  [filename]")
+    print(programName .. " run ")
 end
 
 local tArgs = { ... }
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/label.lua b/src/main/resources/data/computercraft/lua/rom/programs/label.lua
index f857dac5c..68f228c60 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/label.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/label.lua
@@ -1,11 +1,12 @@
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usages:")
-    print("label get")
-    print("label get ")
-    print("label set ")
-    print("label set  ")
-    print("label clear")
-    print("label clear ")
+    print(programName .. " get")
+    print(programName .. " get ")
+    print(programName .. " set ")
+    print(programName .. " set  ")
+    print(programName .. " clear")
+    print(programName .. " clear ")
 end
 
 local function checkDrive(sDrive)
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua b/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua
index bbdd08002..4e1b8ac10 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/mkdir.lua
@@ -1,7 +1,8 @@
 local tArgs = { ... }
 
 if #tArgs < 1 then
-    print("Usage: mkdir ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua
index 01c9d7949..e97558357 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua
@@ -1,5 +1,6 @@
 local function printUsage()
-    print("Usage: monitor   ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "   ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/move.lua b/src/main/resources/data/computercraft/lua/rom/programs/move.lua
index 254592200..3f68236d0 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/move.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/move.lua
@@ -1,6 +1,7 @@
 local tArgs = { ... }
 if #tArgs < 2 then
-    print("Usage: mv  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua b/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua
index 1bf5582b2..6585d0675 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/rednet/chat.lua
@@ -1,9 +1,10 @@
 local tArgs = { ... }
 
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usages:")
-    print("chat host ")
-    print("chat join  ")
+    print(programName .. " host ")
+    print(programName .. " join  ")
 end
 
 local sOpenedModem = nil
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua b/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua
index 65d6c5e1f..7c3165c1c 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/redstone.lua
@@ -1,11 +1,12 @@
 local tArgs = { ... }
 
 local function printUsage()
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
     print("Usages:")
-    print("redstone probe")
-    print("redstone set  ")
-    print("redstone set   ")
-    print("redstone pulse   ")
+    print(programName .. " probe")
+    print(programName .. " set  ")
+    print(programName .. " set   ")
+    print(programName .. " pulse   ")
 end
 
 local sCommand = tArgs[1]
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rename.lua b/src/main/resources/data/computercraft/lua/rom/programs/rename.lua
index 8b491abcd..e627bb27f 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/rename.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/rename.lua
@@ -1,6 +1,7 @@
 local tArgs = { ... }
 if #tArgs < 2 then
-    print("Usage: rename  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua
index 65f93104b..ce9e84dc7 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/craft.lua
@@ -11,7 +11,8 @@ end
 local tArgs = { ... }
 local nLimit = nil
 if #tArgs < 1 then
-    print("Usage: craft [number]")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " [number]")
     return
 else
     nLimit = tonumber(tArgs[1])
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua
index b69ef4c45..9f0d60735 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/equip.lua
@@ -5,7 +5,8 @@ end
 
 local tArgs = { ... }
 local function printUsage()
-    print("Usage: equip  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
 end
 
 if #tArgs ~= 2 then
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua
index 9d4313eb1..1bb0488fe 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/excavate.lua
@@ -5,7 +5,8 @@ end
 
 local tArgs = { ... }
 if #tArgs ~= 1 then
-    print("Usage: excavate ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua
index 9c6de67ce..5b6c658e2 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/go.lua
@@ -5,7 +5,8 @@ end
 
 local tArgs = { ... }
 if #tArgs < 1 then
-    print("Usage: go  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua
index d9dd5b002..138cb9e47 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/refuel.lua
@@ -6,7 +6,8 @@ end
 local tArgs = { ... }
 local nLimit = 1
 if #tArgs > 1 then
-    print("Usage: refuel [number]")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " [number]")
     return
 elseif #tArgs > 0 then
     if tArgs[1] == "all" then
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua
index 34c0807d9..821965390 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/tunnel.lua
@@ -5,7 +5,8 @@ end
 
 local tArgs = { ... }
 if #tArgs ~= 1 then
-    print("Usage: tunnel ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua
index e3fbbcbd3..c4d6ceeb7 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/turn.lua
@@ -5,7 +5,8 @@ end
 
 local tArgs = { ... }
 if #tArgs < 1 then
-    print("Usage: turn  ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. "  ")
     return
 end
 
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua b/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua
index 97501aa42..82a37c895 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/turtle/unequip.lua
@@ -5,7 +5,8 @@ end
 
 local tArgs = { ... }
 local function printUsage()
-    print("Usage: unequip ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
 end
 
 if #tArgs ~= 1 then
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/type.lua b/src/main/resources/data/computercraft/lua/rom/programs/type.lua
index ccbaf0dd8..aa2ee54bb 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/type.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/type.lua
@@ -1,6 +1,7 @@
 local tArgs = { ... }
 if #tArgs < 1 then
-    print("Usage: type ")
+    local programName = arg[0] or fs.getName(shell.getRunningProgram())
+    print("Usage: " .. programName .. " ")
     return
 end
 
diff --git a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua
index ba714629f..f5eecd3d3 100644
--- a/src/test/resources/test-rom/spec/programs/command/exec_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/command/exec_spec.lua
@@ -10,7 +10,7 @@ describe("The exec program", function()
     it("displays its usage when given no argument", function()
         stub(_G, "commands", {})
         expect(capture(stub, "/rom/programs/command/exec.lua"))
-            :matches { ok = true, output = "", error = "Usage: exec \n" }
+            :matches { ok = true, output = "", error = "Usage: /rom/programs/command/exec.lua \n" }
     end)
 
     it("runs a command", function()
diff --git a/src/test/resources/test-rom/spec/programs/copy_spec.lua b/src/test/resources/test-rom/spec/programs/copy_spec.lua
index 4ab043986..5bcdda8b0 100644
--- a/src/test/resources/test-rom/spec/programs/copy_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/copy_spec.lua
@@ -35,6 +35,6 @@ describe("The copy program", function()
 
     it("displays the usage when given no arguments", function()
         expect(capture(stub, "copy"))
-            :matches { ok = true, output = "Usage: cp  \n", error = "" }
+            :matches { ok = true, output = "Usage: copy  \n", error = "" }
     end)
 end)
diff --git a/src/test/resources/test-rom/spec/programs/move_spec.lua b/src/test/resources/test-rom/spec/programs/move_spec.lua
index 664010118..dcc156362 100644
--- a/src/test/resources/test-rom/spec/programs/move_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/move_spec.lua
@@ -69,6 +69,6 @@ describe("The move program", function()
 
     it("displays the usage with no arguments", function()
         expect(capture(stub, "move"))
-            :matches { ok = true, output = "Usage: mv  \n", error = "" }
+            :matches { ok = true, output = "Usage: move  \n", error = "" }
     end)
 end)
diff --git a/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua
index 11934b7ec..8e1f12bb1 100644
--- a/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/turtle/craft_spec.lua
@@ -19,7 +19,7 @@ describe("The craft program", function()
         stub(_G, "turtle", { craft = function() end })
 
         expect(capture(stub, "/rom/programs/turtle/craft.lua"))
-            :matches { ok = true, output = "Usage: craft [number]\n", error = "" }
+            :matches { ok = true, output = "Usage: /rom/programs/turtle/craft.lua [number]\n", error = "" }
     end)
 
     it("crafts multiple items", function()
diff --git a/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua
index 09284f8a6..92f75b73c 100644
--- a/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/turtle/equip_spec.lua
@@ -13,7 +13,7 @@ describe("The turtle equip program", function()
         stub(_G, "turtle", {})
 
         expect(capture(stub, "/rom/programs/turtle/equip.lua"))
-            :matches { ok = true, output = "Usage: equip  \n", error = "" }
+            :matches { ok = true, output = "Usage: /rom/programs/turtle/equip.lua  \n", error = "" }
     end)
 
     it("equip nothing", function()
diff --git a/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua
index 986d028c1..485a66111 100644
--- a/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/turtle/refuel_spec.lua
@@ -32,7 +32,7 @@ describe("The refuel program", function()
     it("displays its usage when given too many argument", function()
         setup_turtle(0, 5, 0)
         expect(capture(stub, "/rom/programs/turtle/refuel.lua a b"))
-            :matches { ok = true, output = "Usage: refuel [number]\n", error = "" }
+            :matches { ok = true, output = "Usage: /rom/programs/turtle/refuel.lua [number]\n", error = "" }
     end)
 
     it("requires a numeric argument", function()
diff --git a/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua
index eea58f78f..1d81334f6 100644
--- a/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua
+++ b/src/test/resources/test-rom/spec/programs/turtle/unequip_spec.lua
@@ -13,7 +13,7 @@ describe("The turtle unequip program", function()
         stub(_G, "turtle", {})
 
         expect(capture(stub, "/rom/programs/turtle/unequip.lua"))
-            :matches { ok = true, output = "Usage: unequip \n", error = "" }
+            :matches { ok = true, output = "Usage: /rom/programs/turtle/unequip.lua \n", error = "" }
     end)
 
     it("says when nothing was unequipped", function()

From 74ac5bb3d17e5bee30643a5d6702696600c06229 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Sat, 7 Nov 2020 12:43:18 +0000
Subject: [PATCH 360/711] Bump to 1.94.0

---
 gradle.properties                                   |  2 +-
 .../data/computercraft/lua/rom/help/changelog.txt   | 12 ++++++++++++
 .../data/computercraft/lua/rom/help/whatsnew.txt    | 13 ++++++++++---
 3 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/gradle.properties b/gradle.properties
index ff1289383..5c6f6ea2b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,5 @@
 # Mod properties
-mod_version=1.93.1
+mod_version=1.94.0
 
 # Minecraft properties (update mods.toml when changing)
 mc_version=1.15.2
diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
index e22cae04e..b173cbceb 100644
--- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
+++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
@@ -1,3 +1,15 @@
+# New features in CC: Tweaked 1.94.0
+
+* Add getter for window visibility (devomaa)
+* Generic peripherals are no longer experimental, and on by default.
+* Use term.blit to draw boxes in paintutils (Lemmmy).
+
+And several bug fixes:
+* Fix turtles not getting advancements when turtles are on.
+* Draw in-hand pocket computers with the correct transparent flags enabled.
+* Several bug fixes to SNBT parsing.
+* Fix several programs using their original name instead of aliases in usage hints (Lupus590).
+
 # New features in CC: Tweaked 1.93.1
 
 * Various documentation improvements (Lemmmy).
diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt
index 3354c403b..563dc0f69 100644
--- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt
+++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt
@@ -1,6 +1,13 @@
-New features in CC: Tweaked 1.93.1
+New features in CC: Tweaked 1.94.0
 
-* Various documentation improvements (Lemmmy).
-* Fix TBO monitor renderer on some older graphics cards (Lemmmy).
+* Add getter for window visibility (devomaa)
+* Generic peripherals are no longer experimental, and on by default.
+* Use term.blit to draw boxes in paintutils (Lemmmy).
+
+And several bug fixes:
+* Fix turtles not getting advancements when turtles are on.
+* Draw in-hand pocket computers with the correct transparent flags enabled.
+* Several bug fixes to SNBT parsing.
+* Fix several programs using their original name instead of aliases in usage hints (Lupus590).
 
 Type "help changelog" to see the full version history.

From c8aeddedd4ed430f9cb6428676ebb4fa39834182 Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Wed, 11 Nov 2020 21:14:50 +0000
Subject: [PATCH 361/711] Auto-generate monitor models

I didn't think it was worth it, and then I found myself needing to
update a dozen of them. The code isn't especially pretty, but it works,
so that's fine.

Also fixes several issues with us using the wrong texture (closes #572).
I've put together a wiki page[1] which describes each texture in a
little more detail.

[1] https://github.com/SquidDev-CC/CC-Tweaked/wiki/Monitor-texture-reference
---
 .../blockstates/monitor_advanced.json         | 852 ++++++++++++++++++
 .../blockstates/monitor_normal.json           | 852 ++++++++++++++++++
 .../models/block/monitor_advanced.json        |   9 +
 .../models/block/monitor_advanced_d.json      |   9 +
 .../models/block/monitor_advanced_l.json      |   9 +
 .../models/block/monitor_advanced_ld.json     |   9 +
 .../models/block/monitor_advanced_lr.json     |   9 +
 .../models/block/monitor_advanced_lrd.json    |   9 +
 .../models/block/monitor_advanced_lru.json    |   9 +
 .../models/block/monitor_advanced_lrud.json   |   9 +
 .../models/block/monitor_advanced_lu.json     |   9 +
 .../models/block/monitor_advanced_lud.json    |   9 +
 .../models/block/monitor_advanced_r.json      |   9 +
 .../models/block/monitor_advanced_rd.json     |   9 +
 .../models/block/monitor_advanced_ru.json     |   9 +
 .../models/block/monitor_advanced_rud.json    |   9 +
 .../models/block/monitor_advanced_u.json      |   9 +
 .../models/block/monitor_advanced_ud.json     |   9 +
 .../models/block/monitor_normal.json          |   9 +
 .../models/block/monitor_normal_d.json        |   9 +
 .../models/block/monitor_normal_l.json        |   9 +
 .../models/block/monitor_normal_ld.json       |   9 +
 .../models/block/monitor_normal_lr.json       |   9 +
 .../models/block/monitor_normal_lrd.json      |   9 +
 .../models/block/monitor_normal_lru.json      |   9 +
 .../models/block/monitor_normal_lrud.json     |   9 +
 .../models/block/monitor_normal_lu.json       |   9 +
 .../models/block/monitor_normal_lud.json      |   9 +
 .../models/block/monitor_normal_r.json        |   9 +
 .../models/block/monitor_normal_rd.json       |   9 +
 .../models/block/monitor_normal_ru.json       |   9 +
 .../models/block/monitor_normal_rud.json      |   9 +
 .../models/block/monitor_normal_u.json        |   9 +
 .../models/block/monitor_normal_ud.json       |   9 +
 .../data/BlockModelProvider.java              | 109 +++
 .../dan200/computercraft/data/Generators.java |   1 +
 .../peripheral/monitor/BlockMonitor.java      |   2 +-
 .../peripheral/monitor/MonitorEdgeState.java  |   6 +
 .../blockstates/monitor_advanced.json         | 364 --------
 .../blockstates/monitor_normal.json           | 296 ------
 .../models/block/monitor_advanced.json        |   9 -
 .../models/block/monitor_advanced_d.json      |   9 -
 .../models/block/monitor_advanced_l.json      |   9 -
 .../models/block/monitor_advanced_ld.json     |   9 -
 .../models/block/monitor_advanced_lr.json     |   9 -
 .../models/block/monitor_advanced_lrd.json    |   9 -
 .../models/block/monitor_advanced_lru.json    |   9 -
 .../models/block/monitor_advanced_lrud.json   |   9 -
 .../models/block/monitor_advanced_lu.json     |   9 -
 .../models/block/monitor_advanced_lud.json    |   9 -
 .../models/block/monitor_advanced_r.json      |   9 -
 .../models/block/monitor_advanced_rd.json     |   9 -
 .../models/block/monitor_advanced_ru.json     |   9 -
 .../models/block/monitor_advanced_rud.json    |   9 -
 .../models/block/monitor_advanced_u.json      |   9 -
 .../models/block/monitor_advanced_ud.json     |   9 -
 .../models/block/monitor_normal.json          |   9 -
 .../models/block/monitor_normal_l.json        |   9 -
 .../models/block/monitor_normal_ld.json       |   9 -
 .../models/block/monitor_normal_lr.json       |   9 -
 .../models/block/monitor_normal_lrd.json      |   9 -
 .../models/block/monitor_normal_lru.json      |   9 -
 .../models/block/monitor_normal_lrud.json     |   9 -
 .../models/block/monitor_normal_lu.json       |   9 -
 .../models/block/monitor_normal_lud.json      |   9 -
 .../models/block/monitor_normal_r.json        |   9 -
 .../models/block/monitor_normal_rd.json       |   9 -
 .../models/block/monitor_normal_ru.json       |   9 -
 .../models/block/monitor_normal_rud.json      |   9 -
 .../models/block/monitor_normal_u.json        |   9 -
 .../models/block/monitor_normal_ud.json       |   9 -
 71 files changed, 2109 insertions(+), 940 deletions(-)
 create mode 100644 src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json
 create mode 100644 src/generated/resources/assets/computercraft/blockstates/monitor_normal.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json
 create mode 100644 src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json
 create mode 100644 src/main/java/dan200/computercraft/data/BlockModelProvider.java
 delete mode 100644 src/main/resources/assets/computercraft/blockstates/monitor_advanced.json
 delete mode 100644 src/main/resources/assets/computercraft/blockstates/monitor_normal.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_l.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_r.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_u.json
 delete mode 100644 src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json

diff --git a/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json b/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json
new file mode 100644
index 000000000..978e3ed95
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json
@@ -0,0 +1,852 @@
+{
+  "variants": {
+    "facing=north,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_advanced"
+    },
+    "facing=south,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_advanced",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_advanced_l"
+    },
+    "facing=south,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_advanced_l",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_advanced_r"
+    },
+    "facing=south,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_advanced_r",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr"
+    },
+    "facing=south,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_advanced_lr",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_advanced_u"
+    },
+    "facing=south,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_advanced_u",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_advanced_d"
+    },
+    "facing=south,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_advanced_d",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud"
+    },
+    "facing=south,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_advanced_ud",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd"
+    },
+    "facing=south,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_advanced_rd",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld"
+    },
+    "facing=south,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_advanced_ld",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru"
+    },
+    "facing=south,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_advanced_ru",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu"
+    },
+    "facing=south,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_advanced_lu",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd"
+    },
+    "facing=south,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_advanced_lrd",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud"
+    },
+    "facing=south,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_advanced_rud",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud"
+    },
+    "facing=south,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_advanced_lud",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru"
+    },
+    "facing=south,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_advanced_lru",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud"
+    },
+    "facing=south,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_advanced_lrud",
+      "y": -90
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json b/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json
new file mode 100644
index 000000000..64d2d4ce9
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json
@@ -0,0 +1,852 @@
+{
+  "variants": {
+    "facing=north,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_normal"
+    },
+    "facing=south,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=none": {
+      "model": "computercraft:block/monitor_normal",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_normal_l"
+    },
+    "facing=south,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=l": {
+      "model": "computercraft:block/monitor_normal_l",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_normal_r"
+    },
+    "facing=south,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=r": {
+      "model": "computercraft:block/monitor_normal_r",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr"
+    },
+    "facing=south,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lr": {
+      "model": "computercraft:block/monitor_normal_lr",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_normal_u"
+    },
+    "facing=south,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=u": {
+      "model": "computercraft:block/monitor_normal_u",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_normal_d"
+    },
+    "facing=south,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=d": {
+      "model": "computercraft:block/monitor_normal_d",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud"
+    },
+    "facing=south,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=ud": {
+      "model": "computercraft:block/monitor_normal_ud",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd"
+    },
+    "facing=south,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=rd": {
+      "model": "computercraft:block/monitor_normal_rd",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld"
+    },
+    "facing=south,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=ld": {
+      "model": "computercraft:block/monitor_normal_ld",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru"
+    },
+    "facing=south,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=ru": {
+      "model": "computercraft:block/monitor_normal_ru",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu"
+    },
+    "facing=south,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lu": {
+      "model": "computercraft:block/monitor_normal_lu",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd"
+    },
+    "facing=south,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lrd": {
+      "model": "computercraft:block/monitor_normal_lrd",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud"
+    },
+    "facing=south,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=rud": {
+      "model": "computercraft:block/monitor_normal_rud",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud"
+    },
+    "facing=south,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lud": {
+      "model": "computercraft:block/monitor_normal_lud",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru"
+    },
+    "facing=south,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lru": {
+      "model": "computercraft:block/monitor_normal_lru",
+      "y": -90
+    },
+    "facing=north,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 90
+    },
+    "facing=south,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 90,
+      "y": 180
+    },
+    "facing=west,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 90,
+      "y": 90
+    },
+    "facing=east,orientation=down,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 90,
+      "y": -90
+    },
+    "facing=north,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 270
+    },
+    "facing=south,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 270,
+      "y": 180
+    },
+    "facing=west,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 270,
+      "y": 90
+    },
+    "facing=east,orientation=up,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "x": 270,
+      "y": -90
+    },
+    "facing=north,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud"
+    },
+    "facing=south,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "y": 180
+    },
+    "facing=west,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "y": 90
+    },
+    "facing=east,orientation=north,state=lrud": {
+      "model": "computercraft:block/monitor_normal_lrud",
+      "y": -90
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced.json
new file mode 100644
index 000000000..a13f34e05
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_16",
+    "side": "computercraft:block/monitor_advanced_4",
+    "top": "computercraft:block/monitor_advanced_0",
+    "back": "computercraft:block/monitor_advanced_32"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json
new file mode 100644
index 000000000..ff39d102c
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_d.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_20",
+    "side": "computercraft:block/monitor_advanced_7",
+    "top": "computercraft:block/monitor_advanced_0",
+    "back": "computercraft:block/monitor_advanced_36"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json
new file mode 100644
index 000000000..3bfb91292
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_l.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_19",
+    "side": "computercraft:block/monitor_advanced_4",
+    "top": "computercraft:block/monitor_advanced_1",
+    "back": "computercraft:block/monitor_advanced_33"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json
new file mode 100644
index 000000000..25269670d
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ld.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_31",
+    "side": "computercraft:block/monitor_advanced_7",
+    "top": "computercraft:block/monitor_advanced_1",
+    "back": "computercraft:block/monitor_advanced_45"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json
new file mode 100644
index 000000000..d94c3a5cf
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lr.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_18",
+    "side": "computercraft:block/monitor_advanced_4",
+    "top": "computercraft:block/monitor_advanced_2",
+    "back": "computercraft:block/monitor_advanced_34"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json
new file mode 100644
index 000000000..0de1d3268
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrd.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_30",
+    "side": "computercraft:block/monitor_advanced_7",
+    "top": "computercraft:block/monitor_advanced_2",
+    "back": "computercraft:block/monitor_advanced_46"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json
new file mode 100644
index 000000000..a28abc853
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lru.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_24",
+    "side": "computercraft:block/monitor_advanced_5",
+    "top": "computercraft:block/monitor_advanced_2",
+    "back": "computercraft:block/monitor_advanced_40"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json
new file mode 100644
index 000000000..9759d442e
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lrud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_27",
+    "side": "computercraft:block/monitor_advanced_6",
+    "top": "computercraft:block/monitor_advanced_2",
+    "back": "computercraft:block/monitor_advanced_43"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json
new file mode 100644
index 000000000..038626c68
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lu.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_25",
+    "side": "computercraft:block/monitor_advanced_5",
+    "top": "computercraft:block/monitor_advanced_1",
+    "back": "computercraft:block/monitor_advanced_39"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json
new file mode 100644
index 000000000..38e9374aa
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_lud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_28",
+    "side": "computercraft:block/monitor_advanced_6",
+    "top": "computercraft:block/monitor_advanced_1",
+    "back": "computercraft:block/monitor_advanced_42"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json
new file mode 100644
index 000000000..555aab92c
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_r.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_17",
+    "side": "computercraft:block/monitor_advanced_4",
+    "top": "computercraft:block/monitor_advanced_3",
+    "back": "computercraft:block/monitor_advanced_35"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json
new file mode 100644
index 000000000..22e0195b7
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rd.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_29",
+    "side": "computercraft:block/monitor_advanced_7",
+    "top": "computercraft:block/monitor_advanced_3",
+    "back": "computercraft:block/monitor_advanced_47"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json
new file mode 100644
index 000000000..6a503312a
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ru.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_23",
+    "side": "computercraft:block/monitor_advanced_5",
+    "top": "computercraft:block/monitor_advanced_3",
+    "back": "computercraft:block/monitor_advanced_41"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json
new file mode 100644
index 000000000..70cd94b68
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_rud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_26",
+    "side": "computercraft:block/monitor_advanced_6",
+    "top": "computercraft:block/monitor_advanced_3",
+    "back": "computercraft:block/monitor_advanced_44"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json
new file mode 100644
index 000000000..8c2271ce7
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_u.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_22",
+    "side": "computercraft:block/monitor_advanced_5",
+    "top": "computercraft:block/monitor_advanced_0",
+    "back": "computercraft:block/monitor_advanced_38"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json
new file mode 100644
index 000000000..481c8402d
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_advanced_ud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_advanced_21",
+    "side": "computercraft:block/monitor_advanced_6",
+    "top": "computercraft:block/monitor_advanced_0",
+    "back": "computercraft:block/monitor_advanced_37"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal.json
new file mode 100644
index 000000000..b08678497
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_16",
+    "side": "computercraft:block/monitor_normal_4",
+    "top": "computercraft:block/monitor_normal_0",
+    "back": "computercraft:block/monitor_normal_32"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json
new file mode 100644
index 000000000..3d6137782
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_d.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_20",
+    "side": "computercraft:block/monitor_normal_7",
+    "top": "computercraft:block/monitor_normal_0",
+    "back": "computercraft:block/monitor_normal_36"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json
new file mode 100644
index 000000000..3f863819a
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_l.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_19",
+    "side": "computercraft:block/monitor_normal_4",
+    "top": "computercraft:block/monitor_normal_1",
+    "back": "computercraft:block/monitor_normal_33"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json
new file mode 100644
index 000000000..860b84d7d
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ld.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_31",
+    "side": "computercraft:block/monitor_normal_7",
+    "top": "computercraft:block/monitor_normal_1",
+    "back": "computercraft:block/monitor_normal_45"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json
new file mode 100644
index 000000000..c69bab42d
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lr.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_18",
+    "side": "computercraft:block/monitor_normal_4",
+    "top": "computercraft:block/monitor_normal_2",
+    "back": "computercraft:block/monitor_normal_34"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json
new file mode 100644
index 000000000..3dd8543a7
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrd.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_30",
+    "side": "computercraft:block/monitor_normal_7",
+    "top": "computercraft:block/monitor_normal_2",
+    "back": "computercraft:block/monitor_normal_46"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json
new file mode 100644
index 000000000..c0fe995ee
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lru.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_24",
+    "side": "computercraft:block/monitor_normal_5",
+    "top": "computercraft:block/monitor_normal_2",
+    "back": "computercraft:block/monitor_normal_40"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json
new file mode 100644
index 000000000..61545472f
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lrud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_27",
+    "side": "computercraft:block/monitor_normal_6",
+    "top": "computercraft:block/monitor_normal_2",
+    "back": "computercraft:block/monitor_normal_43"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json
new file mode 100644
index 000000000..5572eb3bc
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lu.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_25",
+    "side": "computercraft:block/monitor_normal_5",
+    "top": "computercraft:block/monitor_normal_1",
+    "back": "computercraft:block/monitor_normal_39"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json
new file mode 100644
index 000000000..ba56cd1cd
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_lud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_28",
+    "side": "computercraft:block/monitor_normal_6",
+    "top": "computercraft:block/monitor_normal_1",
+    "back": "computercraft:block/monitor_normal_42"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json
new file mode 100644
index 000000000..bcbb7ef76
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_r.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_17",
+    "side": "computercraft:block/monitor_normal_4",
+    "top": "computercraft:block/monitor_normal_3",
+    "back": "computercraft:block/monitor_normal_35"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json
new file mode 100644
index 000000000..469f486c0
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rd.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_29",
+    "side": "computercraft:block/monitor_normal_7",
+    "top": "computercraft:block/monitor_normal_3",
+    "back": "computercraft:block/monitor_normal_47"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json
new file mode 100644
index 000000000..ca937ffa3
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ru.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_23",
+    "side": "computercraft:block/monitor_normal_5",
+    "top": "computercraft:block/monitor_normal_3",
+    "back": "computercraft:block/monitor_normal_41"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json
new file mode 100644
index 000000000..21fb19602
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_rud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_26",
+    "side": "computercraft:block/monitor_normal_6",
+    "top": "computercraft:block/monitor_normal_3",
+    "back": "computercraft:block/monitor_normal_44"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json
new file mode 100644
index 000000000..a93b45be8
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_u.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_22",
+    "side": "computercraft:block/monitor_normal_5",
+    "top": "computercraft:block/monitor_normal_0",
+    "back": "computercraft:block/monitor_normal_38"
+  }
+}
\ No newline at end of file
diff --git a/src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json
new file mode 100644
index 000000000..ff10350c8
--- /dev/null
+++ b/src/generated/resources/assets/computercraft/models/block/monitor_normal_ud.json
@@ -0,0 +1,9 @@
+{
+  "parent": "computercraft:block/monitor_base",
+  "textures": {
+    "front": "computercraft:block/monitor_normal_21",
+    "side": "computercraft:block/monitor_normal_6",
+    "top": "computercraft:block/monitor_normal_0",
+    "back": "computercraft:block/monitor_normal_37"
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java
new file mode 100644
index 000000000..0ab5c92b8
--- /dev/null
+++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java
@@ -0,0 +1,109 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
+
+package dan200.computercraft.data;
+
+import dan200.computercraft.ComputerCraft;
+import dan200.computercraft.shared.Registry;
+import dan200.computercraft.shared.peripheral.monitor.BlockMonitor;
+import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState;
+import net.minecraft.block.Block;
+import net.minecraft.data.DataGenerator;
+import net.minecraft.util.Direction;
+import net.minecraft.util.ResourceLocation;
+import net.minecraftforge.client.model.generators.*;
+
+import javax.annotation.Nonnull;
+
+public class BlockModelProvider extends BlockStateProvider
+{
+    private final ModelFile root;
+
+    public BlockModelProvider( DataGenerator generator, ExistingFileHelper existingFileHelper )
+    {
+        super( generator, ComputerCraft.MOD_ID, existingFileHelper );
+        root = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) );
+    }
+
+    @Nonnull
+    @Override
+    public String getName()
+    {
+        return "Block states and models";
+    }
+
+    @Override
+    protected void registerStatesAndModels()
+    {
+        registerMonitors( Registry.ModBlocks.MONITOR_NORMAL.get() );
+        registerMonitors( Registry.ModBlocks.MONITOR_ADVANCED.get() );
+    }
+
+    private void registerMonitors( Block block )
+    {
+        String name = block.getRegistryName().getPath();
+        registerMonitorModel( name, "", 16, 4, 0, 32 );
+        registerMonitorModel( name, "_d", 20, 7, 0, 36 );
+        registerMonitorModel( name, "_l", 19, 4, 1, 33 );
+        registerMonitorModel( name, "_ld", 31, 7, 1, 45 );
+        registerMonitorModel( name, "_lr", 18, 4, 2, 34 );
+        registerMonitorModel( name, "_lrd", 30, 7, 2, 46 );
+        registerMonitorModel( name, "_lru", 24, 5, 2, 40 );
+        registerMonitorModel( name, "_lrud", 27, 6, 2, 43 );
+        registerMonitorModel( name, "_lu", 25, 5, 1, 39 );
+        registerMonitorModel( name, "_lud", 28, 6, 1, 42 );
+        registerMonitorModel( name, "_r", 17, 4, 3, 35 );
+        registerMonitorModel( name, "_rd", 29, 7, 3, 47 );
+        registerMonitorModel( name, "_ru", 23, 5, 3, 41 );
+        registerMonitorModel( name, "_rud", 26, 6, 3, 44 );
+        registerMonitorModel( name, "_u", 22, 5, 0, 38 );
+        registerMonitorModel( name, "_ud", 21, 6, 0, 37 );
+
+        VariantBlockStateBuilder builder = getVariantBuilder( block );
+        for( MonitorEdgeState edge : BlockMonitor.STATE.getAllowedValues() )
+        {
+            String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getName();
+            ResourceLocation modelName = new ResourceLocation( ComputerCraft.MOD_ID, "block/" + name + suffix );
+            ModelFile model = models().getBuilder( modelName.toString() );
+
+            for( Direction facing : BlockMonitor.FACING.getAllowedValues() )
+            {
+                for( Direction orientation : BlockMonitor.ORIENTATION.getAllowedValues() )
+                {
+                    builder.partialState()
+                        .with( BlockMonitor.STATE, edge )
+                        .with( BlockMonitor.FACING, facing )
+                        .with( BlockMonitor.ORIENTATION, orientation )
+                        .addModels( new ConfiguredModel( model, toXAngle( orientation ), 180 - (int) facing.getHorizontalAngle(), false ) );
+                }
+            }
+        }
+    }
+
+    private void registerMonitorModel( String prefix, String corners, int front, int side, int top, int back )
+    {
+        String texturePrefix = ComputerCraft.MOD_ID + ":block/" + prefix + "_";
+        models().getBuilder( prefix + corners )
+            .parent( root )
+            .texture( "front", texturePrefix + front )
+            .texture( "side", texturePrefix + side )
+            .texture( "top", texturePrefix + top )
+            .texture( "back", texturePrefix + back );
+    }
+
+    private int toXAngle( Direction direction )
+    {
+        switch( direction )
+        {
+            default:
+                return 0;
+            case UP:
+                return 270;
+            case DOWN:
+                return 90;
+        }
+    }
+}
diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java
index 69ef83b78..8e8f931f1 100644
--- a/src/main/java/dan200/computercraft/data/Generators.java
+++ b/src/main/java/dan200/computercraft/data/Generators.java
@@ -24,5 +24,6 @@ public class Generators
         generator.addProvider( new Recipes( generator ) );
         generator.addProvider( new LootTables( generator ) );
         generator.addProvider( new Tags( generator ) );
+        generator.addProvider( new BlockModelProvider( generator, event.getExistingFileHelper() ) );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
index a6df660e4..345741c59 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
@@ -32,7 +32,7 @@ public class BlockMonitor extends BlockGeneric
 
     public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
 
-    static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class );
+    public static final EnumProperty STATE = EnumProperty.create( "state", MonitorEdgeState.class );
 
     public BlockMonitor( Properties settings, RegistryObject> type )
     {
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java
index 0ada54c82..ffc7b22df 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java
@@ -57,6 +57,12 @@ public enum MonitorEdgeState implements IStringSerializable
         return BY_FLAG[(up ? UP : 0) | (down ? DOWN : 0) | (left ? LEFT : 0) | (right ? RIGHT : 0)];
     }
 
+    @Override
+    public String toString()
+    {
+        return getName();
+    }
+
     @Nonnull
     @Override
     public String getName()
diff --git a/src/main/resources/assets/computercraft/blockstates/monitor_advanced.json b/src/main/resources/assets/computercraft/blockstates/monitor_advanced.json
deleted file mode 100644
index b55870f67..000000000
--- a/src/main/resources/assets/computercraft/blockstates/monitor_advanced.json
+++ /dev/null
@@ -1,364 +0,0 @@
-{
-    "variants": {
-        "facing=north,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced" },
-        "facing=south,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", "y": 180 },
-        "facing=west,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", "y": 270 },
-        "facing=east,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", "y": 90 },
-        "facing=north,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r" },
-        "facing=south,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 180 },
-        "facing=west,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 270 },
-        "facing=east,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 90 },
-        "facing=north,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr" },
-        "facing=south,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "y": 180 },
-        "facing=west,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "y": 270 },
-        "facing=east,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "y": 90 },
-        "facing=north,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l" },
-        "facing=south,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 180 },
-        "facing=west,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 270 },
-        "facing=east,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 90 },
-        "facing=north,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d" },
-        "facing=south,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 180 },
-        "facing=west,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 270 },
-        "facing=east,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 90 },
-        "facing=north,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud" },
-        "facing=south,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "y": 180 },
-        "facing=west,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "y": 270 },
-        "facing=east,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "y": 90 },
-        "facing=north,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u" },
-        "facing=south,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 180 },
-        "facing=west,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 270 },
-        "facing=east,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 90 },
-        "facing=north,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd" },
-        "facing=south,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "y": 180 },
-        "facing=west,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "y": 270 },
-        "facing=east,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "y": 90 },
-        "facing=north,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd" },
-        "facing=south,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "y": 180 },
-        "facing=west,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "y": 270 },
-        "facing=east,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "y": 90 },
-        "facing=north,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld" },
-        "facing=south,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "y": 180 },
-        "facing=west,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "y": 270 },
-        "facing=east,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "y": 90 },
-        "facing=north,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud" },
-        "facing=south,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "y": 180 },
-        "facing=west,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "y": 270 },
-        "facing=east,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "y": 90 },
-        "facing=north,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud" },
-        "facing=south,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "y": 180 },
-        "facing=west,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "y": 270 },
-        "facing=east,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "y": 90 },
-        "facing=north,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud" },
-        "facing=south,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "y": 180 },
-        "facing=west,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "y": 270 },
-        "facing=east,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "y": 90 },
-        "facing=north,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru" },
-        "facing=south,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "y": 180 },
-        "facing=west,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "y": 270 },
-        "facing=east,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "y": 90 },
-        "facing=north,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru" },
-        "facing=south,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "y": 180 },
-        "facing=west,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "y": 270 },
-        "facing=east,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "y": 90 },
-        "facing=north,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu" },
-        "facing=south,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "y": 180 },
-        "facing=west,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "y": 270 },
-        "facing=east,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "y": 90 },
-
-        "facing=north,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", "x": 270 },
-        "facing=south,orientation=up,state=none": {
-            "model": "computercraft:block/monitor_advanced", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=none": {
-            "model": "computercraft:block/monitor_advanced", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 270 },
-        "facing=south,orientation=up,state=r": {
-            "model": "computercraft:block/monitor_advanced_r", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 270 },
-        "facing=south,orientation=up,state=lr": {
-            "model": "computercraft:block/monitor_advanced_lr", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lr": {
-            "model": "computercraft:block/monitor_advanced_lr", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lr": {
-            "model": "computercraft:block/monitor_advanced_lr", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 270 },
-        "facing=south,orientation=up,state=l": {
-            "model": "computercraft:block/monitor_advanced_l", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 270 },
-        "facing=south,orientation=up,state=d": {
-            "model": "computercraft:block/monitor_advanced_d", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 270 },
-        "facing=south,orientation=up,state=ud": {
-            "model": "computercraft:block/monitor_advanced_ud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=ud": {
-            "model": "computercraft:block/monitor_advanced_ud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=ud": {
-            "model": "computercraft:block/monitor_advanced_ud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 270 },
-        "facing=south,orientation=up,state=u": {
-            "model": "computercraft:block/monitor_advanced_u", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 270 },
-        "facing=south,orientation=up,state=rd": {
-            "model": "computercraft:block/monitor_advanced_rd", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=rd": {
-            "model": "computercraft:block/monitor_advanced_rd", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=rd": {
-            "model": "computercraft:block/monitor_advanced_rd", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 270 },
-        "facing=south,orientation=up,state=lrd": {
-            "model": "computercraft:block/monitor_advanced_lrd", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lrd": {
-            "model": "computercraft:block/monitor_advanced_lrd", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lrd": {
-            "model": "computercraft:block/monitor_advanced_lrd", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 270 },
-        "facing=south,orientation=up,state=ld": {
-            "model": "computercraft:block/monitor_advanced_ld", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=ld": {
-            "model": "computercraft:block/monitor_advanced_ld", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=ld": {
-            "model": "computercraft:block/monitor_advanced_ld", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 270 },
-        "facing=south,orientation=up,state=rud": {
-            "model": "computercraft:block/monitor_advanced_rud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=rud": {
-            "model": "computercraft:block/monitor_advanced_rud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=rud": {
-            "model": "computercraft:block/monitor_advanced_rud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 270 },
-        "facing=south,orientation=up,state=lrud": {
-            "model": "computercraft:block/monitor_advanced_lrud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lrud": {
-            "model": "computercraft:block/monitor_advanced_lrud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lrud": {
-            "model": "computercraft:block/monitor_advanced_lrud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 270 },
-        "facing=south,orientation=up,state=lud": {
-            "model": "computercraft:block/monitor_advanced_lud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lud": {
-            "model": "computercraft:block/monitor_advanced_lud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lud": {
-            "model": "computercraft:block/monitor_advanced_lud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 270 },
-        "facing=south,orientation=up,state=ru": {
-            "model": "computercraft:block/monitor_advanced_ru", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=ru": {
-            "model": "computercraft:block/monitor_advanced_ru", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=ru": {
-            "model": "computercraft:block/monitor_advanced_ru", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 270 },
-        "facing=south,orientation=up,state=lru": {
-            "model": "computercraft:block/monitor_advanced_lru", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lru": {
-            "model": "computercraft:block/monitor_advanced_lru", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lru": {
-            "model": "computercraft:block/monitor_advanced_lru", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 270 },
-        "facing=south,orientation=up,state=lu": {
-            "model": "computercraft:block/monitor_advanced_lu", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lu": {
-            "model": "computercraft:block/monitor_advanced_lu", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lu": {
-            "model": "computercraft:block/monitor_advanced_lu", "y": 90, "x": 270
-        },
-
-        "facing=north,orientation=down,state=none": { "model": "computercraft:block/monitor_advanced", "x": 90 },
-        "facing=south,orientation=down,state=none": {
-            "model": "computercraft:block/monitor_advanced", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=none": {
-            "model": "computercraft:block/monitor_advanced", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=none": {
-            "model": "computercraft:block/monitor_advanced", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 90 },
-        "facing=south,orientation=down,state=r": {
-            "model": "computercraft:block/monitor_advanced_r", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=r": {
-            "model": "computercraft:block/monitor_advanced_r", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 90 },
-        "facing=south,orientation=down,state=lr": {
-            "model": "computercraft:block/monitor_advanced_lr", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lr": {
-            "model": "computercraft:block/monitor_advanced_lr", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lr": {
-            "model": "computercraft:block/monitor_advanced_lr", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 90 },
-        "facing=south,orientation=down,state=l": {
-            "model": "computercraft:block/monitor_advanced_l", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=l": {
-            "model": "computercraft:block/monitor_advanced_l", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 90 },
-        "facing=south,orientation=down,state=d": {
-            "model": "computercraft:block/monitor_advanced_d", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=d": {
-            "model": "computercraft:block/monitor_advanced_d", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 90 },
-        "facing=south,orientation=down,state=ud": {
-            "model": "computercraft:block/monitor_advanced_ud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=ud": {
-            "model": "computercraft:block/monitor_advanced_ud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=ud": {
-            "model": "computercraft:block/monitor_advanced_ud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 90 },
-        "facing=south,orientation=down,state=u": {
-            "model": "computercraft:block/monitor_advanced_u", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=u": {
-            "model": "computercraft:block/monitor_advanced_u", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 90 },
-        "facing=south,orientation=down,state=rd": {
-            "model": "computercraft:block/monitor_advanced_rd", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=rd": {
-            "model": "computercraft:block/monitor_advanced_rd", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=rd": {
-            "model": "computercraft:block/monitor_advanced_rd", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 90 },
-        "facing=south,orientation=down,state=lrd": {
-            "model": "computercraft:block/monitor_advanced_lrd", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lrd": {
-            "model": "computercraft:block/monitor_advanced_lrd", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lrd": {
-            "model": "computercraft:block/monitor_advanced_lrd", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 90 },
-        "facing=south,orientation=down,state=ld": {
-            "model": "computercraft:block/monitor_advanced_ld", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=ld": {
-            "model": "computercraft:block/monitor_advanced_ld", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=ld": {
-            "model": "computercraft:block/monitor_advanced_ld", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 90 },
-        "facing=south,orientation=down,state=rud": {
-            "model": "computercraft:block/monitor_advanced_rud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=rud": {
-            "model": "computercraft:block/monitor_advanced_rud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=rud": {
-            "model": "computercraft:block/monitor_advanced_rud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 90 },
-        "facing=south,orientation=down,state=lrud": {
-            "model": "computercraft:block/monitor_advanced_lrud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lrud": {
-            "model": "computercraft:block/monitor_advanced_lrud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lrud": {
-            "model": "computercraft:block/monitor_advanced_lrud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 90 },
-        "facing=south,orientation=down,state=lud": {
-            "model": "computercraft:block/monitor_advanced_lud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lud": {
-            "model": "computercraft:block/monitor_advanced_lud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lud": {
-            "model": "computercraft:block/monitor_advanced_lud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 90 },
-        "facing=south,orientation=down,state=ru": {
-            "model": "computercraft:block/monitor_advanced_ru", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=ru": {
-            "model": "computercraft:block/monitor_advanced_ru", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=ru": {
-            "model": "computercraft:block/monitor_advanced_ru", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 90 },
-        "facing=south,orientation=down,state=lru": {
-            "model": "computercraft:block/monitor_advanced_lru", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lru": {
-            "model": "computercraft:block/monitor_advanced_lru", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lru": {
-            "model": "computercraft:block/monitor_advanced_lru", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 90 },
-        "facing=south,orientation=down,state=lu": {
-            "model": "computercraft:block/monitor_advanced_lu", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lu": {
-            "model": "computercraft:block/monitor_advanced_lu", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lu": {
-            "model": "computercraft:block/monitor_advanced_lu", "y": 90, "x": 90
-        }
-    }
-}
diff --git a/src/main/resources/assets/computercraft/blockstates/monitor_normal.json b/src/main/resources/assets/computercraft/blockstates/monitor_normal.json
deleted file mode 100644
index b14a45a21..000000000
--- a/src/main/resources/assets/computercraft/blockstates/monitor_normal.json
+++ /dev/null
@@ -1,296 +0,0 @@
-{
-    "variants": {
-        "facing=north,orientation=north,state=none": { "model": "computercraft:block/monitor_normal" },
-        "facing=south,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", "y": 180 },
-        "facing=west,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", "y": 270 },
-        "facing=east,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", "y": 90 },
-        "facing=north,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r" },
-        "facing=south,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 180 },
-        "facing=west,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 270 },
-        "facing=east,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 90 },
-        "facing=north,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr" },
-        "facing=south,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 180 },
-        "facing=west,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 270 },
-        "facing=east,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 90 },
-        "facing=north,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l" },
-        "facing=south,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 180 },
-        "facing=west,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 270 },
-        "facing=east,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 90 },
-        "facing=north,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d" },
-        "facing=south,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 180 },
-        "facing=west,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 270 },
-        "facing=east,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 90 },
-        "facing=north,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud" },
-        "facing=south,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 180 },
-        "facing=west,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 270 },
-        "facing=east,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 90 },
-        "facing=north,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u" },
-        "facing=south,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 180 },
-        "facing=west,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 270 },
-        "facing=east,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 90 },
-        "facing=north,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd" },
-        "facing=south,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 180 },
-        "facing=west,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 270 },
-        "facing=east,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 90 },
-        "facing=north,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd" },
-        "facing=south,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "y": 180 },
-        "facing=west,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "y": 270 },
-        "facing=east,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "y": 90 },
-        "facing=north,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld" },
-        "facing=south,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 180 },
-        "facing=west,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 270 },
-        "facing=east,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 90 },
-        "facing=north,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud" },
-        "facing=south,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", "y": 180 },
-        "facing=west,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", "y": 270 },
-        "facing=east,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", "y": 90 },
-        "facing=north,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud" },
-        "facing=south,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "y": 180 },
-        "facing=west,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "y": 270 },
-        "facing=east,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "y": 90 },
-        "facing=north,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud" },
-        "facing=south,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", "y": 180 },
-        "facing=west,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", "y": 270 },
-        "facing=east,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", "y": 90 },
-        "facing=north,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru" },
-        "facing=south,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 180 },
-        "facing=west,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 270 },
-        "facing=east,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 90 },
-        "facing=north,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru" },
-        "facing=south,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", "y": 180 },
-        "facing=west,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", "y": 270 },
-        "facing=east,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", "y": 90 },
-        "facing=north,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu" },
-        "facing=south,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 180 },
-        "facing=west,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 270 },
-        "facing=east,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 90 },
-
-        "facing=north,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "x": 270 },
-        "facing=south,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "y": 180, "x": 270 },
-        "facing=west,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 270 },
-        "facing=south,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 180, "x": 270 },
-        "facing=west,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 270 },
-        "facing=south,orientation=up,state=lr": {
-            "model": "computercraft:block/monitor_normal_lr", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 270 },
-        "facing=south,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 180, "x": 270 },
-        "facing=west,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 270 },
-        "facing=south,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 180, "x": 270 },
-        "facing=west,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 270 },
-        "facing=south,orientation=up,state=ud": {
-            "model": "computercraft:block/monitor_normal_ud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 270 },
-        "facing=south,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 180, "x": 270 },
-        "facing=west,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 270 },
-        "facing=south,orientation=up,state=rd": {
-            "model": "computercraft:block/monitor_normal_rd", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 270 },
-        "facing=south,orientation=up,state=lrd": {
-            "model": "computercraft:block/monitor_normal_lrd", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lrd": {
-            "model": "computercraft:block/monitor_normal_lrd", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lrd": {
-            "model": "computercraft:block/monitor_normal_lrd", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 270 },
-        "facing=south,orientation=up,state=ld": {
-            "model": "computercraft:block/monitor_normal_ld", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 270 },
-        "facing=south,orientation=up,state=rud": {
-            "model": "computercraft:block/monitor_normal_rud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=rud": {
-            "model": "computercraft:block/monitor_normal_rud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=rud": {
-            "model": "computercraft:block/monitor_normal_rud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 270 },
-        "facing=south,orientation=up,state=lrud": {
-            "model": "computercraft:block/monitor_normal_lrud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lrud": {
-            "model": "computercraft:block/monitor_normal_lrud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lrud": {
-            "model": "computercraft:block/monitor_normal_lrud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 270 },
-        "facing=south,orientation=up,state=lud": {
-            "model": "computercraft:block/monitor_normal_lud", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lud": {
-            "model": "computercraft:block/monitor_normal_lud", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lud": {
-            "model": "computercraft:block/monitor_normal_lud", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 270 },
-        "facing=south,orientation=up,state=ru": {
-            "model": "computercraft:block/monitor_normal_ru", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 90, "x": 270 },
-        "facing=north,orientation=up,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 270 },
-        "facing=south,orientation=up,state=lru": {
-            "model": "computercraft:block/monitor_normal_lru", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lru": {
-            "model": "computercraft:block/monitor_normal_lru", "y": 270, "x": 270
-        },
-        "facing=east,orientation=up,state=lru": {
-            "model": "computercraft:block/monitor_normal_lru", "y": 90, "x": 270
-        },
-        "facing=north,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 270 },
-        "facing=south,orientation=up,state=lu": {
-            "model": "computercraft:block/monitor_normal_lu", "y": 180, "x": 270
-        },
-        "facing=west,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 270, "x": 270 },
-        "facing=east,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 90, "x": 270 },
-
-        "facing=north,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "x": 90 },
-        "facing=south,orientation=down,state=none": {
-            "model": "computercraft:block/monitor_normal", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "y": 270, "x": 90 },
-        "facing=east,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 90 },
-        "facing=south,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 180, "x": 90 },
-        "facing=west,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 270, "x": 90 },
-        "facing=east,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 90 },
-        "facing=south,orientation=down,state=lr": {
-            "model": "computercraft:block/monitor_normal_lr", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lr": {
-            "model": "computercraft:block/monitor_normal_lr", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 90 },
-        "facing=south,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 180, "x": 90 },
-        "facing=west,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 270, "x": 90 },
-        "facing=east,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 90 },
-        "facing=south,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 180, "x": 90 },
-        "facing=west,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 270, "x": 90 },
-        "facing=east,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 90 },
-        "facing=south,orientation=down,state=ud": {
-            "model": "computercraft:block/monitor_normal_ud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=ud": {
-            "model": "computercraft:block/monitor_normal_ud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 90 },
-        "facing=south,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 180, "x": 90 },
-        "facing=west,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 270, "x": 90 },
-        "facing=east,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 90 },
-        "facing=south,orientation=down,state=rd": {
-            "model": "computercraft:block/monitor_normal_rd", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=rd": {
-            "model": "computercraft:block/monitor_normal_rd", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 90 },
-        "facing=south,orientation=down,state=lrd": {
-            "model": "computercraft:block/monitor_normal_lrd", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lrd": {
-            "model": "computercraft:block/monitor_normal_lrd", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lrd": {
-            "model": "computercraft:block/monitor_normal_lrd", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 90 },
-        "facing=south,orientation=down,state=ld": {
-            "model": "computercraft:block/monitor_normal_ld", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=ld": {
-            "model": "computercraft:block/monitor_normal_ld", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 90 },
-        "facing=south,orientation=down,state=rud": {
-            "model": "computercraft:block/monitor_normal_rud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=rud": {
-            "model": "computercraft:block/monitor_normal_rud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=rud": {
-            "model": "computercraft:block/monitor_normal_rud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 90 },
-        "facing=south,orientation=down,state=lrud": {
-            "model": "computercraft:block/monitor_normal_lrud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lrud": {
-            "model": "computercraft:block/monitor_normal_lrud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lrud": {
-            "model": "computercraft:block/monitor_normal_lrud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 90 },
-        "facing=south,orientation=down,state=lud": {
-            "model": "computercraft:block/monitor_normal_lud", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lud": {
-            "model": "computercraft:block/monitor_normal_lud", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lud": {
-            "model": "computercraft:block/monitor_normal_lud", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 90 },
-        "facing=south,orientation=down,state=ru": {
-            "model": "computercraft:block/monitor_normal_ru", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=ru": {
-            "model": "computercraft:block/monitor_normal_ru", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", "y": 90, "x": 90 },
-        "facing=north,orientation=down,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 90 },
-        "facing=south,orientation=down,state=lru": {
-            "model": "computercraft:block/monitor_normal_lru", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lru": {
-            "model": "computercraft:block/monitor_normal_lru", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lru": {
-            "model": "computercraft:block/monitor_normal_lru", "y": 90, "x": 90
-        },
-        "facing=north,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 90 },
-        "facing=south,orientation=down,state=lu": {
-            "model": "computercraft:block/monitor_normal_lu", "y": 180, "x": 90
-        },
-        "facing=west,orientation=down,state=lu": {
-            "model": "computercraft:block/monitor_normal_lu", "y": 270, "x": 90
-        },
-        "facing=east,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", "y": 90, "x": 90 }
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced.json
deleted file mode 100644
index 3ff0ed5dc..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_16",
-        "side": "computercraft:block/monitor_advanced_4",
-        "top": "computercraft:block/monitor_advanced_0",
-        "back": "computercraft:block/monitor_advanced_4"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json
deleted file mode 100644
index d8936956d..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_d.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_20",
-        "side": "computercraft:block/monitor_advanced_36",
-        "top": "computercraft:block/monitor_advanced_0",
-        "back": "computercraft:block/monitor_advanced_36"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json
deleted file mode 100644
index 3abee2204..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_l.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_19",
-        "side": "computercraft:block/monitor_advanced_4",
-        "top": "computercraft:block/monitor_advanced_1",
-        "back": "computercraft:block/monitor_advanced_33"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json
deleted file mode 100644
index ee054dbc8..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ld.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_31",
-        "side": "computercraft:block/monitor_advanced_7",
-        "top": "computercraft:block/monitor_advanced_1",
-        "back": "computercraft:block/monitor_advanced_45"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json
deleted file mode 100644
index 320c8d354..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lr.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_18",
-        "side": "computercraft:block/monitor_advanced_4",
-        "top": "computercraft:block/monitor_advanced_2",
-        "back": "computercraft:block/monitor_advanced_34"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json
deleted file mode 100644
index 5f7a43407..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrd.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_30",
-        "side": "computercraft:block/monitor_advanced_7",
-        "top": "computercraft:block/monitor_advanced_2",
-        "back": "computercraft:block/monitor_advanced_46"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json
deleted file mode 100644
index 56acdd077..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lru.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_24",
-        "side": "computercraft:block/monitor_advanced_38",
-        "top": "computercraft:block/monitor_advanced_2",
-        "back": "computercraft:block/monitor_advanced_40"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json
deleted file mode 100644
index dce3c2baf..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lrud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_27",
-        "side": "computercraft:block/monitor_advanced_37",
-        "top": "computercraft:block/monitor_advanced_2",
-        "back": "computercraft:block/monitor_advanced_43"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json
deleted file mode 100644
index 905ebdce3..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lu.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_25",
-        "side": "computercraft:block/monitor_advanced_38",
-        "top": "computercraft:block/monitor_advanced_1",
-        "back": "computercraft:block/monitor_advanced_39"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json
deleted file mode 100644
index 43b110c03..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_lud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_28",
-        "side": "computercraft:block/monitor_advanced_37",
-        "top": "computercraft:block/monitor_advanced_1",
-        "back": "computercraft:block/monitor_advanced_42"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json
deleted file mode 100644
index 03d1d386f..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_r.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_17",
-        "side": "computercraft:block/monitor_advanced_4",
-        "top": "computercraft:block/monitor_advanced_3",
-        "back": "computercraft:block/monitor_advanced_35"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json
deleted file mode 100644
index 4ded80dba..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rd.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_29",
-        "side": "computercraft:block/monitor_advanced_7",
-        "top": "computercraft:block/monitor_advanced_3",
-        "back": "computercraft:block/monitor_advanced_47"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json
deleted file mode 100644
index 67cd36920..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ru.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_23",
-        "side": "computercraft:block/monitor_advanced_38",
-        "top": "computercraft:block/monitor_advanced_3",
-        "back": "computercraft:block/monitor_advanced_41"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json
deleted file mode 100644
index 0573ad049..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_rud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_26",
-        "side": "computercraft:block/monitor_advanced_37",
-        "top": "computercraft:block/monitor_advanced_3",
-        "back": "computercraft:block/monitor_advanced_44"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json
deleted file mode 100644
index bdc9f7a2d..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_u.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_22",
-        "side": "computercraft:block/monitor_advanced_38",
-        "top": "computercraft:block/monitor_advanced_0",
-        "back": "computercraft:block/monitor_advanced_38"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json b/src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json
deleted file mode 100644
index 3987b109f..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_advanced_ud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_advanced_21",
-        "side": "computercraft:block/monitor_advanced_37",
-        "top": "computercraft:block/monitor_advanced_0",
-        "back": "computercraft:block/monitor_advanced_37"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal.json b/src/main/resources/assets/computercraft/models/block/monitor_normal.json
deleted file mode 100644
index e7a669695..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_16",
-        "side": "computercraft:block/monitor_normal_4",
-        "top": "computercraft:block/monitor_normal_0",
-        "back": "computercraft:block/monitor_normal_4"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_l.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_l.json
deleted file mode 100644
index def167210..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_l.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_19",
-        "side": "computercraft:block/monitor_normal_4",
-        "top": "computercraft:block/monitor_normal_1",
-        "back": "computercraft:block/monitor_normal_33"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json
deleted file mode 100644
index 410d65029..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_ld.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_31",
-        "side": "computercraft:block/monitor_normal_7",
-        "top": "computercraft:block/monitor_normal_1",
-        "back": "computercraft:block/monitor_normal_45"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json
deleted file mode 100644
index 36243944d..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lr.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_18",
-        "side": "computercraft:block/monitor_normal_4",
-        "top": "computercraft:block/monitor_normal_2",
-        "back": "computercraft:block/monitor_normal_34"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json
deleted file mode 100644
index 1fe673561..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrd.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_30",
-        "side": "computercraft:block/monitor_normal_7",
-        "top": "computercraft:block/monitor_normal_2",
-        "back": "computercraft:block/monitor_normal_46"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json
deleted file mode 100644
index d6c5b2ce4..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lru.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_24",
-        "side": "computercraft:block/monitor_normal_38",
-        "top": "computercraft:block/monitor_normal_2",
-        "back": "computercraft:block/monitor_normal_40"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json
deleted file mode 100644
index ba96ee76d..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lrud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_27",
-        "side": "computercraft:block/monitor_normal_37",
-        "top": "computercraft:block/monitor_normal_2",
-        "back": "computercraft:block/monitor_normal_43"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json
deleted file mode 100644
index 444408d25..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lu.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_25",
-        "side": "computercraft:block/monitor_normal_38",
-        "top": "computercraft:block/monitor_normal_1",
-        "back": "computercraft:block/monitor_normal_39"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json
deleted file mode 100644
index 28f06d420..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_lud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_28",
-        "side": "computercraft:block/monitor_normal_37",
-        "top": "computercraft:block/monitor_normal_1",
-        "back": "computercraft:block/monitor_normal_42"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_r.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_r.json
deleted file mode 100644
index 8b8eb4df1..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_r.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_17",
-        "side": "computercraft:block/monitor_normal_4",
-        "top": "computercraft:block/monitor_normal_3",
-        "back": "computercraft:block/monitor_normal_35"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json
deleted file mode 100644
index 61d7d1231..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_rd.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_29",
-        "side": "computercraft:block/monitor_normal_7",
-        "top": "computercraft:block/monitor_normal_3",
-        "back": "computercraft:block/monitor_normal_47"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json
deleted file mode 100644
index ddb474736..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_ru.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_23",
-        "side": "computercraft:block/monitor_normal_38",
-        "top": "computercraft:block/monitor_normal_3",
-        "back": "computercraft:block/monitor_normal_41"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json
deleted file mode 100644
index a8f272995..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_rud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_26",
-        "side": "computercraft:block/monitor_normal_37",
-        "top": "computercraft:block/monitor_normal_3",
-        "back": "computercraft:block/monitor_normal_44"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_u.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_u.json
deleted file mode 100644
index c7d67619b..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_u.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_22",
-        "side": "computercraft:block/monitor_normal_38",
-        "top": "computercraft:block/monitor_normal_0",
-        "back": "computercraft:block/monitor_normal_38"
-    }
-}
diff --git a/src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json b/src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json
deleted file mode 100644
index 0cbadcc4b..000000000
--- a/src/main/resources/assets/computercraft/models/block/monitor_normal_ud.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "parent": "computercraft:block/monitor_base",
-    "textures": {
-        "front": "computercraft:block/monitor_normal_21",
-        "side": "computercraft:block/monitor_normal_37",
-        "top": "computercraft:block/monitor_normal_0",
-        "back": "computercraft:block/monitor_normal_37"
-    }
-}

From a4c9e89370ddb80ec4cf8f9560c585b5b61cc7dc Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Thu, 12 Nov 2020 19:01:50 +0000
Subject: [PATCH 362/711] Runnable examples (#576)

Provides a basic interface for running examples on tweaked.cc. This is probably
janky as anything, but it works on my machine.

This is the culmination of 18 months of me building far too much infrastructure
(copy-cat, illuaminate), so that's nice I guess.

I should probably get out more.
---
 .editorconfig                   |   1 -
 .github/workflows/make-doc.sh   |   2 +-
 .github/workflows/make-doc.yml  |  18 ++--
 .gitignore                      |  10 +-
 build.gradle                    |  52 +++++++++-
 doc/styles.css                  |  14 ---
 illuaminate.sexp                |  24 +++--
 package-lock.json               | 172 ++++++++++++++++++++++++++++++++
 package.json                    |  18 ++++
 rollup.config.js                |  49 +++++++++
 src/web/copy-cat.d.ts           |  21 ++++
 src/web/index.tsx               | 155 ++++++++++++++++++++++++++++
 src/web/mount/.settings         |   3 +
 src/web/mount/expr_template.lua |  14 +++
 src/web/mount/startup.lua       |   5 +
 src/web/styles.css              |  85 ++++++++++++++++
 tools/check-lines.py            |   2 +-
 tsconfig.json                   |  34 +++++++
 18 files changed, 639 insertions(+), 40 deletions(-)
 delete mode 100644 doc/styles.css
 create mode 100644 package-lock.json
 create mode 100644 package.json
 create mode 100644 rollup.config.js
 create mode 100644 src/web/copy-cat.d.ts
 create mode 100644 src/web/index.tsx
 create mode 100644 src/web/mount/.settings
 create mode 100644 src/web/mount/expr_template.lua
 create mode 100644 src/web/mount/startup.lua
 create mode 100644 src/web/styles.css
 create mode 100644 tsconfig.json

diff --git a/.editorconfig b/.editorconfig
index d57b269a4..f5f23d8d4 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,6 +17,5 @@ indent_size = 2
 [*.yml]
 indent_size = 2
 
-
 [*.properties]
 insert_final_newline = false
diff --git a/.github/workflows/make-doc.sh b/.github/workflows/make-doc.sh
index f7446f84c..f86ef60f0 100755
--- a/.github/workflows/make-doc.sh
+++ b/.github/workflows/make-doc.sh
@@ -12,5 +12,5 @@ chmod 600 "$HOME/.ssh/key"
 
 # And upload
 rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
-      "$GITHUB_WORKSPACE/doc/out/" \
+      "$GITHUB_WORKSPACE/build/docs/lua/" \
       "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST"
diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml
index 3abf5d265..18ce815a5 100644
--- a/.github/workflows/make-doc.yml
+++ b/.github/workflows/make-doc.yml
@@ -30,18 +30,20 @@ jobs:
         restore-keys: |
           ${{ runner.os }}-gradle-
 
-    - name: Build with Gradle
-      run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon
-
-    - name: Generate Java documentation stubs
-      run: ./gradlew luaJavadoc --no-daemon
-
-    - name: Build documentation
+    - name: Setup illuaminate
       run: |
         test -d bin || mkdir bin
         test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
         chmod +x bin/illuaminate
-        bin/illuaminate doc-gen
+
+    - name: Setup node
+      run: npm ci
+
+    - name: Build with Gradle
+      run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon
+
+    - name: Generate documentation
+      run: ./gradlew docWebsite --no-daemon
 
     - name: Upload documentation
       run: .github/workflows/make-doc.sh 2> /dev/null
diff --git a/.gitignore b/.gitignore
index 84f17aee8..808032e6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,7 @@
 /build
 /out
 /doc/out/
-/doc/javadoc/
+/node_modules
 
 # Runtime directories
 /run
@@ -18,10 +18,12 @@
 .gradle
 *.DS_Store
 
-.classpath
-.project
-.settings/
+/.classpath
+/.project
+/.settings
+/.vscode
 bin/
 *.launch
 
 /src/generated/resources/.cache
+/src/web/mount/*.d.ts
diff --git a/build.gradle b/build.gradle
index 33a414ab9..5c36a17fd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -136,7 +136,7 @@ task luaJavadoc(type: Javadoc) {
     group "documentation"
 
     source = sourceSets.main.allJava
-    destinationDir = file("doc/javadoc")
+    destinationDir = file("${project.docsDir}/luaJavadoc")
     classpath = sourceSets.main.compileClasspath
 
     options.docletpath = configurations.cctJavadoc.files as List
@@ -306,6 +306,56 @@ task compressJson(dependsOn: jar) {
 
 assemble.dependsOn compressJson
 
+// Web tasks
+
+import org.apache.tools.ant.taskdefs.condition.Os
+
+List mkCommand(String command) {
+    return Os.isFamily(Os.FAMILY_WINDOWS) ? ["cmd", "/c", command] : ["sh", "-c", command]
+}
+
+task rollup(type: Exec) {
+    group = "build"
+    description = "Bundles JS into rollup"
+
+    inputs.files(fileTree("src/web")).withPropertyName("sources")
+    inputs.file("package-lock.json").withPropertyName("package-lock.json")
+    inputs.file("tsconfig.json").withPropertyName("Typescript config")
+    inputs.file("rollup.config.js").withPropertyName("Rollup config")
+    outputs.file("$buildDir/rollup/index.js").withPropertyName("output")
+
+    commandLine mkCommand('"node_modules/.bin/rollup" --config rollup.config.js')
+}
+
+task minifyWeb(type: Exec, dependsOn: rollup) {
+    group = "build"
+    description = "Bundles JS into rollup"
+
+    inputs.file("$buildDir/rollup/index.js").withPropertyName("sources")
+    inputs.file("package-lock.json").withPropertyName("package-lock.json")
+    outputs.file("$buildDir/rollup/index.min.js").withPropertyName("output")
+
+    commandLine mkCommand('"node_modules/.bin/terser"' + " -o $buildDir/rollup/index.min.js $buildDir/rollup/index.js")
+}
+
+task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) {
+    group = "build"
+    description = "Bundles JS into rollup"
+
+    inputs.files(fileTree("doc")).withPropertyName("sources")
+    inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp")
+    inputs.file("$buildDir/rollup/index.min.js").withPropertyName("scripts")
+    inputs.file("src/web/styles.css").withPropertyName("styles")
+    outputs.dir("$buildDir/docs/lua")
+
+    commandLine mkCommand('"bin/illuaminate" doc-gen')
+}
+
+task docWebsite(type: Copy, dependsOn: [illuaminateDocs]) {
+    from 'doc/logo.png'
+    into "${project.docsDir}/lua"
+}
+
 // Check tasks
 
 test {
diff --git a/doc/styles.css b/doc/styles.css
deleted file mode 100644
index a21b9ac34..000000000
--- a/doc/styles.css
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Pretty tables, mostly inherited from table.definition-list */
-table.pretty-table {
-    border-collapse: collapse;
-    width: 100%;
-}
-
-table.pretty-table td, table.pretty-table th {
-    border: 1px solid #cccccc;
-    padding: 2px 4px;
-}
-
-table.pretty-table th {
-    background-color: #f0f0f0;
-}
diff --git a/illuaminate.sexp b/illuaminate.sexp
index 558028975..80a481a64 100644
--- a/illuaminate.sexp
+++ b/illuaminate.sexp
@@ -2,18 +2,20 @@
 
 (sources
   /doc/stub/
-  /doc/javadoc/
+  /build/docs/luaJavadoc/
   /src/main/resources/*/computercraft/lua/bios.lua
   /src/main/resources/*/computercraft/lua/rom/
-  /src/test/resources/test-rom)
+  /src/test/resources/test-rom
+  /src/web/mount)
 
 
 (doc
   (title "CC: Tweaked")
-  (destination doc/out)
+  (destination build/docs/lua)
   (logo src/main/resources/pack.png)
   (index doc/index.md)
-  (styles doc/styles.css)
+  (styles src/web/styles.css)
+  (scripts build/rollup/index.js)
   (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line})
 
   (module-kinds
@@ -21,7 +23,7 @@
 
   (library-path
     /doc/stub/
-    /doc/javadoc/
+    /build/docs/luaJavadoc/
 
     /src/main/resources/*/computercraft/lua/rom/apis
     /src/main/resources/*/computercraft/lua/rom/apis/command
@@ -72,7 +74,7 @@
   (lint (allow-toplevel-global true)))
 
 ;; Silence some variable warnings in documentation stubs.
-(at (/doc/stub/ /doc/javadoc/)
+(at (/doc/stub/ /build/docs/luaJavadoc/)
   (linters -var:unused-global)
   (lint (allow-toplevel-global true)))
 
@@ -84,11 +86,11 @@
    /doc/stub/turtle.lua
    /doc/stub/global.lua
    ; Java generated APIs
-   /doc/javadoc/turtle.lua
+   /build/docs/luaJavadoc/turtle.lua
    ; Peripherals
-   /doc/javadoc/drive.lua
-   /doc/javadoc/speaker.lua
-   /doc/javadoc/printer.lua
+   /build/docs/luaJavadoc/drive.lua
+   /build/docs/luaJavadoc/speaker.lua
+   /build/docs/luaJavadoc/printer.lua
    ; Lua APIs
    /src/main/resources/*/computercraft/lua/rom/apis/io.lua
    /src/main/resources/*/computercraft/lua/rom/apis/window.lua)
@@ -116,3 +118,5 @@
     (globals
       :max sleep write
       cct_test describe expect howlci fail it pending stub)))
+
+(at /src/web/mount/expr_template.lua (lint (globals :max __expr__)))
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..b12022dac
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,172 @@
+{
+  "name": "tweaked.cc",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@rollup/plugin-typescript": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-6.1.0.tgz",
+      "integrity": "sha512-hJxaiE6WyNOsK+fZpbFh9CUijZYqPQuAOWO5khaGTUkM8DYNNyA2TDlgamecE+qLOG1G1+CwbWMAx3rbqpp6xQ==",
+      "dev": true,
+      "requires": {
+        "@rollup/pluginutils": "^3.1.0",
+        "resolve": "^1.17.0"
+      }
+    },
+    "@rollup/pluginutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+      "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "0.0.39",
+        "estree-walker": "^1.0.1",
+        "picomatch": "^2.2.2"
+      }
+    },
+    "@types/estree": {
+      "version": "0.0.39",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+      "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+      "dev": true
+    },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "estree-walker": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+      "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+      "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+      "dev": true,
+      "optional": true
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "is-core-module": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
+      "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "path-parse": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+      "dev": true
+    },
+    "picomatch": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+      "dev": true
+    },
+    "preact": {
+      "version": "10.5.5",
+      "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.5.tgz",
+      "integrity": "sha512-5ONLNH1SXMzzbQoExZX4TELemNt+TEDb622xXFNfZngjjM9qtrzseJt+EfiUu4TZ6EJ95X5sE1ES4yqHFSIdhg=="
+    },
+    "requirejs": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
+      "integrity": "sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==",
+      "dev": true
+    },
+    "resolve": {
+      "version": "1.18.1",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
+      "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==",
+      "dev": true,
+      "requires": {
+        "is-core-module": "^2.0.0",
+        "path-parse": "^1.0.6"
+      }
+    },
+    "rollup": {
+      "version": "2.33.1",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.1.tgz",
+      "integrity": "sha512-uY4O/IoL9oNW8MMcbA5hcOaz6tZTMIh7qJHx/tzIJm+n1wLoY38BLn6fuy7DhR57oNFLMbDQtDeJoFURt5933w==",
+      "dev": true,
+      "requires": {
+        "fsevents": "~2.1.2"
+      }
+    },
+    "source-map": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+      "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "terser": {
+      "version": "5.3.8",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.8.tgz",
+      "integrity": "sha512-zVotuHoIfnYjtlurOouTazciEfL7V38QMAOhGqpXDEg6yT13cF4+fEP9b0rrCEQTn+tT46uxgFsTZzhygk+CzQ==",
+      "dev": true,
+      "requires": {
+        "commander": "^2.20.0",
+        "source-map": "~0.7.2",
+        "source-map-support": "~0.5.19"
+      }
+    },
+    "tslib": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
+      "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
+    },
+    "typescript": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.5.tgz",
+      "integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==",
+      "dev": true
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..682f93de0
--- /dev/null
+++ b/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "tweaked.cc",
+  "version": "1.0.0",
+  "description": "Website additions for tweaked.cc",
+  "author": "SquidDev",
+  "license": "BSD-3-Clause",
+  "dependencies": {
+    "preact": "^10.5.5",
+    "tslib": "^2.0.3"
+  },
+  "devDependencies": {
+    "@rollup/plugin-typescript": "^6.1.0",
+    "requirejs": "^2.3.6",
+    "rollup": "^2.33.1",
+    "terser": "^5.3.8",
+    "typescript": "^4.0.5"
+  }
+}
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 000000000..1e0342fea
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,49 @@
+import { readFileSync, promises as fs } from "fs";
+import path from "path";
+
+import typescript from "@rollup/plugin-typescript";
+
+const input = "src/web";
+const requirejs = readFileSync("node_modules/requirejs/require.js");
+
+export default {
+    input: [`${input}/index.tsx`],
+    output: {
+        file: "build/rollup/index.js",
+        // We bundle requirejs (and config) into the header. It's rather gross
+        // but also works reasonably well.
+        banner: `${requirejs}\nrequire.config({ paths: { copycat: "https://copy-cat.squiddev.cc" } });`,
+        format: "amd",
+        preferConst: true,
+        amd: {
+            define: "require",
+        }
+    },
+    context: "window",
+    external: ["copycat/embed"],
+
+    plugins: [
+        typescript(),
+
+        {
+            name: "cc-tweaked",
+            async options(options) {
+                // Generate .d.ts files for all /mount files. This is the worst way to do it,
+                // but we need to run before the TS pass.
+                const template = "declare const contents : string;\nexport default contents;\n";
+                const files = await fs.readdir(`${input}/mount`);
+
+                await Promise.all(files
+                    .filter(x => path.extname(x) !== ".ts")
+                    .map(file => fs.writeFile(`${input}/mount/${file}.d.ts`, template))
+                );
+                return options;
+            },
+            async transform(code, file) {
+                // Allow loading files in /mount.
+                if (path.extname(file) != ".lua" && path.basename(file) != ".settings") return null;
+                return `export default ${JSON.stringify(code)};\n`;
+            },
+        }
+    ],
+};
diff --git a/src/web/copy-cat.d.ts b/src/web/copy-cat.d.ts
new file mode 100644
index 000000000..b4a85d267
--- /dev/null
+++ b/src/web/copy-cat.d.ts
@@ -0,0 +1,21 @@
+import { h, Component, render, ComponentChild } from "preact";
+
+export { h, Component, render };
+
+export type ComputerAccess = unknown;
+
+export type MainProps = {
+  hdFont?: boolean | string,
+  persistId?: number,
+  files?: { [filename: string]: string | ArrayBuffer },
+  label?: string,
+  width?: number,
+  height?: number,
+  resolve?: (computer: ComputerAccess) => void,
+}
+
+declare class Computer extends Component {
+  public render(props: MainProps, state: unknown): ComponentChild;
+}
+
+export { Computer };
diff --git a/src/web/index.tsx b/src/web/index.tsx
new file mode 100644
index 000000000..0bf476a86
--- /dev/null
+++ b/src/web/index.tsx
@@ -0,0 +1,155 @@
+import { render, h, Component, Computer } from "copycat/embed";
+import type { ComponentChild } from "preact";
+
+import settingsFile from "./mount/.settings";
+import startupFile from "./mount/startup.lua";
+import exprTemplate from "./mount/expr_template.lua";
+
+const defaultFiles: { [filename: string]: string } = {
+    ".settings": settingsFile,
+    "startup.lua": startupFile,
+};
+
+const clamp = (value: number, min: number, max: number): number => {
+    if (value < min) return min;
+    if (value > max) return max;
+    return value;
+}
+
+const Click = (options: { run: () => void }) =>
+    
+
+type WindowProps = {};
+
+type WindowState = {
+    visible: boolean,
+
+    example: string,
+    exampleIdx: number,
+}
+
+type Touch = { clientX: number, clientY: number };
+
+class Window extends Component {
+    private positioned: boolean = false;
+    private left: number = 0;
+    private top: number = 0;
+    private dragging?: { downX: number, downY: number, initialX: number, initialY: number };
+
+    constructor(props: WindowProps, context: unknown) {
+        super(props, context);
+
+        this.state = {
+            visible: false,
+            example: "",
+            exampleIdx: 0,
+        }
+    }
+
+    componentDidMount() {
+        const elements = document.querySelectorAll("pre[data-lua-kind]");
+        for (let i = 0; i < elements.length; i++) {
+            const element = elements[i] as HTMLElement;
+
+            let example = element.innerText;
+            if (element.getAttribute("data-lua-kind") == "expr") {
+                example = exprTemplate.replace("__expr__", example);
+            }
+            render(, element);
+        }
+    }
+
+    componentDidUpdate(_: WindowProps, { visible }: WindowState) {
+        if (!visible && this.state.visible) this.setPosition(this.left, this.top);
+    }
+
+    public render(_: WindowProps, { visible, example, exampleIdx }: WindowState): ComponentChild {
+        return visible ? 
+
+
+ +
+
+ +
+
:
; + } + + private runExample(example: string): () => void { + return () => { + if (!this.positioned) { + this.positioned = true; + this.left = 20; + this.top = 20; + } + + this.setState(({ exampleIdx }: WindowState) => ({ + visible: true, + example: example, + exampleIdx: exampleIdx + 1, + })); + } + } + + private readonly close = () => this.setState({ visible: false }); + + // All the dragging code is terrible. However, I've had massive performance + // issues doing it other ways, so this'll have to do. + private onDown(e: Event, touch: Touch) { + e.stopPropagation(); + e.preventDefault(); + + this.dragging = { + initialX: this.left, initialY: this.top, + downX: touch.clientX, downY: touch.clientY + }; + + window.addEventListener("mousemove", this.onMouseDrag, true); + window.addEventListener("touchmove", this.onTouchDrag, true); + window.addEventListener("mouseup", this.onUp, true); + window.addEventListener("touchend", this.onUp, true); + } + private readonly onMouseDown = (e: MouseEvent) => this.onDown(e, e); + private readonly onTouchDown = (e: TouchEvent) => this.onDown(e, e.touches[0]); + + private onDrag(e: Event, touch: Touch) { + e.stopPropagation(); + e.preventDefault(); + + const dragging = this.dragging; + if (!dragging) return; + + this.setPosition( + dragging.initialX + (touch.clientX - dragging.downX), + dragging.initialY + (touch.clientY - dragging.downY), + ); + }; + private readonly onMouseDrag = (e: MouseEvent) => this.onDrag(e, e); + private readonly onTouchDrag = (e: TouchEvent) => this.onDrag(e, e.touches[0]); + + private readonly onUp = (e: Event) => { + e.stopPropagation(); + + this.dragging = undefined; + + window.removeEventListener("mousemove", this.onMouseDrag, true); + window.removeEventListener("touchmove", this.onTouchDrag, true); + window.removeEventListener("mouseup", this.onUp, true); + window.removeEventListener("touchend", this.onUp, true); + } + + private readonly setPosition = (left: number, top: number): void => { + const root = this.base as HTMLElement; + + left = this.left = clamp(left, 0, window.innerWidth - root.offsetWidth); + top = this.top = clamp(top, 0, window.innerHeight - root.offsetHeight); + root.style.transform = `translate(${left}px, ${top}px)`; + } + +} + +const root = document.createElement("div"); +document.body.appendChild(root); +render(, document.body, root); diff --git a/src/web/mount/.settings b/src/web/mount/.settings new file mode 100644 index 000000000..5b9849575 --- /dev/null +++ b/src/web/mount/.settings @@ -0,0 +1,3 @@ +{ + [ "motd.enable" ] = false, +} diff --git a/src/web/mount/expr_template.lua b/src/web/mount/expr_template.lua new file mode 100644 index 000000000..37faf4180 --- /dev/null +++ b/src/web/mount/expr_template.lua @@ -0,0 +1,14 @@ +local result = table.pack(__expr__ +) + +if result.n == 0 then return end + +local pp = require "cc.pretty" + +local line = {} +for i = 1, result.n do + if i > 1 then line[#line + 1] = pp.text(", ") end + line[#line + 1] = pp.pretty(result[i]) +end + +pp.print(pp.concat(table.unpack(line))) diff --git a/src/web/mount/startup.lua b/src/web/mount/startup.lua new file mode 100644 index 000000000..91bbf535f --- /dev/null +++ b/src/web/mount/startup.lua @@ -0,0 +1,5 @@ +-- Make the startup file invisible, then run the file. We could use +-- shell.run, but this ensures the program is in shell history, etc... +fs.delete("startup.lua") +os.queueEvent("paste", "example.lua") +os.queueEvent("key", keys.enter, false) diff --git a/src/web/styles.css b/src/web/styles.css new file mode 100644 index 000000000..e60e670ee --- /dev/null +++ b/src/web/styles.css @@ -0,0 +1,85 @@ +/* Pretty tables, mostly inherited from table.definition-list */ +table.pretty-table { + border-collapse: collapse; + width: 100%; +} + +table.pretty-table td, table.pretty-table th { + border: 1px solid #cccccc; + padding: 2px 4px; +} + +table.pretty-table th { + background-color: #f0f0f0; +} + +.highlight.highlight-lua { + position: relative; + background: #eee; + padding: 2px; +} + +.example-run { + position: absolute; + top: 0; + right: 0; + background: #058e05; + color: #fff; + padding: 2px 5px; +} + +.example-window { + position: fixed; + z-index: 200; + top: 0px; + top: 0px;; +} + +/* Behold, the most cursed CSS! copy-cat's resizing algorithm is a weird, in + that it basically does "wrapper height - 40px" to determine the effective + size. But the footer is actually 1em+6px high, so we need to do very weird + things. + + Yes, it should probably be fixed on the copy-cat side. + */ +.computer-container { + width: 620px; + height: calc(350px + 40px); + margin-top: calc((1em + 6px - 40px) / 2); +} + +.example-window-hidden { + display: none; +} + +.titlebar { + display: flex; + background: #dede6c; + height: 30px; +} + +.titlebar-drag { + flex-grow: 1; + cursor: grab; +} + +.titlebar-close { + background: none; + padding: 0px 5px; + border: none; + border-radius: 0px; + margin: 0px; + font-size: 15px; +} + +.titlebar-close:hover { background: #cc4c4c; } + +@media (max-width: 700px) { + .computer-container { + width: 314px; + height: calc(179px + 40px); + } + + .titlebar { height: 20px; } + .titlebar-close { font-size: 7px; } +} diff --git a/tools/check-lines.py b/tools/check-lines.py index 3659924ae..47ff15fc9 100644 --- a/tools/check-lines.py +++ b/tools/check-lines.py @@ -18,7 +18,7 @@ for path in pathlib.Path("src").glob("**/*"): if line.strip() == "": print("%s has empty first line" % path) - if len(line) >= 2 and line[-2] == "\r" and line[-1] == "\n" and not has_line: + if len(line) >= 2 and line[-2] == "\r" and line[-1] == "\n" and not has_dos: print("%s has contains '\\r\\n' on line %d" % (path, i + 1)) problems = has_dos = True diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..b6dc1da3f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "module": "esNext", + "moduleResolution": "node", + "target": "es6", + "lib": [ + "es2015", + "dom" + ], + "newLine": "LF", + "baseUrl": ".", + // Additional compile options + "noEmitOnError": true, + "preserveWatchOutput": true, + "jsx": "react", + "jsxFactory": "h", + // Strict Type-Checking Options + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "importsNotUsedAsValues": "error", + "forceConsistentCasingInFileNames": true, + "paths": { + "copycat/embed": [ + "src/web/copy-cat.d.ts" + ], + } + }, + "include": [ + "src/web", + ] +} From ab39cb849d9a356378c359931ad1546ad6937f00 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 12 Nov 2020 19:04:55 +0000 Subject: [PATCH 363/711] Publish Javadoc to tweaked.cc too Closes #578 Also only publish docs for 1.15.x trunk for now. Tags aren't especially useful until we add a version switcher. --- .github/workflows/make-doc.sh | 3 +++ .github/workflows/make-doc.yml | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/make-doc.sh b/.github/workflows/make-doc.sh index f86ef60f0..802426430 100755 --- a/.github/workflows/make-doc.sh +++ b/.github/workflows/make-doc.sh @@ -14,3 +14,6 @@ chmod 600 "$HOME/.ssh/key" rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \ "$GITHUB_WORKSPACE/build/docs/lua/" \ "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST" +rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \ + "$GITHUB_WORKSPACE/build/docs/javadoc/" \ + "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST/javadoc" diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index 18ce815a5..ab7d60b1a 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -3,11 +3,7 @@ name: Build documentation on: push: branches: - - master - mc-1.15.x - tags: - release: - types: [ published ] jobs: make_doc: @@ -43,7 +39,7 @@ jobs: run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon - name: Generate documentation - run: ./gradlew docWebsite --no-daemon + run: ./gradlew docWebsite javadoc --no-daemon - name: Upload documentation run: .github/workflows/make-doc.sh 2> /dev/null From 9f57e77ed367611b4f33fda650edc2b65435ae88 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 12 Nov 2020 19:12:03 +0000 Subject: [PATCH 364/711] Add a link to the Java docs --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d344fb157..6ce3f3df9 100644 --- a/README.md +++ b/README.md @@ -67,3 +67,6 @@ dependencies { You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are subject to change at any point. If you depend on functionality outside the API, file an issue, and we can look into exposing more features. + +We bundle the API sources with the jar, so documentation should be easily viewable within your editor. Alternatively, +the generated documentation [can be browsed online](https://tweaked.cc/javadoc/). From 7f90f2f7cadce0d5b9177b16626979591bce8137 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 12 Nov 2020 19:40:18 +0000 Subject: [PATCH 365/711] Clean up some examples a little bit Would be good if they didn't crash and burn on entry :). --- doc/stub/fs.lua | 2 +- doc/stub/os.lua | 6 +++++- illuaminate.sexp | 9 --------- .../data/computercraft/lua/rom/apis/colors.lua | 8 ++++---- .../data/computercraft/lua/rom/apis/disk.lua | 2 +- .../data/computercraft/lua/rom/apis/help.lua | 3 ++- .../data/computercraft/lua/rom/apis/keys.lua | 1 + .../data/computercraft/lua/rom/apis/peripheral.lua | 2 +- .../data/computercraft/lua/rom/apis/textutils.lua | 12 ++++++------ .../lua/rom/modules/main/cc/completion.lua | 4 ++-- .../computercraft/lua/rom/modules/main/cc/pretty.lua | 4 ++-- .../lua/rom/modules/main/cc/shell/completion.lua | 2 +- .../data/computercraft/lua/rom/programs/shell.lua | 4 ++-- 13 files changed, 28 insertions(+), 31 deletions(-) diff --git a/doc/stub/fs.lua b/doc/stub/fs.lua index 6e3b56c84..40b9107db 100644 --- a/doc/stub/fs.lua +++ b/doc/stub/fs.lua @@ -15,7 +15,7 @@ function isDriveRoot(path) end --[[- Provides completion for a file or directory name, suitable for use with -@{read}. +@{_G.read}. When a directory is a possible candidate for completion, two entries are included - one with a trailing slash (indicating that entries within this diff --git a/doc/stub/os.lua b/doc/stub/os.lua index 7da3ea0c3..89a472bf3 100644 --- a/doc/stub/os.lua +++ b/doc/stub/os.lua @@ -85,6 +85,9 @@ the `terminate` event yourself - the program will not stop execution when function pullEventRaw(filter) end --- Pauses execution for the specified number of seconds, alias of @{_G.sleep}. +-- +-- @tparam number time The number of seconds to sleep for, rounded up to the +-- nearest multiple of 0.05. function sleep(time) end --- Get the current CraftOS version (for example, `CraftOS 1.8`). @@ -93,6 +96,7 @@ function sleep(time) end -- should return `CraftOS 1.8`. -- -- @treturn string The current CraftOS version. +-- @usage os.version() function version() end --[[- Run the program at the given path with the specified environment and @@ -113,7 +117,7 @@ such as @{loadfile}. @treturn boolean Whether or not the program ran successfully. @usage Run the default shell from within your program: - os.run({}, "/rom/programs/shell") + os.run({}, "/rom/programs/shell.lua") @see shell.run @see loadfile diff --git a/illuaminate.sexp b/illuaminate.sexp index 80a481a64..6bf2d2688 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -97,15 +97,6 @@ (linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return)) -;; These currently rely on unknown references. -(at - (/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua - /src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua - /src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua - /src/main/resources/*/computercraft/lua/rom/programs/shell.lua - /doc/stub/fs.lua) - (linters -doc:unresolved-reference)) - ;; Suppress warnings for the BIOS using its own deprecated members for now. (at /src/main/resources/*/computercraft/lua/bios.lua (linters -var:deprecated)) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua index 83c8e0f21..ba4050763 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/colors.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/colors.lua @@ -270,7 +270,7 @@ end -- @treturn number The combined hexadecimal colour. -- @usage -- ```lua --- colors.rgb(0.7, 0.2, 0.6) +-- colors.packRGB(0.7, 0.2, 0.6) -- -- => 0xb23399 -- ``` function packRGB(r, g, b) @@ -291,7 +291,7 @@ end -- @treturn number The blue channel, will be between 0 and 1. -- @usage -- ```lua --- colors.rgb(0xb23399) +-- colors.unpackRGB(0xb23399) -- -- => 0.7, 0.2, 0.6 -- ``` -- @see colors.packRGB @@ -317,12 +317,12 @@ end -- @deprecated Use @{packRGB} or @{unpackRGB} directly. -- @usage -- ```lua --- colors.rgb(0xb23399) +-- colors.rgb8(0xb23399) -- -- => 0.7, 0.2, 0.6 -- ``` -- @usage -- ```lua --- colors.rgb(0.7, 0.2, 0.6) +-- colors.rgb8(0.7, 0.2, 0.6) -- -- => 0xb23399 -- ``` function rgb8(r, g, b) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/disk.lua b/src/main/resources/data/computercraft/lua/rom/apis/disk.lua index 9e136b22c..ca5ac21d2 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/disk.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/disk.lua @@ -22,7 +22,7 @@ end -- -- @tparam string name The name of the disk drive. -- @treturn boolean If something is in the disk drive. --- @usage disk.isPresent(false) +-- @usage disk.isPresent("top") function isPresent(name) if isDrive(name) then return peripheral.call(name, "isDiskPresent") diff --git a/src/main/resources/data/computercraft/lua/rom/apis/help.lua b/src/main/resources/data/computercraft/lua/rom/apis/help.lua index 438af474f..777ab45bf 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/help.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/help.lua @@ -32,7 +32,7 @@ end -- @tparam string topic The topic to find -- @treturn string|nil The path to the given topic's help file, or `nil` if it -- cannot be found. --- @usage print(help.lookup("disk")) +-- @usage help.lookup("disk") function lookup(_sTopic) expect(1, _sTopic, "string") -- Look on the path variable @@ -52,6 +52,7 @@ end --- Returns a list of topics that can be looked up and/or displayed. -- -- @treturn table A list of topics in alphabetical order. +-- @usage help.topics() function topics() -- Add index local tItems = { diff --git a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua index 90f877aa5..206646c21 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/keys.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/keys.lua @@ -145,6 +145,7 @@ keys.cimcumflex = keys.circumflex --- @local -- -- @tparam number code The key code to look up. -- @treturn string|nil The name of the key, or `nil` if not a valid key code. +-- @usage keys.getName(keys.enter) function getName(_nKey) expect(1, _nKey, "number") return tKeys[_nKey] diff --git a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua index d8be09ad3..c284d0691 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua @@ -191,7 +191,7 @@ end -- filter function, which takes the peripheral's name and wrapped table -- and returns if it should be included in the result. -- @treturn table... 0 or more wrapped peripherals matching the given filters. --- @usage local monitors = { peripheral.find("monitor") } +-- @usage { peripheral.find("monitor") } -- @usage peripheral.find("modem", rednet.open) function find(ty, filter) expect(1, ty, "string") diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index e6156d3b0..ec0633589 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -9,7 +9,7 @@ local expect, field = expect.expect, expect.field --- Slowly writes string text at current cursor position, -- character-by-character. -- --- Like @{write}, this does not insert a newline at the end. +-- Like @{_G.write}, this does not insert a newline at the end. -- -- @tparam string sText The the text to write to the screen -- @tparam[opt] number nRate The number of characters to write each second, @@ -119,8 +119,8 @@ end -- displayed before prompting. -- @treturn number The number of lines printed. -- @usage --- local width, height = term.getSize() --- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2) +-- local width, height = term.getSize() +-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2) function pagedPrint(_sText, _nFreeLines) expect(2, _nFreeLines, "number", "nil") -- Setup a redirector @@ -706,7 +706,7 @@ unserialiseJSON = unserialise_json -- -- @tparam string str The string to encode -- @treturn string The encoded string. --- @usage print("https://example.com/?view=" .. textutils.urlEncode(read())) +-- @usage print("https://example.com/?view=" .. textutils.urlEncode("some text&things")) function urlEncode(str) expect(1, str, "string") if str then @@ -744,8 +744,8 @@ local tEmpty = {} -- -- @treturn { string... } The (possibly empty) list of completions. -- @see shell.setCompletionFunction --- @see read --- @usage textutils.complete( "pa", getfenv() ) +-- @see _G.read +-- @usage textutils.complete( "pa", _ENV ) function complete(sSearchText, tSearchTable) expect(1, sSearchText, "string") expect(2, tSearchTable, "table", "nil") diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua index 2ae2e4966..01cc187b1 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua @@ -1,5 +1,5 @@ --- A collection of helper methods for working with input completion, such --- as that require by @{read}. +-- as that require by @{_G.read}. -- -- @module cc.completion -- @see cc.shell.completion For additional helpers to use with @@ -29,7 +29,7 @@ end -- @tparam { string... } choices The list of choices to complete from. -- @tparam[opt] boolean add_space Whether to add a space after the completed item. -- @treturn { string... } A list of suffixes of matching strings. --- @usage Call @{read}, completing the names of various animals. +-- @usage Call @{_G.read}, completing the names of various animals. -- -- local animals = { "dog", "cat", "lion", "unicorn" } -- read(nil, nil, function(text) return choice(text, animals) end) diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua index a62a6f9f1..1c782ecee 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -13,11 +13,11 @@ -- @module cc.pretty -- @usage Print a table to the terminal -- local pretty = require "cc.pretty" --- pretty.write(pretty.pretty({ 1, 2, 3 })) +-- pretty.print(pretty.pretty({ 1, 2, 3 })) -- -- @usage Build a custom document and display it -- local pretty = require "cc.pretty" --- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world"))) +-- pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world"))) local expect = require "cc.expect" local expect, field = expect.expect, expect.field diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua index 91d9ea7a4..21c10ec34 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -8,7 +8,7 @@ -- wrap them using @{build}, or your own custom function. -- -- @module cc.shell.completion --- @see cc.completion For more general helpers, suitable for use with @{read}. +-- @see cc.completion For more general helpers, suitable for use with @{_G.read}. -- @see shell.setCompletionFunction local expect = require "cc.expect".expect diff --git a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua index 0c6b5868b..1cc6dfe48 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua @@ -383,7 +383,7 @@ end -- -- @tparam string sLine The input to complete. -- @treturn { string }|nil The list of possible completions. --- @see read For more information about completion. +-- @see _G.read For more information about completion. -- @see shell.completeProgram -- @see shell.setCompletionFunction -- @see shell.getCompletionInfo @@ -461,7 +461,7 @@ end -- The completion function. -- @see cc.shell.completion Various utilities to help with writing completion functions. -- @see shell.complete --- @see read For more information about completion. +-- @see _G.read For more information about completion. function shell.setCompletionFunction(program, complete) expect(1, program, "string") expect(2, complete, "function") From c9f3d315c058feeb10d6be3ee009f287c22d7751 Mon Sep 17 00:00:00 2001 From: Stephen Gibson Date: Fri, 13 Nov 2020 14:32:49 +0000 Subject: [PATCH 366/711] Fix epoch documentation to use milliseconds (#580) --- .../java/dan200/computercraft/core/apis/OSAPI.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 0d1605926..e35bb94e0 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -378,17 +378,17 @@ public class OSAPI implements ILuaAPI } /** - * Returns the number of seconds since an epoch depending on the locale. + * Returns the number of milliseconds since an epoch depending on the locale. * - * * If called with {@code ingame}, returns the number of seconds since the + * * If called with {@code ingame}, returns the number of milliseconds since the * world was created. This is the default. - * * If called with {@code utc}, returns the number of seconds since 1 + * * If called with {@code utc}, returns the number of milliseconds since 1 * January 1970 in the UTC timezone. - * * If called with {@code local}, returns the number of seconds since 1 + * * If called with {@code local}, returns the number of milliseconds since 1 * January 1970 in the server's local timezone. * - * @param args The locale to get the seconds for. Defaults to {@code ingame} if not set. - * @return The seconds since the epoch depending on the selected locale. + * @param args The locale to get the milliseconds for. Defaults to {@code ingame} if not set. + * @return The milliseconds since the epoch depending on the selected locale. * @throws LuaException If an invalid locale is passed. */ @LuaFunction From f194f4fa3a17c48ff1a9088d50063f4a675a23b6 Mon Sep 17 00:00:00 2001 From: Stephen Gibson Date: Fri, 13 Nov 2020 14:32:49 +0000 Subject: [PATCH 367/711] Fix epoch documentation to use milliseconds (#580) --- .../java/dan200/computercraft/core/apis/OSAPI.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index be5dbb2dd..b0752cdaa 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -378,17 +378,17 @@ public class OSAPI implements ILuaAPI } /** - * Returns the number of seconds since an epoch depending on the locale. + * Returns the number of milliseconds since an epoch depending on the locale. * - * * If called with {@code ingame}, returns the number of seconds since the + * * If called with {@code ingame}, returns the number of milliseconds since the * world was created. This is the default. - * * If called with {@code utc}, returns the number of seconds since 1 + * * If called with {@code utc}, returns the number of milliseconds since 1 * January 1970 in the UTC timezone. - * * If called with {@code local}, returns the number of seconds since 1 + * * If called with {@code local}, returns the number of milliseconds since 1 * January 1970 in the server's local timezone. * - * @param args The locale to get the seconds for. Defaults to {@code ingame} if not set. - * @return The seconds since the epoch depending on the selected locale. + * @param args The locale to get the milliseconds for. Defaults to {@code ingame} if not set. + * @return The milliseconds since the epoch depending on the selected locale. * @throws LuaException If an invalid locale is passed. */ @LuaFunction From d2a1a00dc43e5b65f6b64111ce76dd3db16c919f Mon Sep 17 00:00:00 2001 From: Luca Date: Tue, 17 Nov 2020 13:53:20 +0100 Subject: [PATCH 368/711] Clear gets an option to reset the palette (#582) Fixes #555. --- .../data/computercraft/lua/rom/help/clear.txt | 7 +++- .../computercraft/lua/rom/programs/clear.lua | 35 +++++++++++++++++-- .../data/computercraft/lua/rom/startup.lua | 1 + 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/help/clear.txt b/src/main/resources/data/computercraft/lua/rom/help/clear.txt index 6e3258411..037d3c8a5 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/clear.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/clear.txt @@ -1 +1,6 @@ -clear clears the screen. +clear clears the screen and/or resets the palette. +ex: +"clear" clears the screen, but keeps the palette. +"clear screen" does the same as "clear" +"clear palette" resets the palette, but doesn't clear the screen +"clear all" clears the screen and resets the palette diff --git a/src/main/resources/data/computercraft/lua/rom/programs/clear.lua b/src/main/resources/data/computercraft/lua/rom/programs/clear.lua index d69a29993..cfd8cb9c4 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/clear.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/clear.lua @@ -1,2 +1,33 @@ -term.clear() -term.setCursorPos(1, 1) +local tArgs = { ... } + +local function printUsage() + local programName = arg[0] or fs.getName(shell.getRunningProgram()) + print("Usages:") + print(programName) + print(programName .. " screen") + print(programName .. " palette") + print(programName .. " all") +end + +local function clear() + term.clear() + term.setCursorPos(1, 1) +end + +local function resetPalette() + for i = 0, 15 do + term.setPaletteColour(math.pow(2, i), term.nativePaletteColour(math.pow(2, i))) + end +end + +local sCommand = tArgs[1] or "screen" +if sCommand == "screen" then + clear() +elseif sCommand == "palette" then + resetPalette() +elseif sCommand == "all" then + clear() + resetPalette() +else + printUsage() +end diff --git a/src/main/resources/data/computercraft/lua/rom/startup.lua b/src/main/resources/data/computercraft/lua/rom/startup.lua index 1b3046092..8c347cc33 100644 --- a/src/main/resources/data/computercraft/lua/rom/startup.lua +++ b/src/main/resources/data/computercraft/lua/rom/startup.lua @@ -49,6 +49,7 @@ end shell.setCompletionFunction("rom/programs/alias.lua", completion.build(nil, completion.program)) shell.setCompletionFunction("rom/programs/cd.lua", completion.build(completion.dir)) +shell.setCompletionFunction("rom/programs/clear.lua", completion.build({ completion.choice, { "screen", "palette", "all" } })) shell.setCompletionFunction("rom/programs/copy.lua", completion.build( { completion.dirOrFile, true }, completion.dirOrFile From aab0cd34cd64fdf837ff1c3b91a957a25c2cf7f9 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 20 Nov 2020 15:06:47 +0000 Subject: [PATCH 369/711] Use term.blit on original paint render This makes it super speedy, meaning an initial refresh doesn't take ages to load. --- .../lua/rom/programs/fun/advanced/paint.lua | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua index cb9de4153..cab2cfc6c 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -233,14 +233,32 @@ local function drawCanvasPixel(x, y) end end +local color_hex_lookup = {} +for i = 0, 15 do + color_hex_lookup[2 ^ i] = string.format("%x", i) +end + --[[ Converts each colour in a single line of the canvas and draws it returns: nil ]] local function drawCanvasLine(y) + local text, fg, bg = "", "", "" for x = 1, w - 2 do - drawCanvasPixel(x, y) + local pixel = getCanvasPixel(x, y) + if pixel then + text = text .. " " + fg = fg .. "0" + bg = bg .. color_hex_lookup[pixel or canvasColour] + else + text = text .. "\127" + fg = fg .. color_hex_lookup[canvasColour] + bg = bg .. color_hex_lookup[colours.grey] + end end + + term.setCursorPos(1, y) + term.blit(text, fg, bg) end --[[ From b0651082f472baee8f0fa8ec7ba95f433e2637bb Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 20 Nov 2020 19:36:28 +0000 Subject: [PATCH 370/711] Cleanup examples for the various modules --- build.gradle | 3 +- .../lua/rom/modules/main/cc/completion.lua | 19 +++- .../lua/rom/modules/main/cc/expect.lua | 27 +++++- .../lua/rom/modules/main/cc/pretty.lua | 20 +++- .../lua/rom/modules/main/cc/require.lua | 6 +- .../rom/modules/main/cc/shell/completion.lua | 91 ++++++++++--------- 6 files changed, 109 insertions(+), 57 deletions(-) diff --git a/build.gradle b/build.gradle index 5c36a17fd..4f698a445 100644 --- a/build.gradle +++ b/build.gradle @@ -342,7 +342,8 @@ task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) { group = "build" description = "Bundles JS into rollup" - inputs.files(fileTree("doc")).withPropertyName("sources") + inputs.files(fileTree("doc")).withPropertyName("docs") + inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom") inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp") inputs.file("$buildDir/rollup/index.min.js").withPropertyName("scripts") inputs.file("src/web/styles.css").withPropertyName("styles") diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua index 01cc187b1..d07b09506 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua @@ -31,8 +31,9 @@ end -- @treturn { string... } A list of suffixes of matching strings. -- @usage Call @{_G.read}, completing the names of various animals. -- +-- local completion = require "cc.completion" -- local animals = { "dog", "cat", "lion", "unicorn" } --- read(nil, nil, function(text) return choice(text, animals) end) +-- read(nil, nil, function(text) return completion.choice(text, animals) end) local function choice(text, choices, add_space) expect(1, text, "string") expect(2, choices, "table") @@ -45,7 +46,9 @@ end -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed name. -- @treturn { string... } A list of suffixes of matching peripherals. --- @usage read(nil, nil, peripheral) +-- @usage +-- local completion = require "cc.completion" +-- read(nil, nil, completion.peripheral) local function peripheral_(text, add_space) expect(1, text, "string") expect(2, add_space, "boolean", "nil") @@ -59,7 +62,9 @@ local sides = redstone.getSides() -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed side. -- @treturn { string... } A list of suffixes of matching sides. --- @usage read(nil, nil, side) +-- @usage +-- local completion = require "cc.completion" +-- read(nil, nil, completion.side) local function side(text, add_space) expect(1, text, "string") expect(2, add_space, "boolean", "nil") @@ -71,7 +76,9 @@ end -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed settings. -- @treturn { string... } A list of suffixes of matching settings. --- @usage read(nil, nil, setting) +-- @usage +-- local completion = require "cc.completion" +-- read(nil, nil, completion.setting) local function setting(text, add_space) expect(1, text, "string") expect(2, add_space, "boolean", "nil") @@ -85,7 +92,9 @@ local command_list -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed command. -- @treturn { string... } A list of suffixes of matching commands. --- @usage read(nil, nil, command) +-- @usage +-- local completion = require "cc.completion" +-- read(nil, nil, completion.command) local function command(text, add_space) expect(1, text, "string") expect(2, add_space, "boolean", "nil") diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua index 24ca66d56..397be085e 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua @@ -1,7 +1,26 @@ ---- The @{cc.expect} library provides helper functions for verifying that --- function arguments are well-formed and of the correct type. --- --- @module cc.expect +--[[- The @{cc.expect} library provides helper functions for verifying that +function arguments are well-formed and of the correct type. + +@module cc.expect +@usage Define a basic function and check it has the correct arguments. + + local expect = require "cc.expect" + local expect, field = expect.expect, expect.field + + local function add_person(name, info) + expect(1, name, "string") + expect(2, info, "table", "nil") + + if info then + print("Got age=", field(info, "age", "number")) + print("Got gender=", field(info, "gender", "string", "nil")) + end + end + + add_person("Anastazja") -- `info' is optional + add_person("Kion", { age = 23 }) -- `gender' is optional + add_person("Caoimhin", { age = 23, gender = true }) -- error! +]] local native_select, native_type = select, type diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua index 1c782ecee..37a70a515 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -67,6 +67,9 @@ end -- @tparam[opt] number colour The colour this text should be printed with. If not given, we default to the current -- colour. -- @treturn Doc The document with the provided text. +-- @usage Write some blue text. +-- local pretty = require "cc.pretty" +-- pretty.print(pretty.text("Hello!", colours.blue)) local function text(text, colour) expect(1, text, "string") expect(2, colour, "number", "nil") @@ -101,8 +104,11 @@ end -- -- @tparam Doc|string ... The documents to concatenate. -- @treturn Doc The concatenated documents. --- @usage pretty.concat(doc1, " - ", doc2) --- @usage doc1 .. " - " .. doc2 +-- @usage +-- local pretty = require "cc.pretty" +-- local doc1, doc2 = pretty.text("doc1"), pretty.text("doc2") +-- print(pretty.concat(doc1, " - ", doc2)) +-- print(doc1 .. " - " .. doc2) -- Also supports .. local function concat(...) local args = table.pack(...) for i = 1, args.n do @@ -135,7 +141,9 @@ Doc.__concat = concat --- @local -- @tparam number depth The number of spaces with which the document should be indented. -- @tparam Doc doc The document to indent. -- @treturn Doc The nested document. --- @usage pretty.nest(2, pretty.text("foo\nbar")) +-- @usage +-- local pretty = require "cc.pretty" +-- print(pretty.nest(2, pretty.text("foo\nbar"))) local function nest(depth, doc) expect(1, depth, "number") if getmetatable(doc) ~= Doc then expect(2, doc, "document") end @@ -169,6 +177,12 @@ end -- -- @tparam Doc doc The document to group. -- @treturn Doc The grouped document. +-- @usage Uses group to show things being displayed on one or multiple lines. +-- +-- local pretty = require "cc.pretty" +-- local doc = pretty.group("Hello" .. pretty.space_line .. "World") +-- print(pretty.render(doc, 5)) -- On multiple lines +-- print(pretty.render(doc, 20)) -- Collapsed onto one. local function group(doc) if getmetatable(doc) ~= Doc then expect(1, doc, "document") end diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/require.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/require.lua index a90e189b8..c7b2e2741 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/require.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/require.lua @@ -9,9 +9,13 @@ -- @usage Construct the package and require function, and insert them into a -- custom environment. -- --- local env = setmetatable({}, { __index = _ENV }) -- local r = require "cc.require" +-- local env = setmetatable({}, { __index = _ENV }) -- env.require, env.package = r.make(env, "/") +-- +-- -- Now we have our own require function, separate to the original. +-- local r2 = env.require "cc.require" +-- print(r, r2) local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua") local expect = expect.expect diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua index 21c10ec34..06619c7f1 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua @@ -1,15 +1,28 @@ ---- A collection of helper methods for working with shell completion. --- --- Most programs may be completed using the @{build} helper method, rather than --- manually switching on the argument index. --- --- Note, the helper functions within this module do not accept an argument index, --- and so are not directly usable with the @{shell.setCompletionFunction}. Instead, --- wrap them using @{build}, or your own custom function. --- --- @module cc.shell.completion --- @see cc.completion For more general helpers, suitable for use with @{_G.read}. --- @see shell.setCompletionFunction +--[[- A collection of helper methods for working with shell completion. + +Most programs may be completed using the @{build} helper method, rather than +manually switching on the argument index. + +Note, the helper functions within this module do not accept an argument index, +and so are not directly usable with the @{shell.setCompletionFunction}. Instead, +wrap them using @{build}, or your own custom function. + +@module cc.shell.completion +@see cc.completion For more general helpers, suitable for use with @{_G.read}. +@see shell.setCompletionFunction + +@usage Register a completion handler for example.lua which prompts for a +choice of options, followed by a directory, and then multiple files. + + local completion = require "cc.shell.completion" + local complete = completion.build( + { completion.choice, { "get", "put" } }, + completion.dir, + { completion.file, many = true } + ) + shell.setCompletionFunction("example.lua", complete) + read(nil, nil, shell.complete, "example ") +]] local expect = require "cc.expect".expect local completion = require "cc.completion" @@ -69,37 +82,29 @@ local function program(shell, text) return shell.completeProgram(text) end ---- A helper function for building shell completion arguments. --- --- This accepts a series of single-argument completion functions, and combines --- them into a function suitable for use with @{shell.setCompletionFunction}. --- --- @tparam nil|table|function ... Every argument to @{build} represents an argument --- to the program you wish to complete. Each argument can be one of three types: --- --- - `nil`: This argument will not be completed. --- --- - A function: This argument will be completed with the given function. It is --- called with the @{shell} object, the string to complete and the arguments --- before this one. --- --- - A table: This acts as a more powerful version of the function case. The table --- must have a function as the first item - this will be called with the shell, --- string and preceding arguments as above, but also followed by any additional --- items in the table. This provides a more convenient interface to pass --- options to your completion functions. --- --- If this table is the last argument, it may also set the `many` key to true, --- which states this function should be used to complete any remaining arguments. --- --- @usage Prompt for a choice of options, followed by a directory, and then multiple --- files. --- --- complete.build( --- { complete.choice, { "get", "put" } }, --- complete.dir, --- { complete.file, many = true } --- ) +--[[- A helper function for building shell completion arguments. + +This accepts a series of single-argument completion functions, and combines +them into a function suitable for use with @{shell.setCompletionFunction}. + +@tparam nil|table|function ... Every argument to @{build} represents an argument +to the program you wish to complete. Each argument can be one of three types: + + - `nil`: This argument will not be completed. + + - A function: This argument will be completed with the given function. It is + called with the @{shell} object, the string to complete and the arguments + before this one. + + - A table: This acts as a more powerful version of the function case. The table + must have a function as the first item - this will be called with the shell, + string and preceding arguments as above, but also followed by any additional + items in the table. This provides a more convenient interface to pass + options to your completion functions. + + If this table is the last argument, it may also set the `many` key to true, + which states this function should be used to complete any remaining arguments. +]] local function build(...) local arguments = table.pack(...) for i = 1, arguments.n do From c35707725f1441e9870bda820d5de04edf2033ee Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 20 Nov 2020 21:59:17 +0000 Subject: [PATCH 371/711] More examples Yay! --- rollup.config.js | 12 ++- .../computercraft/lua/rom/apis/paintutils.lua | 7 ++ .../computercraft/lua/rom/apis/parallel.lua | 83 +++++++++++++------ .../lua/rom/programs/fun/advanced/paint.lua | 4 +- src/web/index.tsx | 5 ++ src/web/mount/example.nfp | 16 ++++ 6 files changed, 97 insertions(+), 30 deletions(-) create mode 100644 src/web/mount/example.nfp diff --git a/rollup.config.js b/rollup.config.js index 1e0342fea..725abb7ca 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -35,14 +35,20 @@ export default { await Promise.all(files .filter(x => path.extname(x) !== ".ts") - .map(file => fs.writeFile(`${input}/mount/${file}.d.ts`, template)) + .map(async file => { + const path = `${input}/mount/${file}.d.ts`; + const contents = await fs.readFile(path, { encoding: "utf-8" }).catch(() => ""); + if (contents !== template) await fs.writeFile(path, template); + }) ); return options; }, async transform(code, file) { // Allow loading files in /mount. - if (path.extname(file) != ".lua" && path.basename(file) != ".settings") return null; - return `export default ${JSON.stringify(code)};\n`; + const ext = path.extname(file); + return ext != '.tsx' && ext != '.ts' && path.dirname(file) === path.resolve(`${input}/mount`) + ? `export default ${JSON.stringify(code)};\n` + : null; }, } ], diff --git a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua index 7ae1006b8..b920341c3 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua @@ -64,6 +64,10 @@ end -- -- @treturn table|nil The parsed image data, suitable for use with -- @{paintutils.drawImage}, or `nil` if the file does not exist. +-- @usage Load an image and draw it. +-- +-- local image = paintutils.loadImage("test-image.nfp") +-- paintutils.drawImage(image, term.getCursorPos()) function loadImage(path) expect(1, path, "string") @@ -107,6 +111,7 @@ end -- @tparam number endY The end y position of the line. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. +-- @usage paintutils.drawLine(2, 3, 30, 7, colors.red) function drawLine(startX, startY, endX, endY, colour) expect(1, startX, "number") expect(2, startY, "number") @@ -170,6 +175,7 @@ end -- @tparam number endY The end y position of the line. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. +-- @usage paintutils.drawBox(2, 3, 30, 7, colors.red) function drawBox(startX, startY, endX, endY, nColour) expect(1, startX, "number") expect(2, startY, "number") @@ -222,6 +228,7 @@ end -- @tparam number endY The end y position of the line. -- @tparam[opt] number colour The @{colors|color} of this pixel. This will be -- the current background colour if not specified. +-- @usage paintutils.drawFilledBox(2, 3, 30, 7, colors.red) function drawFilledBox(startX, startY, endX, endY, nColour) expect(1, startX, "number") expect(2, startY, "number") diff --git a/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua b/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua index c787eff41..e826ed28e 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua @@ -1,18 +1,19 @@ ---- Provides a simple implementation of multitasking. --- --- Functions are not actually executed simultaniously, but rather this API will --- automatically switch between them whenever they yield (eg whenever they call --- @{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or --- functions that call that, etc - basically, anything that causes the function --- to "pause"). --- --- Each function executed in "parallel" gets its own copy of the event queue, --- and so "event consuming" functions (again, mostly anything that causes the --- script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API, --- etc) can safely be used in one without affecting the event queue accessed by --- the other. --- --- @module parallel +--[[- Provides a simple implementation of multitasking. + +Functions are not actually executed simultaniously, but rather this API will +automatically switch between them whenever they yield (eg whenever they call +@{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or +functions that call that, etc - basically, anything that causes the function +to "pause"). + +Each function executed in "parallel" gets its own copy of the event queue, +and so "event consuming" functions (again, mostly anything that causes the +script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API, +etc) can safely be used in one without affecting the event queue accessed by +the other. + +@module parallel +]] local function create(...) local tFns = table.pack(...) @@ -70,21 +71,53 @@ local function runUntilLimit(_routines, _limit) end end ---- Switches between execution of the functions, until any of them --- finishes. If any of the functions errors, the message is propagated upwards --- from the @{parallel.waitForAny} call. --- --- @tparam function ... The functions this task will run +--[[- Switches between execution of the functions, until any of them +finishes. If any of the functions errors, the message is propagated upwards +from the @{parallel.waitForAny} call. + +@tparam function ... The functions this task will run +@usage Print a message every second until the `q` key is pressed. + + local function tick() + while true do + os.sleep(1) + print("Tick") + end + end + local function wait_for_q() + repeat + local _, key = os.pullEvent("key") + until key == keys.q + print("Q was pressed!") + end + + parallel.waitForAny(tick, wait_for_q) + print("Everything done!") +]] function waitForAny(...) local routines = create(...) return runUntilLimit(routines, #routines - 1) end ---- Switches between execution of the functions, until all of them are --- finished. If any of the functions errors, the message is propagated upwards --- from the @{parallel.waitForAll} call. --- --- @tparam function ... The functions this task will run +--[[- Switches between execution of the functions, until all of them are +finished. If any of the functions errors, the message is propagated upwards +from the @{parallel.waitForAll} call. + +@tparam function ... The functions this task will run +@usage Start off two timers and wait for them both to run. + + local function a() + os.sleep(1) + print("A is done") + end + local function b() + os.sleep(3) + print("B is done") + end + + parallel.waitForAll(a, b) + print("Everything done!") +]] function waitForAll(...) local routines = create(...) return runUntilLimit(routines, 0) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua index cab2cfc6c..862bc2afe 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua @@ -252,8 +252,8 @@ local function drawCanvasLine(y) bg = bg .. color_hex_lookup[pixel or canvasColour] else text = text .. "\127" - fg = fg .. color_hex_lookup[canvasColour] - bg = bg .. color_hex_lookup[colours.grey] + fg = fg .. color_hex_lookup[colours.grey] + bg = bg .. color_hex_lookup[canvasColour] end end diff --git a/src/web/index.tsx b/src/web/index.tsx index 0bf476a86..f4e85033a 100644 --- a/src/web/index.tsx +++ b/src/web/index.tsx @@ -4,10 +4,15 @@ import type { ComponentChild } from "preact"; import settingsFile from "./mount/.settings"; import startupFile from "./mount/startup.lua"; import exprTemplate from "./mount/expr_template.lua"; +import exampleImage from "./mount/example.nfp"; const defaultFiles: { [filename: string]: string } = { ".settings": settingsFile, "startup.lua": startupFile, + + // TODO: Ideally this'd be in data/image.nfp or something, but copy-cat's + // dir bootstrapping doesn't cope with that right now. + "test-image.nfp": exampleImage }; const clamp = (value: number, min: number, max: number): number => { diff --git a/src/web/mount/example.nfp b/src/web/mount/example.nfp new file mode 100644 index 000000000..1025172c9 --- /dev/null +++ b/src/web/mount/example.nfp @@ -0,0 +1,16 @@ +fffffffffffffffffffffff +f444444444444444444444f +f444444444444444444444f +f44fffffffffffffffff44f +f44ff0ffffffffffffff44f +f44fff0fffffffffffff44f +f44ff0ffffffffffffff44f +f44fffffffffffffffff44f +f44fffffffffffffffff44f +f44fffffffffffffffff44f +f44fffffffffffffffff44f +f44fffffffffffffffff44f +f444444444444444444444f +f4444444444444444fff44f +f444444444444444444444f +fffffffffffffffffffffff From 9a749642d294506095e697a3a4345dfe260bd68c Mon Sep 17 00:00:00 2001 From: Lupus590 Date: Sat, 21 Nov 2020 12:11:40 +0000 Subject: [PATCH 372/711] Strict Globals (#583) --- .../resources/data/computercraft/lua/bios.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/resources/data/computercraft/lua/bios.lua b/src/main/resources/data/computercraft/lua/bios.lua index 4573f9826..f8e21f941 100644 --- a/src/main/resources/data/computercraft/lua/bios.lua +++ b/src/main/resources/data/computercraft/lua/bios.lua @@ -523,6 +523,16 @@ function os.run(_tEnv, _sPath, ...) local tEnv = _tEnv setmetatable(tEnv, { __index = _G }) + + if settings.get("bios.strict_globals", false) then + -- load will attempt to set _ENV on this environment, which + -- throws an error with this protection enabled. Thus we set it here first. + tEnv._ENV = tEnv + getmetatable(tEnv).__newindex = function(_, name) + error("Attempt to create global " .. tostring(name), 2) + end + end + local fnFile, err = loadfile(_sPath, nil, tEnv) if fnFile then local ok, err = pcall(fnFile, ...) @@ -954,6 +964,11 @@ settings.define("lua.function_source", { description = "Show where a function was defined when printing functions.", type = "boolean", }) +settings.define("bios.strict_globals", { + default = false, + description = "Prevents assigning variables into a program's environment. Make sure you use the local keyword or assign to _G explicitly.", + type = "boolean", +}) if term.isColour() then settings.define("bios.use_multishell", { From fff8353451451be5ae31e0f63d8e529b127fd186 Mon Sep 17 00:00:00 2001 From: Lupus590 Date: Sat, 21 Nov 2020 12:25:19 +0000 Subject: [PATCH 373/711] Remove extra space (#586) --- src/main/resources/data/computercraft/lua/bios.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/bios.lua b/src/main/resources/data/computercraft/lua/bios.lua index f8e21f941..4407dc99e 100644 --- a/src/main/resources/data/computercraft/lua/bios.lua +++ b/src/main/resources/data/computercraft/lua/bios.lua @@ -524,7 +524,7 @@ function os.run(_tEnv, _sPath, ...) local tEnv = _tEnv setmetatable(tEnv, { __index = _G }) - if settings.get("bios.strict_globals", false) then + if settings.get("bios.strict_globals", false) then -- load will attempt to set _ENV on this environment, which -- throws an error with this protection enabled. Thus we set it here first. tEnv._ENV = tEnv From 486f41f08286ddcfad91d72b83a9361bd9c215cb Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Thu, 26 Nov 2020 14:46:03 -0500 Subject: [PATCH 374/711] Fixed length check on function name in `expect` (#589) --- .../data/computercraft/lua/rom/modules/main/cc/expect.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua index 397be085e..6be4e135d 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/expect.lua @@ -53,7 +53,7 @@ local function expect(index, value, ...) local name if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then local ok, info = pcall(debug.getinfo, 3, "nS") - if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end + if ok and info.name and info.name ~= "" and info.what ~= "C" then name = info.name end end local type_names = get_type_names(...) From 04f9644ae75dafc72da4c4790f334d2e90b03e6f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 27 Nov 2020 21:29:11 +0000 Subject: [PATCH 375/711] Allow strings or numbers in textutils.*tabulate A little dubious, but apparently CC used to support it. This means we're consistent with methods like io.write or string.len which accept strings or numbers. Fixes #591 --- .../data/computercraft/lua/rom/apis/textutils.lua | 7 ++++--- src/test/resources/test-rom/spec/apis/textutils_spec.lua | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index ec0633589..30766e8ec 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -163,10 +163,11 @@ local function tabulateCommon(bPaged, ...) for n, t in ipairs(tAll) do if type(t) == "table" then for nu, sItem in pairs(t) do - if type(sItem) ~= "string" then - error("bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type(sItem) .. ")", 3) + local ty = type(sItem) + if ty ~= "string" and ty ~= "number" then + error("bad argument #" .. n .. "." .. nu .. " (expected string, got " .. ty .. ")", 3) end - nMaxLen = math.max(#sItem + 1, nMaxLen) + nMaxLen = math.max(#tostring(sItem) + 1, nMaxLen) end end end diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index 486bf6118..6db7917ea 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -33,11 +33,12 @@ describe("The textutils library", function() term.redirect(window.create(term.current(), 1, 1, 5, 5, false)) textutils.tabulate() - textutils.tabulate({ "test" }) + textutils.tabulate({ "test", 1 }) textutils.tabulate(colors.white) expect.error(textutils.tabulate, nil):eq("bad argument #1 (expected number or table, got nil)") expect.error(textutils.tabulate, { "test" }, nil):eq("bad argument #2 (expected number or table, got nil)") + expect.error(textutils.tabulate, { false }):eq("bad argument #1.1 (expected string, got boolean)") end) end) From d4199064ae5ae8023c589f80f12d94e1c6bbc2b5 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 28 Nov 2020 11:41:03 +0000 Subject: [PATCH 376/711] Make fs.combine accept multiple arguments Means we can now do fs.combine("a", "b", "c"). Of course, one may just write "a/b/c" in this case, but it's definitely useful elsewhere. This is /technically/ a breaking change as fs.combine(a, b:gsub(...)) will no longer function (as gsub returns multiple arguments). However, I've done a quick search through GH and my Pastebin archives and can't find any programs which would break. Fingers crossed. --- .../dan200/computercraft/core/apis/FSAPI.java | 24 ++++++++++++++----- .../core/filesystem/FileSystem.java | 4 ++-- .../resources/test-rom/spec/apis/fs_spec.lua | 18 ++++++++------ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 4f122ae4c..34a2e0f4c 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -5,6 +5,7 @@ */ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.IArguments; import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaFunction; @@ -83,17 +84,28 @@ public class FSAPI implements ILuaAPI } /** - * Combines two parts of a path into one full path, adding separators as + * Combines several parts of a path into one full path, adding separators as * needed. * - * @param pathA The first part of the path. For example, a parent directory path. - * @param pathB The second part of the path. For example, a file name. + * @param arguments The paths to combine. * @return The new path, with separators added between parts as needed. + * @cc.tparam string path The first part of the path. For example, a parent directory path. + * @cc.tparam string ... Additional parts of the path to combine. */ @LuaFunction - public final String combine( String pathA, String pathB ) + public final String combine( IArguments arguments ) throws LuaException { - return fileSystem.combine( pathA, pathB ); + StringBuilder result = new StringBuilder(); + result.append( FileSystem.sanitizePath( arguments.getString( 0 ), true ) ); + + for( int i = 1, n = arguments.count(); i < n; i++ ) + { + String part = FileSystem.sanitizePath( arguments.getString( i ), true ); + if( result.length() != 0 && !part.isEmpty() ) result.append( '/' ); + result.append( part ); + } + + return FileSystem.sanitizePath( result.toString(), true ); } /** @@ -385,8 +397,8 @@ public class FSAPI implements ILuaAPI * * @param path The path to check the free space for. * @return The amount of free space available, in bytes. - * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". * @throws LuaException If the path doesn't exist. + * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". */ @LuaFunction public final Object getFreeSpace( String path ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 644515e1c..bb6c7149c 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -98,7 +98,7 @@ public class FileSystem mounts.remove( sanitizePath( path ) ); } - public synchronized String combine( String path, String childPath ) + public String combine( String path, String childPath ) { path = sanitizePath( path, true ); childPath = sanitizePath( childPath, true ); @@ -479,7 +479,7 @@ public class FileSystem private static final Pattern threeDotsPattern = Pattern.compile( "^\\.{3,}$" ); - private static String sanitizePath( String path, boolean allowWildcards ) + public static String sanitizePath( String path, boolean allowWildcards ) { // Allow windowsy slashes path = path.replace( '\\', '/' ); diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua index 58db9e566..9a861af34 100644 --- a/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -39,15 +39,19 @@ describe("The fs library", function() end) end) - describe("fs.list", function() - it("fails on files", function() - expect.error(fs.list, "rom/startup.lua"):eq("/rom/startup.lua: Not a directory") - expect.error(fs.list, "startup.lua"):eq("/startup.lua: Not a directory") + describe("fs.combine", function() + it("removes . and ..", function() + expect(fs.combine("./a/b")):eq("a/b") + expect(fs.combine("a/b", "../c")):eq("a/c") + expect(fs.combine("a", "../c")):eq("c") + expect(fs.combine("a", "../../c")):eq("../c") end) - it("fails on non-existent nodes", function() - expect.error(fs.list, "rom/x"):eq("/rom/x: Not a directory") - expect.error(fs.list, "x"):eq("/x: Not a directory") + it("combines empty paths", function() + expect(fs.combine("a")):eq("a") + expect(fs.combine("a", "")):eq("a") + expect(fs.combine("", "a")):eq("a") + expect(fs.combine("a", "", "b", "c")):eq("a/b/c") end) end) From 6734a0e112c29541bc6611cc26c18874ec7a4c18 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 28 Nov 2020 12:06:25 +0000 Subject: [PATCH 377/711] Also generate computer models I'm getting quite addicted to this. Maybe less savings than monitors, but still worth doing due to the number of files created. Also fix our angle calculations for monitors. Thankfully we hadn't shipped this yet :). --- .../blockstates/computer_advanced.json | 49 +++++ .../blockstates/computer_command.json | 49 +++++ .../blockstates/computer_normal.json | 49 +++++ .../blockstates/monitor_advanced.json | 192 +++++++++--------- .../blockstates/monitor_normal.json | 192 +++++++++--------- .../block/computer_advanced_blinking.json | 8 + .../models/block/computer_advanced_off.json | 8 + .../models/block/computer_advanced_on.json | 8 + .../block/computer_command_blinking.json | 8 + .../models/block/computer_command_off.json | 8 + .../models/block/computer_command_on.json | 8 + .../block/computer_normal_blinking.json | 8 + .../models/block/computer_normal_off.json | 8 + .../models/block/computer_normal_on.json | 8 + .../data/BlockModelProvider.java | 70 ++++++- .../blockstates/computer_advanced.json | 18 -- .../blockstates/computer_command.json | 19 -- .../blockstates/computer_normal.json | 18 -- .../block/computer_advanced_blinking.json | 8 - .../models/block/computer_advanced_off.json | 8 - .../models/block/computer_advanced_on.json | 8 - .../block/computer_command_blinking.json | 8 - .../models/block/computer_command_off.json | 8 - .../models/block/computer_command_on.json | 8 - .../block/computer_normal_blinking.json | 8 - .../models/block/computer_normal_off.json | 8 - .../models/block/computer_normal_on.json | 8 - 27 files changed, 473 insertions(+), 327 deletions(-) create mode 100644 src/generated/resources/assets/computercraft/blockstates/computer_advanced.json create mode 100644 src/generated/resources/assets/computercraft/blockstates/computer_command.json create mode 100644 src/generated/resources/assets/computercraft/blockstates/computer_normal.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_command_off.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_command_on.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_normal_off.json create mode 100644 src/generated/resources/assets/computercraft/models/block/computer_normal_on.json delete mode 100644 src/main/resources/assets/computercraft/blockstates/computer_advanced.json delete mode 100644 src/main/resources/assets/computercraft/blockstates/computer_command.json delete mode 100644 src/main/resources/assets/computercraft/blockstates/computer_normal.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_advanced_off.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_advanced_on.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_command_blinking.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_command_off.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_command_on.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_normal_off.json delete mode 100644 src/main/resources/assets/computercraft/models/block/computer_normal_on.json diff --git a/src/generated/resources/assets/computercraft/blockstates/computer_advanced.json b/src/generated/resources/assets/computercraft/blockstates/computer_advanced.json new file mode 100644 index 000000000..ca62effa6 --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/computer_advanced.json @@ -0,0 +1,49 @@ +{ + "variants": { + "facing=north,state=off": { + "model": "computercraft:block/computer_advanced_off" + }, + "facing=south,state=off": { + "model": "computercraft:block/computer_advanced_off", + "y": 180 + }, + "facing=west,state=off": { + "model": "computercraft:block/computer_advanced_off", + "y": 270 + }, + "facing=east,state=off": { + "model": "computercraft:block/computer_advanced_off", + "y": 90 + }, + "facing=north,state=on": { + "model": "computercraft:block/computer_advanced_on" + }, + "facing=south,state=on": { + "model": "computercraft:block/computer_advanced_on", + "y": 180 + }, + "facing=west,state=on": { + "model": "computercraft:block/computer_advanced_on", + "y": 270 + }, + "facing=east,state=on": { + "model": "computercraft:block/computer_advanced_on", + "y": 90 + }, + "facing=north,state=blinking": { + "model": "computercraft:block/computer_advanced_blinking" + }, + "facing=south,state=blinking": { + "model": "computercraft:block/computer_advanced_blinking", + "y": 180 + }, + "facing=west,state=blinking": { + "model": "computercraft:block/computer_advanced_blinking", + "y": 270 + }, + "facing=east,state=blinking": { + "model": "computercraft:block/computer_advanced_blinking", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/computer_command.json b/src/generated/resources/assets/computercraft/blockstates/computer_command.json new file mode 100644 index 000000000..d0580539a --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/computer_command.json @@ -0,0 +1,49 @@ +{ + "variants": { + "facing=north,state=off": { + "model": "computercraft:block/computer_command_off" + }, + "facing=south,state=off": { + "model": "computercraft:block/computer_command_off", + "y": 180 + }, + "facing=west,state=off": { + "model": "computercraft:block/computer_command_off", + "y": 270 + }, + "facing=east,state=off": { + "model": "computercraft:block/computer_command_off", + "y": 90 + }, + "facing=north,state=on": { + "model": "computercraft:block/computer_command_on" + }, + "facing=south,state=on": { + "model": "computercraft:block/computer_command_on", + "y": 180 + }, + "facing=west,state=on": { + "model": "computercraft:block/computer_command_on", + "y": 270 + }, + "facing=east,state=on": { + "model": "computercraft:block/computer_command_on", + "y": 90 + }, + "facing=north,state=blinking": { + "model": "computercraft:block/computer_command_blinking" + }, + "facing=south,state=blinking": { + "model": "computercraft:block/computer_command_blinking", + "y": 180 + }, + "facing=west,state=blinking": { + "model": "computercraft:block/computer_command_blinking", + "y": 270 + }, + "facing=east,state=blinking": { + "model": "computercraft:block/computer_command_blinking", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/computer_normal.json b/src/generated/resources/assets/computercraft/blockstates/computer_normal.json new file mode 100644 index 000000000..4108d0aa9 --- /dev/null +++ b/src/generated/resources/assets/computercraft/blockstates/computer_normal.json @@ -0,0 +1,49 @@ +{ + "variants": { + "facing=north,state=off": { + "model": "computercraft:block/computer_normal_off" + }, + "facing=south,state=off": { + "model": "computercraft:block/computer_normal_off", + "y": 180 + }, + "facing=west,state=off": { + "model": "computercraft:block/computer_normal_off", + "y": 270 + }, + "facing=east,state=off": { + "model": "computercraft:block/computer_normal_off", + "y": 90 + }, + "facing=north,state=on": { + "model": "computercraft:block/computer_normal_on" + }, + "facing=south,state=on": { + "model": "computercraft:block/computer_normal_on", + "y": 180 + }, + "facing=west,state=on": { + "model": "computercraft:block/computer_normal_on", + "y": 270 + }, + "facing=east,state=on": { + "model": "computercraft:block/computer_normal_on", + "y": 90 + }, + "facing=north,state=blinking": { + "model": "computercraft:block/computer_normal_blinking" + }, + "facing=south,state=blinking": { + "model": "computercraft:block/computer_normal_blinking", + "y": 180 + }, + "facing=west,state=blinking": { + "model": "computercraft:block/computer_normal_blinking", + "y": 270 + }, + "facing=east,state=blinking": { + "model": "computercraft:block/computer_normal_blinking", + "y": 90 + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json b/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json index 978e3ed95..230c2c727 100644 --- a/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json +++ b/src/generated/resources/assets/computercraft/blockstates/monitor_advanced.json @@ -12,12 +12,12 @@ "facing=west,orientation=down,state=none": { "model": "computercraft:block/monitor_advanced", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=none": { "model": "computercraft:block/monitor_advanced", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", @@ -31,12 +31,12 @@ "facing=west,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=none": { "model": "computercraft:block/monitor_advanced", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced" @@ -47,11 +47,11 @@ }, "facing=west,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=none": { "model": "computercraft:block/monitor_advanced", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", @@ -65,12 +65,12 @@ "facing=west,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", @@ -84,12 +84,12 @@ "facing=west,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=l": { "model": "computercraft:block/monitor_advanced_l", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l" @@ -100,11 +100,11 @@ }, "facing=west,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=l": { "model": "computercraft:block/monitor_advanced_l", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", @@ -118,12 +118,12 @@ "facing=west,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", @@ -137,12 +137,12 @@ "facing=west,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=r": { "model": "computercraft:block/monitor_advanced_r", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r" @@ -153,11 +153,11 @@ }, "facing=west,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=r": { "model": "computercraft:block/monitor_advanced_r", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lr": { "model": "computercraft:block/monitor_advanced_lr", @@ -171,12 +171,12 @@ "facing=west,orientation=down,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lr": { "model": "computercraft:block/monitor_advanced_lr", @@ -190,12 +190,12 @@ "facing=west,orientation=up,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lr": { "model": "computercraft:block/monitor_advanced_lr", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr" @@ -206,11 +206,11 @@ }, "facing=west,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lr": { "model": "computercraft:block/monitor_advanced_lr", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", @@ -224,12 +224,12 @@ "facing=west,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", @@ -243,12 +243,12 @@ "facing=west,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=u": { "model": "computercraft:block/monitor_advanced_u", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u" @@ -259,11 +259,11 @@ }, "facing=west,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=u": { "model": "computercraft:block/monitor_advanced_u", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", @@ -277,12 +277,12 @@ "facing=west,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", @@ -296,12 +296,12 @@ "facing=west,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=d": { "model": "computercraft:block/monitor_advanced_d", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d" @@ -312,11 +312,11 @@ }, "facing=west,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=d": { "model": "computercraft:block/monitor_advanced_d", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=ud": { "model": "computercraft:block/monitor_advanced_ud", @@ -330,12 +330,12 @@ "facing=west,orientation=down,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=ud": { "model": "computercraft:block/monitor_advanced_ud", @@ -349,12 +349,12 @@ "facing=west,orientation=up,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=ud": { "model": "computercraft:block/monitor_advanced_ud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud" @@ -365,11 +365,11 @@ }, "facing=west,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=ud": { "model": "computercraft:block/monitor_advanced_ud", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=rd": { "model": "computercraft:block/monitor_advanced_rd", @@ -383,12 +383,12 @@ "facing=west,orientation=down,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=rd": { "model": "computercraft:block/monitor_advanced_rd", @@ -402,12 +402,12 @@ "facing=west,orientation=up,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=rd": { "model": "computercraft:block/monitor_advanced_rd", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd" @@ -418,11 +418,11 @@ }, "facing=west,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=rd": { "model": "computercraft:block/monitor_advanced_rd", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=ld": { "model": "computercraft:block/monitor_advanced_ld", @@ -436,12 +436,12 @@ "facing=west,orientation=down,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=ld": { "model": "computercraft:block/monitor_advanced_ld", @@ -455,12 +455,12 @@ "facing=west,orientation=up,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=ld": { "model": "computercraft:block/monitor_advanced_ld", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld" @@ -471,11 +471,11 @@ }, "facing=west,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=ld": { "model": "computercraft:block/monitor_advanced_ld", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=ru": { "model": "computercraft:block/monitor_advanced_ru", @@ -489,12 +489,12 @@ "facing=west,orientation=down,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=ru": { "model": "computercraft:block/monitor_advanced_ru", @@ -508,12 +508,12 @@ "facing=west,orientation=up,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=ru": { "model": "computercraft:block/monitor_advanced_ru", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru" @@ -524,11 +524,11 @@ }, "facing=west,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=ru": { "model": "computercraft:block/monitor_advanced_ru", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lu": { "model": "computercraft:block/monitor_advanced_lu", @@ -542,12 +542,12 @@ "facing=west,orientation=down,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lu": { "model": "computercraft:block/monitor_advanced_lu", @@ -561,12 +561,12 @@ "facing=west,orientation=up,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lu": { "model": "computercraft:block/monitor_advanced_lu", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu" @@ -577,11 +577,11 @@ }, "facing=west,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lu": { "model": "computercraft:block/monitor_advanced_lu", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", @@ -595,12 +595,12 @@ "facing=west,orientation=down,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", @@ -614,12 +614,12 @@ "facing=west,orientation=up,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd" @@ -630,11 +630,11 @@ }, "facing=west,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lrd": { "model": "computercraft:block/monitor_advanced_lrd", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=rud": { "model": "computercraft:block/monitor_advanced_rud", @@ -648,12 +648,12 @@ "facing=west,orientation=down,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=rud": { "model": "computercraft:block/monitor_advanced_rud", @@ -667,12 +667,12 @@ "facing=west,orientation=up,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=rud": { "model": "computercraft:block/monitor_advanced_rud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud" @@ -683,11 +683,11 @@ }, "facing=west,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=rud": { "model": "computercraft:block/monitor_advanced_rud", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lud": { "model": "computercraft:block/monitor_advanced_lud", @@ -701,12 +701,12 @@ "facing=west,orientation=down,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lud": { "model": "computercraft:block/monitor_advanced_lud", @@ -720,12 +720,12 @@ "facing=west,orientation=up,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lud": { "model": "computercraft:block/monitor_advanced_lud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud" @@ -736,11 +736,11 @@ }, "facing=west,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lud": { "model": "computercraft:block/monitor_advanced_lud", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lru": { "model": "computercraft:block/monitor_advanced_lru", @@ -754,12 +754,12 @@ "facing=west,orientation=down,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lru": { "model": "computercraft:block/monitor_advanced_lru", @@ -773,12 +773,12 @@ "facing=west,orientation=up,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lru": { "model": "computercraft:block/monitor_advanced_lru", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru" @@ -789,11 +789,11 @@ }, "facing=west,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lru": { "model": "computercraft:block/monitor_advanced_lru", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", @@ -807,12 +807,12 @@ "facing=west,orientation=down,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", @@ -826,12 +826,12 @@ "facing=west,orientation=up,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud" @@ -842,11 +842,11 @@ }, "facing=west,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lrud": { "model": "computercraft:block/monitor_advanced_lrud", - "y": -90 + "y": 90 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json b/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json index 64d2d4ce9..f3f94002e 100644 --- a/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json +++ b/src/generated/resources/assets/computercraft/blockstates/monitor_normal.json @@ -12,12 +12,12 @@ "facing=west,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=none": { "model": "computercraft:block/monitor_normal", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", @@ -31,12 +31,12 @@ "facing=west,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=none": { "model": "computercraft:block/monitor_normal", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=none": { "model": "computercraft:block/monitor_normal" @@ -47,11 +47,11 @@ }, "facing=west,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=none": { "model": "computercraft:block/monitor_normal", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", @@ -65,12 +65,12 @@ "facing=west,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", @@ -84,12 +84,12 @@ "facing=west,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=l": { "model": "computercraft:block/monitor_normal_l", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l" @@ -100,11 +100,11 @@ }, "facing=west,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=l": { "model": "computercraft:block/monitor_normal_l", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", @@ -118,12 +118,12 @@ "facing=west,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", @@ -137,12 +137,12 @@ "facing=west,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=r": { "model": "computercraft:block/monitor_normal_r", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r" @@ -153,11 +153,11 @@ }, "facing=west,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=r": { "model": "computercraft:block/monitor_normal_r", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", @@ -171,12 +171,12 @@ "facing=west,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", @@ -190,12 +190,12 @@ "facing=west,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lr": { "model": "computercraft:block/monitor_normal_lr", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr" @@ -206,11 +206,11 @@ }, "facing=west,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lr": { "model": "computercraft:block/monitor_normal_lr", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", @@ -224,12 +224,12 @@ "facing=west,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", @@ -243,12 +243,12 @@ "facing=west,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=u": { "model": "computercraft:block/monitor_normal_u", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u" @@ -259,11 +259,11 @@ }, "facing=west,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=u": { "model": "computercraft:block/monitor_normal_u", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", @@ -277,12 +277,12 @@ "facing=west,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", @@ -296,12 +296,12 @@ "facing=west,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=d": { "model": "computercraft:block/monitor_normal_d", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d" @@ -312,11 +312,11 @@ }, "facing=west,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=d": { "model": "computercraft:block/monitor_normal_d", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", @@ -330,12 +330,12 @@ "facing=west,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", @@ -349,12 +349,12 @@ "facing=west,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=ud": { "model": "computercraft:block/monitor_normal_ud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud" @@ -365,11 +365,11 @@ }, "facing=west,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=ud": { "model": "computercraft:block/monitor_normal_ud", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", @@ -383,12 +383,12 @@ "facing=west,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", @@ -402,12 +402,12 @@ "facing=west,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=rd": { "model": "computercraft:block/monitor_normal_rd", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd" @@ -418,11 +418,11 @@ }, "facing=west,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=rd": { "model": "computercraft:block/monitor_normal_rd", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", @@ -436,12 +436,12 @@ "facing=west,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", @@ -455,12 +455,12 @@ "facing=west,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=ld": { "model": "computercraft:block/monitor_normal_ld", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld" @@ -471,11 +471,11 @@ }, "facing=west,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=ld": { "model": "computercraft:block/monitor_normal_ld", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", @@ -489,12 +489,12 @@ "facing=west,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", @@ -508,12 +508,12 @@ "facing=west,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=ru": { "model": "computercraft:block/monitor_normal_ru", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru" @@ -524,11 +524,11 @@ }, "facing=west,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=ru": { "model": "computercraft:block/monitor_normal_ru", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", @@ -542,12 +542,12 @@ "facing=west,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", @@ -561,12 +561,12 @@ "facing=west,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lu": { "model": "computercraft:block/monitor_normal_lu", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu" @@ -577,11 +577,11 @@ }, "facing=west,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lu": { "model": "computercraft:block/monitor_normal_lu", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", @@ -595,12 +595,12 @@ "facing=west,orientation=down,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", @@ -614,12 +614,12 @@ "facing=west,orientation=up,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd" @@ -630,11 +630,11 @@ }, "facing=west,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lrd": { "model": "computercraft:block/monitor_normal_lrd", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=rud": { "model": "computercraft:block/monitor_normal_rud", @@ -648,12 +648,12 @@ "facing=west,orientation=down,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=rud": { "model": "computercraft:block/monitor_normal_rud", @@ -667,12 +667,12 @@ "facing=west,orientation=up,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=rud": { "model": "computercraft:block/monitor_normal_rud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud" @@ -683,11 +683,11 @@ }, "facing=west,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=rud": { "model": "computercraft:block/monitor_normal_rud", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lud": { "model": "computercraft:block/monitor_normal_lud", @@ -701,12 +701,12 @@ "facing=west,orientation=down,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lud": { "model": "computercraft:block/monitor_normal_lud", @@ -720,12 +720,12 @@ "facing=west,orientation=up,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lud": { "model": "computercraft:block/monitor_normal_lud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud" @@ -736,11 +736,11 @@ }, "facing=west,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lud": { "model": "computercraft:block/monitor_normal_lud", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lru": { "model": "computercraft:block/monitor_normal_lru", @@ -754,12 +754,12 @@ "facing=west,orientation=down,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lru": { "model": "computercraft:block/monitor_normal_lru", @@ -773,12 +773,12 @@ "facing=west,orientation=up,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lru": { "model": "computercraft:block/monitor_normal_lru", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru" @@ -789,11 +789,11 @@ }, "facing=west,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lru": { "model": "computercraft:block/monitor_normal_lru", - "y": -90 + "y": 90 }, "facing=north,orientation=down,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", @@ -807,12 +807,12 @@ "facing=west,orientation=down,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 90, - "y": 90 + "y": 270 }, "facing=east,orientation=down,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 90, - "y": -90 + "y": 90 }, "facing=north,orientation=up,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", @@ -826,12 +826,12 @@ "facing=west,orientation=up,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 270, - "y": 90 + "y": 270 }, "facing=east,orientation=up,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", "x": 270, - "y": -90 + "y": 90 }, "facing=north,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud" @@ -842,11 +842,11 @@ }, "facing=west,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", - "y": 90 + "y": 270 }, "facing=east,orientation=north,state=lrud": { "model": "computercraft:block/monitor_normal_lrud", - "y": -90 + "y": 90 } } } \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json b/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json new file mode 100644 index 000000000..25965f980 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_advanced_top", + "side": "computercraft:block/computer_advanced_side", + "front": "computercraft:block/computer_advanced_front_blink" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json b/src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json new file mode 100644 index 000000000..264f6932e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_advanced_off.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_advanced_top", + "side": "computercraft:block/computer_advanced_side", + "front": "computercraft:block/computer_advanced_front" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json b/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json new file mode 100644 index 000000000..1a088dadc --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_advanced_top", + "side": "computercraft:block/computer_advanced_side", + "front": "computercraft:block/computer_advanced_front_on" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json b/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json new file mode 100644 index 000000000..4ad39b620 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_command_top", + "side": "computercraft:block/computer_command_side", + "front": "computercraft:block/computer_command_front_blink" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_command_off.json b/src/generated/resources/assets/computercraft/models/block/computer_command_off.json new file mode 100644 index 000000000..9223552ef --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_command_off.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_command_top", + "side": "computercraft:block/computer_command_side", + "front": "computercraft:block/computer_command_front" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_command_on.json b/src/generated/resources/assets/computercraft/models/block/computer_command_on.json new file mode 100644 index 000000000..635df67ee --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_command_on.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_command_top", + "side": "computercraft:block/computer_command_side", + "front": "computercraft:block/computer_command_front_on" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json b/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json new file mode 100644 index 000000000..fb01777c4 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_normal_top", + "side": "computercraft:block/computer_normal_side", + "front": "computercraft:block/computer_normal_front_blink" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_normal_off.json b/src/generated/resources/assets/computercraft/models/block/computer_normal_off.json new file mode 100644 index 000000000..08288705e --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_normal_off.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_normal_top", + "side": "computercraft:block/computer_normal_side", + "front": "computercraft:block/computer_normal_front" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json b/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json new file mode 100644 index 000000000..f5ca31116 --- /dev/null +++ b/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json @@ -0,0 +1,8 @@ +{ + "parent": "block/orientable", + "textures": { + "top": "computercraft:block/computer_normal_top", + "side": "computercraft:block/computer_normal_side", + "front": "computercraft:block/computer_normal_front_on" + } +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java index 0ab5c92b8..6aea58d25 100644 --- a/src/main/java/dan200/computercraft/data/BlockModelProvider.java +++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java @@ -8,6 +8,8 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.Registry; +import dan200.computercraft.shared.computer.blocks.BlockComputer; +import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.peripheral.monitor.BlockMonitor; import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState; import net.minecraft.block.Block; @@ -20,12 +22,14 @@ import javax.annotation.Nonnull; public class BlockModelProvider extends BlockStateProvider { - private final ModelFile root; + private final ModelFile monitorBase; + private final ModelFile orientable; public BlockModelProvider( DataGenerator generator, ExistingFileHelper existingFileHelper ) { super( generator, ComputerCraft.MOD_ID, existingFileHelper ); - root = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) ); + monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) ); + orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) ); } @Nonnull @@ -40,9 +44,35 @@ public class BlockModelProvider extends BlockStateProvider { registerMonitors( Registry.ModBlocks.MONITOR_NORMAL.get() ); registerMonitors( Registry.ModBlocks.MONITOR_ADVANCED.get() ); + + registerComputer( Registry.ModBlocks.COMPUTER_NORMAL.get() ); + registerComputer( Registry.ModBlocks.COMPUTER_ADVANCED.get() ); + registerComputer( Registry.ModBlocks.COMPUTER_COMMAND.get() ); } - private void registerMonitors( Block block ) + private void registerComputer( BlockComputer block ) + { + VariantBlockStateBuilder builder = getVariantBuilder( block ); + for( ComputerState state : BlockComputer.STATE.getAllowedValues() ) + { + BlockModelBuilder model = models() + .getBuilder( suffix( block, "_" + state ) ) + .parent( orientable ) + .texture( "top", suffix( block, "_top" ) ) + .texture( "side", suffix( block, "_side" ) ) + .texture( "front", suffix( block, "_front" + toSuffix( state ) ) ); + + for( Direction facing : BlockComputer.FACING.getAllowedValues() ) + { + builder.partialState() + .with( BlockComputer.STATE, state ) + .with( BlockComputer.FACING, facing ) + .addModels( new ConfiguredModel( model, 0, toYAngle( facing ), false ) ); + } + } + } + + private void registerMonitors( BlockMonitor block ) { String name = block.getRegistryName().getPath(); registerMonitorModel( name, "", 16, 4, 0, 32 ); @@ -66,8 +96,7 @@ public class BlockModelProvider extends BlockStateProvider for( MonitorEdgeState edge : BlockMonitor.STATE.getAllowedValues() ) { String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getName(); - ResourceLocation modelName = new ResourceLocation( ComputerCraft.MOD_ID, "block/" + name + suffix ); - ModelFile model = models().getBuilder( modelName.toString() ); + ModelFile model = models().getBuilder( suffix( block, suffix ) ); for( Direction facing : BlockMonitor.FACING.getAllowedValues() ) { @@ -77,7 +106,7 @@ public class BlockModelProvider extends BlockStateProvider .with( BlockMonitor.STATE, edge ) .with( BlockMonitor.FACING, facing ) .with( BlockMonitor.ORIENTATION, orientation ) - .addModels( new ConfiguredModel( model, toXAngle( orientation ), 180 - (int) facing.getHorizontalAngle(), false ) ); + .addModels( new ConfiguredModel( model, toXAngle( orientation ), toYAngle( facing ), false ) ); } } } @@ -87,14 +116,14 @@ public class BlockModelProvider extends BlockStateProvider { String texturePrefix = ComputerCraft.MOD_ID + ":block/" + prefix + "_"; models().getBuilder( prefix + corners ) - .parent( root ) + .parent( monitorBase ) .texture( "front", texturePrefix + front ) .texture( "side", texturePrefix + side ) .texture( "top", texturePrefix + top ) .texture( "back", texturePrefix + back ); } - private int toXAngle( Direction direction ) + private static int toXAngle( Direction direction ) { switch( direction ) { @@ -106,4 +135,29 @@ public class BlockModelProvider extends BlockStateProvider return 90; } } + + private static int toYAngle( Direction direction ) + { + return ((int) direction.getHorizontalAngle() + 180) % 360; + } + + private static String toSuffix( ComputerState state ) + { + switch( state ) + { + default: + case OFF: + return ""; + case ON: + return "_on"; + case BLINKING: + return "_blink"; + } + } + + private static String suffix( Block block, String suffix ) + { + ResourceLocation id = block.getRegistryName(); + return new ResourceLocation( id.getNamespace(), "block/" + id.getPath() + suffix ).toString(); + } } diff --git a/src/main/resources/assets/computercraft/blockstates/computer_advanced.json b/src/main/resources/assets/computercraft/blockstates/computer_advanced.json deleted file mode 100644 index f438720d8..000000000 --- a/src/main/resources/assets/computercraft/blockstates/computer_advanced.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "variants": { - "facing=north,state=off": { "model": "computercraft:block/computer_advanced_off" }, - "facing=south,state=off": { "model": "computercraft:block/computer_advanced_off", "y": 180 }, - "facing=west,state=off": { "model": "computercraft:block/computer_advanced_off", "y": 270 }, - "facing=east,state=off": { "model": "computercraft:block/computer_advanced_off", "y": 90 }, - - "facing=north,state=on": { "model": "computercraft:block/computer_advanced_on" }, - "facing=south,state=on": { "model": "computercraft:block/computer_advanced_on", "y": 180 }, - "facing=west,state=on": { "model": "computercraft:block/computer_advanced_on", "y": 270 }, - "facing=east,state=on": { "model": "computercraft:block/computer_advanced_on", "y": 90 }, - - "facing=north,state=blinking": { "model": "computercraft:block/computer_advanced_blinking" }, - "facing=south,state=blinking": { "model": "computercraft:block/computer_advanced_blinking", "y": 180 }, - "facing=west,state=blinking": { "model": "computercraft:block/computer_advanced_blinking", "y": 270 }, - "facing=east,state=blinking": { "model": "computercraft:block/computer_advanced_blinking", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/computer_command.json b/src/main/resources/assets/computercraft/blockstates/computer_command.json deleted file mode 100644 index cb45d46c2..000000000 --- a/src/main/resources/assets/computercraft/blockstates/computer_command.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "variants": { - - "facing=north,state=off": { "model": "computercraft:block/computer_command_off" }, - "facing=south,state=off": { "model": "computercraft:block/computer_command_off", "y": 180 }, - "facing=west,state=off": { "model": "computercraft:block/computer_command_off", "y": 270 }, - "facing=east,state=off": { "model": "computercraft:block/computer_command_off", "y": 90 }, - - "facing=north,state=on": { "model": "computercraft:block/computer_command_on" }, - "facing=south,state=on": { "model": "computercraft:block/computer_command_on", "y": 180 }, - "facing=west,state=on": { "model": "computercraft:block/computer_command_on", "y": 270 }, - "facing=east,state=on": { "model": "computercraft:block/computer_command_on", "y": 90 }, - - "facing=north,state=blinking": { "model": "computercraft:block/computer_command_blinking" }, - "facing=south,state=blinking": { "model": "computercraft:block/computer_command_blinking", "y": 180 }, - "facing=west,state=blinking": { "model": "computercraft:block/computer_command_blinking", "y": 270 }, - "facing=east,state=blinking": { "model": "computercraft:block/computer_command_blinking", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/blockstates/computer_normal.json b/src/main/resources/assets/computercraft/blockstates/computer_normal.json deleted file mode 100644 index 95e521a7d..000000000 --- a/src/main/resources/assets/computercraft/blockstates/computer_normal.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "variants": { - "facing=north,state=off": { "model": "computercraft:block/computer_normal_off" }, - "facing=south,state=off": { "model": "computercraft:block/computer_normal_off", "y": 180 }, - "facing=west,state=off": { "model": "computercraft:block/computer_normal_off", "y": 270 }, - "facing=east,state=off": { "model": "computercraft:block/computer_normal_off", "y": 90 }, - - "facing=north,state=on": { "model": "computercraft:block/computer_normal_on" }, - "facing=south,state=on": { "model": "computercraft:block/computer_normal_on", "y": 180 }, - "facing=west,state=on": { "model": "computercraft:block/computer_normal_on", "y": 270 }, - "facing=east,state=on": { "model": "computercraft:block/computer_normal_on", "y": 90 }, - - "facing=north,state=blinking": { "model": "computercraft:block/computer_normal_blinking" }, - "facing=south,state=blinking": { "model": "computercraft:block/computer_normal_blinking", "y": 180 }, - "facing=west,state=blinking": { "model": "computercraft:block/computer_normal_blinking", "y": 270 }, - "facing=east,state=blinking": { "model": "computercraft:block/computer_normal_blinking", "y": 90 } - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json b/src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json deleted file mode 100644 index ed4c9bec3..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_advanced_blinking.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_advanced_front_blink", - "side": "computercraft:block/computer_advanced_side", - "top": "computercraft:block/computer_advanced_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_advanced_off.json b/src/main/resources/assets/computercraft/models/block/computer_advanced_off.json deleted file mode 100644 index 8631c88ed..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_advanced_off.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_advanced_front", - "side": "computercraft:block/computer_advanced_side", - "top": "computercraft:block/computer_advanced_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_advanced_on.json b/src/main/resources/assets/computercraft/models/block/computer_advanced_on.json deleted file mode 100644 index 2692aab84..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_advanced_on.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_advanced_front_on", - "side": "computercraft:block/computer_advanced_side", - "top": "computercraft:block/computer_advanced_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_command_blinking.json b/src/main/resources/assets/computercraft/models/block/computer_command_blinking.json deleted file mode 100644 index 09d7ac1b3..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_command_blinking.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_command_front_blink", - "side": "computercraft:block/computer_command_side", - "top": "computercraft:block/computer_command_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_command_off.json b/src/main/resources/assets/computercraft/models/block/computer_command_off.json deleted file mode 100644 index eaa4970b9..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_command_off.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_command_front", - "side": "computercraft:block/computer_command_side", - "top": "computercraft:block/computer_command_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_command_on.json b/src/main/resources/assets/computercraft/models/block/computer_command_on.json deleted file mode 100644 index 7d4730140..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_command_on.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_command_front_on", - "side": "computercraft:block/computer_command_side", - "top": "computercraft:block/computer_command_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json b/src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json deleted file mode 100644 index d6d70f696..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_normal_blinking.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_normal_front_blink", - "side": "computercraft:block/computer_normal_side", - "top": "computercraft:block/computer_normal_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_normal_off.json b/src/main/resources/assets/computercraft/models/block/computer_normal_off.json deleted file mode 100644 index 5d200f816..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_normal_off.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_normal_front", - "side": "computercraft:block/computer_normal_side", - "top": "computercraft:block/computer_normal_top" - } -} diff --git a/src/main/resources/assets/computercraft/models/block/computer_normal_on.json b/src/main/resources/assets/computercraft/models/block/computer_normal_on.json deleted file mode 100644 index f434d7fa8..000000000 --- a/src/main/resources/assets/computercraft/models/block/computer_normal_on.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "parent": "block/orientable", - "textures": { - "front": "computercraft:block/computer_normal_front_on", - "side": "computercraft:block/computer_normal_side", - "top": "computercraft:block/computer_normal_top" - } -} From e2761bb31532685b9acd00ff23b19e744c2b085f Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 28 Nov 2020 12:13:43 +0000 Subject: [PATCH 378/711] Woops I ran the tests, just not checkstyle. --- src/main/java/dan200/computercraft/core/apis/FSAPI.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 34a2e0f4c..7d189f34a 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -91,6 +91,7 @@ public class FSAPI implements ILuaAPI * @return The new path, with separators added between parts as needed. * @cc.tparam string path The first part of the path. For example, a parent directory path. * @cc.tparam string ... Additional parts of the path to combine. + * @throws LuaException On argument errors. */ @LuaFunction public final String combine( IArguments arguments ) throws LuaException From 24af36743d08fcdb58439c52bf587b33ed828263 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 28 Nov 2020 13:13:35 +0000 Subject: [PATCH 379/711] Try to handle a turtle being broken while ticked Hopefully fixes #585. Hopefully. --- .../pocket/items/ItemPocketComputer.java | 3 ++ .../shared/turtle/core/TurtleBrain.java | 4 +++ .../shared/turtle/upgrades/TurtleTool.java | 31 ++++++++++++------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index a6258216a..f72b28a31 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -257,6 +257,9 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I public static ServerComputer getServerComputer( @Nonnull ItemStack stack ) { + int session = getSessionID( stack ); + if( session != ComputerCraft.serverComputerRegistry.getSessionID() ) return null; + int instanceID = getInstanceID( stack ); return instanceID >= 0 ? ComputerCraft.serverComputerRegistry.get( instanceID ) : null; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 373d0787c..07b3dec26 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -128,6 +128,10 @@ public class TurtleBrain implements ITurtleAccess { // Advance movement updateCommands(); + + // The block may have been broken while the command was executing (for instance, if a block explodes + // when being mined). If so, abort. + if( m_owner.isRemoved() ) return; } // Advance animation diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index e3ddec335..f76e7b377 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -11,6 +11,7 @@ import dan200.computercraft.api.turtle.*; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import dan200.computercraft.shared.TurtlePermissions; +import dan200.computercraft.shared.turtle.core.TurtleBrain; import dan200.computercraft.shared.turtle.core.TurtlePlaceCommand; import dan200.computercraft.shared.turtle.core.TurtlePlayer; import dan200.computercraft.shared.util.DropConsumer; @@ -111,11 +112,14 @@ public class TurtleTool extends AbstractTurtleUpgrade return 3.0f; } - private TurtleCommandResult attack( final ITurtleAccess turtle, Direction direction, TurtleSide side ) + private TurtleCommandResult attack( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Create a fake player, and orient it appropriately - final World world = turtle.getWorld(); - final BlockPos position = turtle.getPosition(); + World world = turtle.getWorld(); + BlockPos position = turtle.getPosition(); + TileEntity turtleTile = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getTileEntity( position ); + if( turtleTile == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); + final TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction ); // See if there is an entity present @@ -143,7 +147,7 @@ public class TurtleTool extends AbstractTurtleUpgrade } // Start claiming entity drops - DropConsumer.set( hitEntity, turtleDropConsumer( turtle ) ); + DropConsumer.set( hitEntity, turtleDropConsumer( turtleTile, turtle ) ); // Attack the entity boolean attacked = false; @@ -175,7 +179,7 @@ public class TurtleTool extends AbstractTurtleUpgrade } // Stop claiming drops - stopConsuming( turtle ); + stopConsuming( turtleTile, turtle ); // Put everything we collected into the turtles inventory, then return if( attacked ) @@ -193,8 +197,10 @@ public class TurtleTool extends AbstractTurtleUpgrade // Get ready to dig World world = turtle.getWorld(); BlockPos turtlePosition = turtle.getPosition(); - BlockPos blockPosition = turtlePosition.offset( direction ); + TileEntity turtleTile = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getTileEntity( turtlePosition ); + if( turtleTile == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); + BlockPos blockPosition = turtlePosition.offset( direction ); if( world.isAirBlock( blockPosition ) || WorldUtil.isLiquidBlock( world, blockPosition ) ) { return TurtleCommandResult.failure( "Nothing to dig here" ); @@ -234,7 +240,7 @@ public class TurtleTool extends AbstractTurtleUpgrade } // Consume the items the block drops - DropConsumer.set( world, blockPosition, turtleDropConsumer( turtle ) ); + DropConsumer.set( world, blockPosition, turtleDropConsumer( turtleTile, turtle ) ); TileEntity tile = world.getTileEntity( blockPosition ); @@ -253,23 +259,24 @@ public class TurtleTool extends AbstractTurtleUpgrade state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() ); } - stopConsuming( turtle ); + stopConsuming( turtleTile, turtle ); return TurtleCommandResult.success(); } - private static Function turtleDropConsumer( ITurtleAccess turtle ) + private static Function turtleDropConsumer( TileEntity tile, ITurtleAccess turtle ) { - return drop -> InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ); + return drop -> tile.isRemoved() ? drop : InventoryUtil.storeItems( drop, turtle.getItemHandler(), turtle.getSelectedSlot() ); } - private static void stopConsuming( ITurtleAccess turtle ) + private static void stopConsuming( TileEntity tile, ITurtleAccess turtle ) { + Direction direction = tile.isRemoved() ? null : turtle.getDirection().getOpposite(); List extra = DropConsumer.clear(); for( ItemStack remainder : extra ) { - WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection().getOpposite() ); + WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), direction ); } } } From 511eea39a11956c82e2c11a47b2e7cad27f9887e Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 28 Nov 2020 17:53:07 +0000 Subject: [PATCH 380/711] Remove s in usages We fixed the bug in illuaminate, so this should be redundant now. --- .../computercraft/lua/rom/modules/main/cc/completion.lua | 8 ++++---- .../data/computercraft/lua/rom/modules/main/cc/pretty.lua | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua index d07b09506..6315a97cc 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/completion.lua @@ -46,7 +46,7 @@ end -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed name. -- @treturn { string... } A list of suffixes of matching peripherals. --- @usage +-- @usage -- local completion = require "cc.completion" -- read(nil, nil, completion.peripheral) local function peripheral_(text, add_space) @@ -62,7 +62,7 @@ local sides = redstone.getSides() -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed side. -- @treturn { string... } A list of suffixes of matching sides. --- @usage +-- @usage -- local completion = require "cc.completion" -- read(nil, nil, completion.side) local function side(text, add_space) @@ -76,7 +76,7 @@ end -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed settings. -- @treturn { string... } A list of suffixes of matching settings. --- @usage +-- @usage -- local completion = require "cc.completion" -- read(nil, nil, completion.setting) local function setting(text, add_space) @@ -92,7 +92,7 @@ local command_list -- @tparam string text The input string to complete. -- @tparam[opt] boolean add_space Whether to add a space after the completed command. -- @treturn { string... } A list of suffixes of matching commands. --- @usage +-- @usage -- local completion = require "cc.completion" -- read(nil, nil, completion.command) local function command(text, add_space) diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua index 37a70a515..9a3aa7b0a 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua @@ -104,7 +104,7 @@ end -- -- @tparam Doc|string ... The documents to concatenate. -- @treturn Doc The concatenated documents. --- @usage +-- @usage -- local pretty = require "cc.pretty" -- local doc1, doc2 = pretty.text("doc1"), pretty.text("doc2") -- print(pretty.concat(doc1, " - ", doc2)) @@ -141,7 +141,7 @@ Doc.__concat = concat --- @local -- @tparam number depth The number of spaces with which the document should be indented. -- @tparam Doc doc The document to indent. -- @treturn Doc The nested document. --- @usage +-- @usage -- local pretty = require "cc.pretty" -- print(pretty.nest(2, pretty.text("foo\nbar"))) local function nest(depth, doc) From 826797cbd579e867f0f35f0be44b6a28c8c094a9 Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Sun, 29 Nov 2020 06:24:18 -0500 Subject: [PATCH 381/711] Added documentation for global functions (#592) --- doc/stub/global.lua | 74 ++++++++++++++++++- .../shared/turtle/apis/TurtleAPI.java | 2 +- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/doc/stub/global.lua b/doc/stub/global.lua index c0609a1c3..2c0f64ae1 100644 --- a/doc/stub/global.lua +++ b/doc/stub/global.lua @@ -1,6 +1,6 @@ --[[- -Global functions defined by `bios.lua`. This does not include standard Lua -functions. +Functions in the global environment, defined in `bios.lua`. This does not +include standard Lua functions. @module _G ]] @@ -27,18 +27,87 @@ or the @{parallel|parallel API}. nearest multiple of 0.05. @see os.startTimer +@usage Sleep for three seconds. + + print("Sleeping for three seconds") + sleep(3) + print("Done!") ]] function sleep(time) end +--- Writes a line of text to the screen without a newline at the end, wrapping +-- text if necessary. +-- +-- @tparam string text The text to write to the string +-- @treturn number The number of lines written +-- @see print A wrapper around write that adds a newline and accepts multiple arguments +-- @usage write("Hello, world") function write(text) end + +--- Prints the specified values to the screen separated by spaces, wrapping if +-- necessary. After printing, the cursor is moved to the next line. +-- +-- @param ... The values to print on the screen +-- @treturn number The number of lines written +-- @usage print("Hello, world!") function print(...) end + +--- Prints the specified values to the screen in red, separated by spaces, +-- wrapping if necessary. After printing, the cursor is moved to the next line. +-- +-- @param ... The values to print on the screen +-- @usage printError("Something went wrong!") function printError(...) end +--[[- Reads user input from the terminal, automatically handling arrow keys, +pasting, character replacement, history scrollback, auto-completion, and +default values. + +@tparam[opt] string replaceChar A character to replace each typed character with. +This can be used for hiding passwords, for example. +@tparam[opt] table history A table holding history items that can be scrolled +back to with the up/down arrow keys. The oldest item is at index 1, while the +newest item is at the highest index. +@tparam[opt] function(partial: string):({ string... }|nil) completeFn A function +to be used for completion. This function should take the partial text typed so +far, and returns a list of possible completion options. +@tparam[opt] string default Default text which should already be entered into +the prompt. + +@treturn string The text typed in. + +@see cc.completion For functions to help with completion. +@usage Read an string and echo it back to the user + + write("> ") + local msg = read() + print(msg) + +@usage Prompt a user for a password. + + while true do + write("Password> ") + local pwd = read("*") + if pwd == "let me in" then break end + print("Incorrect password, try again.") + end + print("Logged in!") + +@usage A complete example with completion, history and a default value. + + local completion = require "cc.completion" + local history = { "potato", "orange", "apple" } + local choices = { "apple", "orange", "banana", "strawberry" } + write("> ") + local msg = read(nil, history, function(text) return completion.choice(text, choices) end, "app") + print(msg) +]] function read(replaceChar, history, completeFn, default) end --- The ComputerCraft and Minecraft version of the current computer environment. -- -- For example, `ComputerCraft 1.93.0 (Minecraft 1.15.2)`. +-- @usage _HOST _HOST = _HOST --[[- The default computer settings as defined in the ComputerCraft @@ -51,5 +120,6 @@ An example value to disable autocompletion: shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false +@usage _CC_DEFAULT_SETTINGS ]] _CC_DEFAULT_SETTINGS = _CC_DEFAULT_SETTINGS diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 57040804c..b96e3f999 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -501,7 +501,7 @@ public class TurtleAPI implements ILuaAPI } /** - * Get the currently sleected slot. + * Get the currently selected slot. * * @return The current slot. * @see #select From 24d3777722812f975d2bc4594437fbbb0431d910 Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Wed, 2 Dec 2020 14:22:12 -0500 Subject: [PATCH 382/711] Added improved help viewer (#595) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pagination, with (page) up/down, q(uit) and scrolling support. - Render markdown style bullets ('-'/'*') using a '•' instead. --- .../computercraft/lua/rom/programs/help.lua | 123 ++++++++++++++++-- .../test-rom/spec/programs/help_spec.lua | 2 +- 2 files changed, 116 insertions(+), 9 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/help.lua b/src/main/resources/data/computercraft/lua/rom/programs/help.lua index 63ece3ab4..149e9f41e 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/help.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/help.lua @@ -15,12 +15,119 @@ end local sFile = help.lookup(sTopic) local file = sFile ~= nil and io.open(sFile) or nil -if file then - local sContents = file:read("*a") - file:close() - - local _, nHeight = term.getSize() - textutils.pagedPrint(sContents, nHeight - 3) -else - print("No help available") +if not file then + printError("No help available") + return end + +local contents = file:read("*a"):gsub("(\n *)[-*]( +)", "%1\7%2") +file:close() + +local width, height = term.getSize() +local buffer = window.create(term.current(), 1, 1, width, height, false) +local old_term = term.redirect(buffer) + +local print_height = print(contents) + 1 + +-- If we fit within the screen, just display without pagination. +if print_height <= height then + term.redirect(old_term) + print(contents) + return +end + +local function draw_buffer(width) + buffer.reposition(1, 1, width, print_height) + buffer.clear() + buffer.setCursorPos(1, 1) + print(contents) + term.redirect(old_term) +end + +local offset = 0 + +local function draw() + for y = 1, height - 1 do + term.setCursorPos(1, y) + if y + offset > print_height then + -- Should only happen if we resize the terminal to a larger one + -- than actually needed for the current text. + term.clearLine() + else + term.blit(buffer.getLine(y + offset)) + end + end +end + +local function draw_menu() + term.setTextColor(colors.yellow) + term.setCursorPos(1, height) + term.clearLine() + + local tag = "Help: " .. sTopic + term.write("Help: " .. sTopic) + + if width >= #tag + 16 then + term.setCursorPos(width - 14, height) + term.write("Press Q to exit") + end +end + +draw_buffer(width) +draw() +draw_menu() + +while true do + local event, param = os.pullEvent() + if event == "key" then + if param == keys.up and offset > 0 then + offset = offset - 1 + draw() + elseif param == keys.down and offset < print_height - height then + offset = offset + 1 + draw() + elseif param == keys.pageUp and offset > 0 then + offset = math.max(offset - height + 2, 0) + draw() + elseif param == keys.pageDown and offset < print_height - height then + offset = math.min(offset + height - 2, print_height - height) + draw() + elseif param == keys.home then + offset = 0 + draw() + elseif param == keys["end"] then + offset = print_height - height + draw() + elseif param == keys.q then + sleep(0) -- Super janky, but consumes stray "char" events. + break + end + elseif event == "mouse_scroll" then + if param < 0 and offset > 0 then + offset = offset - 1 + draw() + elseif param > 0 and offset < print_height - height then + offset = offset + 1 + draw() + end + elseif event == "term_resize" then + local new_width, new_height = term.getSize() + + if new_width ~= width then + buffer.setCursorPos(1, 1) + buffer.reposition(1, 1, new_width, print_height) + term.redirect(buffer) + print_height = print(contents) + 1 + draw_buffer(new_width) + end + + width, height = new_width, new_height + offset = math.max(math.min(offset, print_height - height), 0) + draw() + draw_menu() + end +end + +term.redirect(old_term) +term.setCursorPos(1, 1) +term.clear() diff --git a/src/test/resources/test-rom/spec/programs/help_spec.lua b/src/test/resources/test-rom/spec/programs/help_spec.lua index 79e4e4742..35ce021b4 100644 --- a/src/test/resources/test-rom/spec/programs/help_spec.lua +++ b/src/test/resources/test-rom/spec/programs/help_spec.lua @@ -3,6 +3,6 @@ local capture = require "test_helpers".capture_program describe("The help program", function() it("errors when there is no such help file", function() expect(capture(stub, "help nothing")) - :matches { ok = true, output = "No help available\n", error = "" } + :matches { ok = true, error = "No help available\n", output = "" } end) end) From d83a68f3ff6e3833278a38798d06215293656e85 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Sat, 5 Dec 2020 11:32:00 +0000 Subject: [PATCH 383/711] Allow $private HTTP rule to block any private IP This is a little magic compared with our previous approach of "list every private IP range", but given then the sheer number we were missing[1][2] this feels more reasonable. Also refactor out some of the logic into separate classes, hopefully to make things a little cleaner. Fixes #594. [1]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml [2]: https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml --- build.gradle | 5 +- .../dan200/computercraft/ComputerCraft.java | 27 +--- .../apis/http/options/AddressPredicate.java | 149 ++++++++++++++++++ .../core/apis/http/options/AddressRule.java | 144 ++++------------- .../dan200/computercraft/shared/Config.java | 12 +- .../apis/http/options/AddressRuleTest.java | 14 ++ .../test-rom/spec/apis/http_spec.lua | 2 + 7 files changed, 209 insertions(+), 144 deletions(-) create mode 100644 src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java diff --git a/build.gradle b/build.gradle index 4f698a445..e19ddfc25 100644 --- a/build.gradle +++ b/build.gradle @@ -116,8 +116,9 @@ dependencies { shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' testImplementation 'org.hamcrest:hamcrest:2.2' deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index d510ab65b..2daa28eb0 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -22,30 +22,17 @@ import net.minecraftforge.fml.common.Mod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; -import java.util.Objects; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.Stream; @Mod( ComputerCraft.MOD_ID ) public final class ComputerCraft { public static final String MOD_ID = "computercraft"; - // Configuration options - public static final String[] DEFAULT_HTTP_ALLOW = new String[] { "*" }; - public static final String[] DEFAULT_HTTP_DENY = new String[] { - "127.0.0.0/8", - "0.0.0.0/8", - "10.0.0.0/8", - "172.16.0.0/12", - "192.168.0.0/16", - "fd00::/8", - }; - public static int computerSpaceLimit = 1000 * 1000; public static int floppySpaceLimit = 125 * 1000; public static int maximumFilesOpen = 128; @@ -61,14 +48,10 @@ public final class ComputerCraft public static boolean httpEnabled = true; public static boolean httpWebsocketEnabled = true; - public static List httpRules = Collections.unmodifiableList( Stream.concat( - Stream.of( DEFAULT_HTTP_DENY ) - .map( x -> AddressRule.parse( x, null, Action.DENY.toPartial() ) ) - .filter( Objects::nonNull ), - Stream.of( DEFAULT_HTTP_ALLOW ) - .map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial() ) ) - .filter( Objects::nonNull ) - ).collect( Collectors.toList() ) ); + public static List httpRules = Collections.unmodifiableList( Arrays.asList( + AddressRule.parse( "$private", null, Action.DENY.toPartial() ), + AddressRule.parse( "*", null, Action.ALLOW.toPartial() ) + ) ); public static int httpMaxRequests = 16; public static int httpMaxWebsockets = 4; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java new file mode 100644 index 000000000..b647f73a3 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java @@ -0,0 +1,149 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.core.apis.http.options; + +import com.google.common.net.InetAddresses; +import dan200.computercraft.ComputerCraft; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.regex.Pattern; + +/** + * A predicate on an address. Matches against a domain and an ip address. + * + * @see AddressRule#apply(Iterable, String, InetSocketAddress) for the actual handling of this rule. + */ +interface AddressPredicate +{ + default boolean matches( String domain ) + { + return false; + } + + default boolean matches( InetAddress socketAddress ) + { + return false; + } + + final class HostRange implements AddressPredicate + { + private final byte[] min; + private final byte[] max; + + HostRange( byte[] min, byte[] max ) + { + this.min = min; + this.max = max; + } + + @Override + public boolean matches( InetAddress address ) + { + byte[] entry = address.getAddress(); + if( entry.length != min.length ) return false; + + for( int i = 0; i < entry.length; i++ ) + { + int value = 0xFF & entry[i]; + if( value < (0xFF & min[i]) || value > (0xFF & max[i]) ) return false; + } + + return true; + } + + public static HostRange parse( String addressStr, String prefixSizeStr ) + { + int prefixSize; + try + { + prefixSize = Integer.parseInt( prefixSizeStr ); + } + catch( NumberFormatException e ) + { + ComputerCraft.log.error( + "Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.", + addressStr + '/' + prefixSizeStr, prefixSizeStr + ); + return null; + } + + InetAddress address; + try + { + address = InetAddresses.forString( addressStr ); + } + catch( IllegalArgumentException e ) + { + ComputerCraft.log.error( + "Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.", + addressStr + '/' + prefixSizeStr, prefixSizeStr + ); + return null; + } + + // Mask the bytes of the IP address. + byte[] minBytes = address.getAddress(), maxBytes = address.getAddress(); + int size = prefixSize; + for( int i = 0; i < minBytes.length; i++ ) + { + if( size <= 0 ) + { + minBytes[i] &= 0; + maxBytes[i] |= 0xFF; + } + else if( size < 8 ) + { + minBytes[i] &= 0xFF << (8 - size); + maxBytes[i] |= ~(0xFF << (8 - size)); + } + + size -= 8; + } + + return new HostRange( minBytes, maxBytes ); + } + } + + final class DomainPattern implements AddressPredicate + { + private final Pattern pattern; + + DomainPattern( Pattern pattern ) + { + this.pattern = pattern; + } + + @Override + public boolean matches( String domain ) + { + return pattern.matcher( domain ).matches(); + } + + @Override + public boolean matches( InetAddress socketAddress ) + { + return pattern.matcher( socketAddress.getHostAddress() ).matches(); + } + } + + + final class PrivatePattern implements AddressPredicate + { + static final PrivatePattern INSTANCE = new PrivatePattern(); + + @Override + public boolean matches( InetAddress socketAddress ) + { + return socketAddress.isAnyLocalAddress() + || socketAddress.isLoopbackAddress() + || socketAddress.isLinkLocalAddress() + || socketAddress.isSiteLocalAddress(); + } + } + +} diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java index c7498f269..f1884e3f3 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java @@ -6,10 +6,13 @@ package dan200.computercraft.core.apis.http.options; import com.google.common.net.InetAddresses; -import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.apis.http.options.AddressPredicate.DomainPattern; +import dan200.computercraft.core.apis.http.options.AddressPredicate.HostRange; +import dan200.computercraft.core.apis.http.options.AddressPredicate.PrivatePattern; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -25,45 +28,13 @@ public final class AddressRule public static final int TIMEOUT = 30_000; public static final int WEBSOCKET_MESSAGE = 128 * 1024; - private static final class HostRange - { - private final byte[] min; - private final byte[] max; - - private HostRange( byte[] min, byte[] max ) - { - this.min = min; - this.max = max; - } - - public boolean contains( InetAddress address ) - { - byte[] entry = address.getAddress(); - if( entry.length != min.length ) return false; - - for( int i = 0; i < entry.length; i++ ) - { - int value = 0xFF & entry[i]; - if( value < (0xFF & min[i]) || value > (0xFF & max[i]) ) return false; - } - - return true; - } - } - - private final HostRange ip; - private final Pattern domainPattern; + private final AddressPredicate predicate; private final Integer port; private final PartialOptions partial; - private AddressRule( - @Nullable HostRange ip, - @Nullable Pattern domainPattern, - @Nullable Integer port, - @Nonnull PartialOptions partial ) + private AddressRule( @Nonnull AddressPredicate predicate, @Nullable Integer port, @Nonnull PartialOptions partial ) { - this.ip = ip; - this.domainPattern = domainPattern; + this.predicate = predicate; this.partial = partial; this.port = port; } @@ -76,103 +47,50 @@ public final class AddressRule { String addressStr = filter.substring( 0, cidr ); String prefixSizeStr = filter.substring( cidr + 1 ); - - int prefixSize; - try - { - prefixSize = Integer.parseInt( prefixSizeStr ); - } - catch( NumberFormatException e ) - { - ComputerCraft.log.error( - "Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.", - filter, prefixSizeStr - ); - return null; - } - - InetAddress address; - try - { - address = InetAddresses.forString( addressStr ); - } - catch( IllegalArgumentException e ) - { - ComputerCraft.log.error( - "Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.", - filter, prefixSizeStr - ); - return null; - } - - // Mask the bytes of the IP address. - byte[] minBytes = address.getAddress(), maxBytes = address.getAddress(); - int size = prefixSize; - for( int i = 0; i < minBytes.length; i++ ) - { - if( size <= 0 ) - { - minBytes[i] &= 0; - maxBytes[i] |= 0xFF; - } - else if( size < 8 ) - { - minBytes[i] &= 0xFF << (8 - size); - maxBytes[i] |= ~(0xFF << (8 - size)); - } - - size -= 8; - } - - return new AddressRule( new HostRange( minBytes, maxBytes ), null, port, partial ); + HostRange range = HostRange.parse( addressStr, prefixSizeStr ); + return range == null ? null : new AddressRule( range, port, partial ); + } + else if( filter.equalsIgnoreCase( "$private" ) ) + { + return new AddressRule( PrivatePattern.INSTANCE, port, partial ); } else { - Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ); - return new AddressRule( null, pattern, port, partial ); + Pattern pattern = Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$", Pattern.CASE_INSENSITIVE ); + return new AddressRule( new DomainPattern( pattern ), port, partial ); } } /** * Determine whether the given address matches a series of patterns. * - * @param domain The domain to match - * @param socketAddress The address to check. + * @param domain The domain to match + * @param port The port of the address. + * @param address The address to check. + * @param ipv4Address An ipv4 version of the address, if the original was an ipv6 address. * @return Whether it matches any of these patterns. */ - private boolean matches( String domain, InetSocketAddress socketAddress ) + private boolean matches( String domain, int port, InetAddress address, Inet4Address ipv4Address ) { - InetAddress address = socketAddress.getAddress(); - if( port != null && port != socketAddress.getPort() ) return false; - - if( domainPattern != null ) - { - if( domainPattern.matcher( domain ).matches() ) return true; - if( domainPattern.matcher( address.getHostName() ).matches() ) return true; - } - - // Match the normal address - if( matchesAddress( address ) ) return true; - - // If we're an IPv4 address in disguise then let's check that. - return address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address ) - && matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) ); + if( this.port != null && this.port != port ) return false; + return predicate.matches( domain ) + || predicate.matches( address ) + || (ipv4Address != null && predicate.matches( ipv4Address )); } - private boolean matchesAddress( InetAddress address ) - { - if( domainPattern != null && domainPattern.matcher( address.getHostAddress() ).matches() ) return true; - return ip != null && ip.contains( address ); - } - - public static Options apply( Iterable rules, String domain, InetSocketAddress address ) + public static Options apply( Iterable rules, String domain, InetSocketAddress socketAddress ) { PartialOptions options = null; boolean hasMany = false; + int port = socketAddress.getPort(); + InetAddress address = socketAddress.getAddress(); + Inet4Address ipv4Address = address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address ) + ? InetAddresses.get6to4IPv4Address( (Inet6Address) address ) : null; + for( AddressRule rule : rules ) { - if( !rule.matches( domain, address ) ) continue; + if( !rule.matches( domain, port, address, ipv4Address ) ) continue; if( options == null ) { diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index a39f513f6..6655d6fd5 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -21,12 +21,12 @@ import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import java.util.stream.Stream; import static net.minecraftforge.common.ForgeConfigSpec.Builder; import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue; @@ -180,12 +180,10 @@ public final class Config "Each rule is an item with a 'host' to match against, and a series of properties. " + "The host may be a domain name (\"pastebin.com\"),\n" + "wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\"). If no rules, the domain is blocked." ) - .defineList( "rules", - Stream.concat( - Stream.of( ComputerCraft.DEFAULT_HTTP_DENY ).map( x -> AddressRuleConfig.makeRule( x, Action.DENY ) ), - Stream.of( ComputerCraft.DEFAULT_HTTP_ALLOW ).map( x -> AddressRuleConfig.makeRule( x, Action.ALLOW ) ) - ).collect( Collectors.toList() ), - x -> x instanceof UnmodifiableConfig && AddressRuleConfig.checkRule( (UnmodifiableConfig) x ) ); + .defineList( "rules", Arrays.asList( + AddressRuleConfig.makeRule( "$private", Action.DENY ), + AddressRuleConfig.makeRule( "*", Action.ALLOW ) + ), x -> x instanceof UnmodifiableConfig && AddressRuleConfig.checkRule( (UnmodifiableConfig) x ) ); httpMaxRequests = builder .comment( "The number of http requests a computer can make at one time. Additional requests will be queued, and sent when the running requests have finished. Set to 0 for unlimited." ) diff --git a/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java index 690cb37f5..3a8246e7f 100644 --- a/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java @@ -6,7 +6,10 @@ package dan200.computercraft.core.apis.http.options; +import dan200.computercraft.ComputerCraft; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.net.InetSocketAddress; import java.util.Collections; @@ -27,6 +30,17 @@ public class AddressRuleTest assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY ); } + @ParameterizedTest + @ValueSource( strings = { + "0.0.0.0", "[::]", + "localhost", "lvh.me", "127.0.0.1", "[::1]", + "172.17.0.1", "192.168.1.114", "[0:0:0:0:0:ffff:c0a8:172]", "10.0.0.1" + } ) + public void blocksLocalDomains( String domain ) + { + assertEquals( apply( ComputerCraft.httpRules, domain, 80 ).action, Action.DENY ); + } + private Options apply( Iterable rules, String host, int port ) { return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) ); diff --git a/src/test/resources/test-rom/spec/apis/http_spec.lua b/src/test/resources/test-rom/spec/apis/http_spec.lua index ecaf1d307..4a6a8b803 100644 --- a/src/test/resources/test-rom/spec/apis/http_spec.lua +++ b/src/test/resources/test-rom/spec/apis/http_spec.lua @@ -12,6 +12,8 @@ describe("The http library", function() end) it("rejects local domains", function() + -- Note, this is tested more thoroughly in AddressRuleTest. We've just got this here + -- to ensure the general control flow works. expect({ http.checkURL("http://localhost") }):same({ false, "Domain not permitted" }) expect({ http.checkURL("http://127.0.0.1") }):same({ false, "Domain not permitted" }) end) From 737b3cb57696fb5517252e7db38bc88ce960b4d8 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 10 Dec 2020 19:02:08 +0000 Subject: [PATCH 384/711] Don't use capabilities for generic peripherals Maybe the capability system was a mistake in retrospect, as we don't store the peripheral outside, so there's no way to reuse it. That will probably come in a later change. As a smaller fix, we pass the invalidate listener directly. The lifetime of this is the same as the computer, so we don't create a new one each time. There's still the potential to leak memory if people break/replace a computer (as listeners aren't removed), but that's an unavoidable flaw with capabilities. Fixes #593 --- .../computercraft/shared/Peripherals.java | 2 +- .../computer/blocks/TileComputerBase.java | 13 ++++++++++++- .../generic/GenericPeripheralProvider.java | 19 +++++++++++++------ 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index cc61e4451..1d93147b4 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -67,7 +67,7 @@ public final class Peripherals } } - return CapabilityUtil.unwrap( GenericPeripheralProvider.getPeripheral( world, pos, side ), invalidate ); + return GenericPeripheralProvider.getPeripheral( world, pos, side, invalidate ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index b384810b9..e904e02f4 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -39,6 +39,8 @@ import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullConsumer; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -56,6 +58,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT private boolean m_on = false; boolean m_startOn = false; private boolean m_fresh = false; + private final NonNullConsumer>[] invalidate; private final ComputerFamily family; @@ -63,6 +66,14 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { super( type ); this.family = family; + + // We cache these so we can guarantee we only ever register one listener for adjacent capabilities. + @SuppressWarnings( { "unchecked", "rawtypes" } ) + NonNullConsumer>[] invalidate = this.invalidate = new NonNullConsumer[6]; + for( Direction direction : Direction.values() ) + { + invalidate[direction.ordinal()] = o -> updateInput( direction ); + } } protected void unload() @@ -225,7 +236,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) ); if( !isPeripheralBlockedOnSide( localDir ) ) { - IPeripheral peripheral = Peripherals.getPeripheral( getWorld(), offset, offsetSide, o -> updateInput( dir ) ); + IPeripheral peripheral = Peripherals.getPeripheral( getWorld(), offset, offsetSide, invalidate[dir.ordinal()] ); computer.setPeripheral( localDir, peripheral ); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index 149179b84..260f8d781 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -15,11 +15,13 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.common.util.NonNullConsumer; import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.items.CapabilityItemHandler; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; @@ -31,14 +33,13 @@ public class GenericPeripheralProvider CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, }; - @Nonnull - public static LazyOptional getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) + @Nullable + public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer> invalidate ) { TileEntity tile = world.getTileEntity( pos ); - if( tile == null ) return LazyOptional.empty(); + if( tile == null ) return null; ArrayList saturated = new ArrayList<>( 0 ); - LazyOptional peripheral = LazyOptional.of( () -> new GenericPeripheral( tile, saturated ) ); List> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() ); if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods ); @@ -51,11 +52,11 @@ public class GenericPeripheralProvider if( capabilityMethods.isEmpty() ) return; addSaturated( saturated, contents, capabilityMethods ); - wrapper.addListener( x -> peripheral.invalidate() ); + wrapper.addListener( cast( invalidate ) ); } ); } - return saturated.isEmpty() ? LazyOptional.empty() : peripheral; + return saturated.isEmpty() ? null : new GenericPeripheral( tile, saturated ); } private static void addSaturated( ArrayList saturated, Object target, List> methods ) @@ -66,4 +67,10 @@ public class GenericPeripheralProvider saturated.add( new SaturatedMethod( target, method ) ); } } + + @SuppressWarnings( { "unchecked", "rawtypes" } ) + private static NonNullConsumer cast( NonNullConsumer consumer ) + { + return (NonNullConsumer) consumer; + } } From ea3a16036794357c3a44edffc90fdb652e03881e Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 10 Dec 2020 19:05:31 +0000 Subject: [PATCH 385/711] Remove a couple of todos --- .../computercraft/client/proxy/ComputerCraftProxyClient.java | 1 - .../computercraft/client/render/MonitorTextureBufferShader.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index 70147c4c6..c8c8374c9 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -47,7 +47,6 @@ public final class ComputerCraftProxyClient ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.MONITOR_ADVANCED.get(), TileEntityMonitorRenderer::new ); ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_NORMAL.get(), TileEntityTurtleRenderer::new ); ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.TURTLE_ADVANCED.get(), TileEntityTurtleRenderer::new ); - // TODO: ClientRegistry.bindTileEntityRenderer( TileCable.FACTORY, x -> new TileEntityCableRenderer() ); RenderingRegistry.registerEntityRenderingHandler( Registry.ModEntities.TURTLE_PLAYER.get(), TurtlePlayerRenderer::new ); } diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index 483957a31..570761186 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -50,7 +50,6 @@ class MonitorTextureBufferShader RenderSystem.glUniform1i( uniformWidth, width ); RenderSystem.glUniform1i( uniformHeight, height ); - // TODO: Cache this? Maybe?? PALETTE_BUFFER.rewind(); for( int i = 0; i < 16; i++ ) { From bb8f4c624bf87169b73fb631d8250cfc38181e15 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 10 Dec 2020 19:13:49 +0000 Subject: [PATCH 386/711] Some sanity checks for get{Direction,Orientation} Silly bodge, but should fix #600. --- .../shared/peripheral/monitor/TileMonitor.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index e9ba5e304..7e9193d91 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -14,6 +14,7 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.util.CapabilityUtil; import dan200.computercraft.shared.util.TickScheduler; +import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; @@ -325,12 +326,16 @@ public class TileMonitor extends TileGeneric // region Sizing and placement stuff public Direction getDirection() { - return getBlockState().get( BlockMonitor.FACING ); + // Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's + // fun problems with the block being missing on the client. + BlockState state = getBlockState(); + return state.has( BlockMonitor.FACING ) ? state.get( BlockMonitor.FACING ) : Direction.NORTH; } public Direction getOrientation() { - return getBlockState().get( BlockMonitor.ORIENTATION ); + BlockState state = getBlockState(); + return state.has( BlockMonitor.ORIENTATION ) ? state.get( BlockMonitor.ORIENTATION ) : Direction.NORTH; } public Direction getFront() From 05c3c8ad3269c9025757f9261e7f609889fb6bdc Mon Sep 17 00:00:00 2001 From: SquidDev Date: Thu, 10 Dec 2020 22:16:49 +0000 Subject: [PATCH 387/711] Generate docs for generic peripherals This was the easy bit. Now I've got to write them! --- build.gradle | 3 ++- illuaminate.sexp | 7 ++++++- .../shared/peripheral/generic/methods/EnergyMethods.java | 5 +++++ .../shared/peripheral/generic/methods/FluidMethods.java | 5 +++++ .../peripheral/generic/methods/InventoryMethods.java | 5 +++++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index e19ddfc25..3ca948a14 100644 --- a/build.gradle +++ b/build.gradle @@ -123,7 +123,7 @@ dependencies { deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" - cctJavadoc 'cc.tweaked:cct-javadoc:1.2.1' + cctJavadoc 'cc.tweaked:cct-javadoc:1.3.0' } // Compile tasks @@ -346,6 +346,7 @@ task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) { inputs.files(fileTree("doc")).withPropertyName("docs") inputs.files(fileTree("src/main/resources/data/computercraft/lua/rom")).withPropertyName("lua rom") inputs.file("illuaminate.sexp").withPropertyName("illuaminate.sexp") + inputs.dir("$buildDir/docs/luaJavadoc") inputs.file("$buildDir/rollup/index.min.js").withPropertyName("scripts") inputs.file("src/web/styles.css").withPropertyName("styles") outputs.dir("$buildDir/docs/lua") diff --git a/illuaminate.sexp b/illuaminate.sexp index 6bf2d2688..d020482f9 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -19,7 +19,8 @@ (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) (module-kinds - (peripheral Peripherals)) + (peripheral Peripherals) + (generic_peripheral "Generic Peripherals")) (library-path /doc/stub/ @@ -91,6 +92,10 @@ /build/docs/luaJavadoc/drive.lua /build/docs/luaJavadoc/speaker.lua /build/docs/luaJavadoc/printer.lua + ; Generic peripherals + /build/docs/luaJavadoc/energy_storage.lua + /build/docs/luaJavadoc/fluid_storage.lua + /build/docs/luaJavadoc/inventory.lua ; Lua APIs /src/main/resources/*/computercraft/lua/rom/apis/io.lua /src/main/resources/*/computercraft/lua/rom/apis/window.lua) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java index 1123318d3..6d0d705ff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java @@ -15,6 +15,11 @@ import net.minecraftforge.versions.forge.ForgeVersion; import javax.annotation.Nonnull; +/** + * Methods for interacting with blocks using Forge's energy storage system. + * + * @cc.module energy_storage + */ @AutoService( GenericSource.class ) public class EnergyMethods implements GenericSource { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java index 26b631f68..1dfe5a2a0 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -31,6 +31,11 @@ import java.util.Optional; import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHelpers.getRegistryEntry; +/** + * Methods for interacting with tanks and other fluid storage blocks. + * + * @cc.module fluid_storage + */ @AutoService( GenericSource.class ) public class FluidMethods implements GenericSource { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 405532b0b..e2e5269c9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -32,6 +32,11 @@ import java.util.Optional; import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHelpers.assertBetween; +/** + * Methods for interacting with inventories. + * + * @cc.module inventory + */ @AutoService( GenericSource.class ) public class InventoryMethods implements GenericSource { From c92f06cfd9f5aefc88e61edcdb18cce3b4998423 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 11 Dec 2020 13:08:24 +0000 Subject: [PATCH 388/711] Bump deps to 1.16.4 --- build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index c20648492..19583cd7a 100644 --- a/build.gradle +++ b/build.gradle @@ -106,10 +106,10 @@ dependencies { minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}" - compileOnly fg.deobf("mezz.jei:jei-1.16.3:7.6.0.49:api") - compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.16.3:7.0.0.48") + compileOnly fg.deobf("mezz.jei:jei-1.16.4:7.6.0.58:api") + compileOnly fg.deobf("com.blamejared.crafttweaker:CraftTweaker-1.16.4:7.0.0.63") - runtimeOnly fg.deobf("mezz.jei:jei-1.16.3:7.6.0.49") + runtimeOnly fg.deobf("mezz.jei:jei-1.16.4:7.6.0.58") compileOnly 'com.google.auto.service:auto-service:1.0-rc7' annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7' From 61f8e97f6b43710c9b25ad56f421d02f0f54a111 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 11 Dec 2020 13:08:45 +0000 Subject: [PATCH 389/711] Force the monitor depth blocker to be flushed As explained in the comment, "built-in" rendering types are now manually rendered ("finish"ed) before calling finish() on the main renderer. This means our depth blocker hasn't actually been drawn (if a monitor is the last TE to be rendered), and so blocks pass the depth test when they shouldn't. Fixes #599 --- .../client/render/TileEntityMonitorRenderer.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 23edc49c7..6e27ab714 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -17,10 +17,7 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.peripheral.monitor.TileMonitor; import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.DirectionUtil; -import net.minecraft.client.renderer.BufferBuilder; -import net.minecraft.client.renderer.GLAllocation; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.*; import net.minecraft.client.renderer.tileentity.TileEntityRenderer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; @@ -147,6 +144,10 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2) ); + // Force a flush of the blocker. WorldRenderer.updateCameraAndRender will "finish" all the built-in + // buffers before calling renderer.finish, which means the blocker isn't actually rendered at that point! + renderer.getBuffer( RenderType.getSolid() ); + transform.pop(); } From 85cf2d5ff1b63010de4661301801aa504e5b9015 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 11 Dec 2020 21:26:36 +0000 Subject: [PATCH 390/711] Docs for energy and inventory methods The inventory transfer methods really need a proper tutorial with screenshots and everything else, but this is a good starting point, I guess. --- illuaminate.sexp | 2 - .../generic/methods/EnergyMethods.java | 17 ++++ .../generic/methods/InventoryMethods.java | 79 ++++++++++++++++++- 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/illuaminate.sexp b/illuaminate.sexp index d020482f9..3922ec02b 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -93,9 +93,7 @@ /build/docs/luaJavadoc/speaker.lua /build/docs/luaJavadoc/printer.lua ; Generic peripherals - /build/docs/luaJavadoc/energy_storage.lua /build/docs/luaJavadoc/fluid_storage.lua - /build/docs/luaJavadoc/inventory.lua ; Lua APIs /src/main/resources/*/computercraft/lua/rom/apis/io.lua /src/main/resources/*/computercraft/lua/rom/apis/window.lua) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java index 6d0d705ff..5df9a7993 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java @@ -18,6 +18,13 @@ import javax.annotation.Nonnull; /** * Methods for interacting with blocks using Forge's energy storage system. * + * This works with energy storage blocks, as well as generators and machines which consume energy. + * + *
+ * Note: Due to limitations with Forge's energy API, it is not possible to measure throughput (i.e. RF + * used/generated per tick). + *
+ * * @cc.module energy_storage */ @AutoService( GenericSource.class ) @@ -30,12 +37,22 @@ public class EnergyMethods implements GenericSource return new ResourceLocation( ForgeVersion.MOD_ID, "energy" ); } + /** + * Get the energy of this block. + * + * @return The energy stored in this block, in FE. + */ @LuaFunction( mainThread = true ) public static int getEnergy( IEnergyStorage energy ) { return energy.getEnergyStored(); } + /** + * Get the maximum amount of energy this block can store. + * + * @return The energy capacity of this block. + */ @LuaFunction( mainThread = true ) public static int getEnergyCapacity( IEnergyStorage energy ) { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index e2e5269c9..4c4864386 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -47,12 +47,30 @@ public class InventoryMethods implements GenericSource return new ResourceLocation( ForgeVersion.MOD_ID, "inventory" ); } + /** + * Get the size of this inventory. + * + * @return The number of slots in this inventory. + */ @LuaFunction( mainThread = true ) public static int size( IItemHandler inventory ) { return inventory.getSlots(); } + /** + * List all items in this inventory. This returns a table, with an entry for each slot. + * + * Each item in the inventory is represented by a table containing some basic information, much like + * {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched + * with {@link #getItemDetail}. + * + * The table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` rather than + * `ipairs`. + * + * @return All items in this inventory. + * @cc.treturn { (table|nil)... } All items in this inventory. + */ @LuaFunction( mainThread = true ) public static Map> list( IItemHandler inventory ) { @@ -67,6 +85,15 @@ public class InventoryMethods implements GenericSource return result; } + /** + * Get detailed information about an item. + * + * @param slot The slot to get information about. + * @return Information about the item in this slot, or {@code nil} if not present. + * @throws LuaException If the slot is out of range. + * @cc.treturn table Information about the item in this slot, or {@code nil} if not present. + */ + @Nullable @LuaFunction( mainThread = true ) public static Map getItemDetail( IItemHandler inventory, int slot ) throws LuaException { @@ -76,6 +103,30 @@ public class InventoryMethods implements GenericSource return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack ); } + /** + * Push items from one inventory to another connected one. + * + * This allows you to push an item in an inventory to another inventory on the same wired network. Both + * inventories must attached to wired modems which are connected via a cable. + * + * @param toName The name of the peripheral/inventory to push to. This is the string given to @{peripheral.wrap}, + * and displayed by the wired modem. + * @param fromSlot The slot in the current inventory to move items to. + * @param limit The maximum number of items to move. Defaults to the current stack limit. + * @param toSlot The slot in the target inventory to move to. If not given, the item will be inserted into any slot. + * @return The number of transferred items. + * @throws LuaException If the peripheral to transfer to doesn't exist or isn't an inventory. + * @throws LuaException If either source or destination slot is out of range. + * + * @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral. + * @cc.usage Wrap two chests, and push an item from one to another. + *
{@code
+     * local chest_a = peripheral.wrap("minecraft:chest_0")
+     * local chest_b = peripheral.wrap("minecraft:chest_0")
+     *
+     * chest_a.pushItems(peripheral.getName(chest_b), 1)
+     * }
+ */ @LuaFunction( mainThread = true ) public static int pushItems( IItemHandler from, IComputerAccess computer, @@ -91,13 +142,37 @@ public class InventoryMethods implements GenericSource // Validate slots int actualLimit = limit.orElse( Integer.MAX_VALUE ); - if( actualLimit <= 0 ) throw new LuaException( "Limit must be > 0" ); assertBetween( fromSlot, 1, from.getSlots(), "From slot out of range (%s)" ); if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.getSlots(), "To slot out of range (%s)" ); + if( actualLimit <= 0 ) return 0; return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit ); } + /** + * Pull items from a connected inventory into this one. + * + * This allows you to transfer items between inventories on the same wired network. Both this and the source + * inventory must attached to wired modems which are connected via a cable. + * + * @param fromName The name of the peripheral/inventory to pull from. This is the string given to @{peripheral.wrap}, + * and displayed by the wired modem. + * @param fromSlot The slot in the source inventory to move items from. + * @param limit The maximum number of items to move. Defaults to the current stack limit. + * @param toSlot The slot in current inventory to move to. If not given, the item will be inserted into any slot. + * @return The number of transferred items. + * @throws LuaException If the peripheral to transfer to doesn't exist or isn't an inventory. + * @throws LuaException If either source or destination slot is out of range. + * + * @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral. + * @cc.usage Wrap two chests, and push an item from one to another. + *
{@code
+     * local chest_a = peripheral.wrap("minecraft:chest_0")
+     * local chest_b = peripheral.wrap("minecraft:chest_0")
+     *
+     * chest_a.pullItems(peripheral.getName(chest_b), 1)
+     * }
+ */ @LuaFunction( mainThread = true ) public static int pullItems( IItemHandler to, IComputerAccess computer, @@ -113,10 +188,10 @@ public class InventoryMethods implements GenericSource // Validate slots int actualLimit = limit.orElse( Integer.MAX_VALUE ); - if( actualLimit <= 0 ) throw new LuaException( "Limit must be > 0" ); assertBetween( fromSlot, 1, from.getSlots(), "From slot out of range (%s)" ); if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.getSlots(), "To slot out of range (%s)" ); + if( actualLimit <= 0 ) return 0; return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit ); } From 5865e9c41a0140b9f1acdd2fb095353c467fbb45 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Fri, 11 Dec 2020 21:41:29 +0000 Subject: [PATCH 391/711] Not sure what irritates me more The fact that I didn't run checkstyle before pushing or checkstyle itself. I wish this ran fast enough I could put it as a commit hook. --- .../shared/peripheral/generic/methods/EnergyMethods.java | 2 ++ .../peripheral/generic/methods/InventoryMethods.java | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java index 5df9a7993..5eab3f94f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java @@ -40,6 +40,7 @@ public class EnergyMethods implements GenericSource /** * Get the energy of this block. * + * @param energy The current energy storage. * @return The energy stored in this block, in FE. */ @LuaFunction( mainThread = true ) @@ -51,6 +52,7 @@ public class EnergyMethods implements GenericSource /** * Get the maximum amount of energy this block can store. * + * @param energy The current energy storage. * @return The energy capacity of this block. */ @LuaFunction( mainThread = true ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 4c4864386..b8585f425 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -50,6 +50,7 @@ public class InventoryMethods implements GenericSource /** * Get the size of this inventory. * + * @param inventory The current inventory. * @return The number of slots in this inventory. */ @LuaFunction( mainThread = true ) @@ -68,6 +69,7 @@ public class InventoryMethods implements GenericSource * The table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` rather than * `ipairs`. * + * @param inventory The current inventory. * @return All items in this inventory. * @cc.treturn { (table|nil)... } All items in this inventory. */ @@ -88,6 +90,7 @@ public class InventoryMethods implements GenericSource /** * Get detailed information about an item. * + * @param inventory The current inventory. * @param slot The slot to get information about. * @return Information about the item in this slot, or {@code nil} if not present. * @throws LuaException If the slot is out of range. @@ -109,6 +112,8 @@ public class InventoryMethods implements GenericSource * This allows you to push an item in an inventory to another inventory on the same wired network. Both * inventories must attached to wired modems which are connected via a cable. * + * @param from Inventory to move items from. + * @param computer The current computer. * @param toName The name of the peripheral/inventory to push to. This is the string given to @{peripheral.wrap}, * and displayed by the wired modem. * @param fromSlot The slot in the current inventory to move items to. @@ -155,6 +160,8 @@ public class InventoryMethods implements GenericSource * This allows you to transfer items between inventories on the same wired network. Both this and the source * inventory must attached to wired modems which are connected via a cable. * + * @param to Inventory to move items to. + * @param computer The current computer. * @param fromName The name of the peripheral/inventory to pull from. This is the string given to @{peripheral.wrap}, * and displayed by the wired modem. * @param fromSlot The slot in the source inventory to move items from. From b97e950d86e4694409c01e507db34a87da85e452 Mon Sep 17 00:00:00 2001 From: TheWireLord Date: Sat, 12 Dec 2020 16:45:02 -0500 Subject: [PATCH 392/711] Added Numpad Enter Support - bios.lua Add the ability to use Numpad Enter and have it act just like normal Enter. (Just like the web-based emulator on the Tweaked.cc wiki) --- src/main/resources/data/computercraft/lua/bios.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/bios.lua b/src/main/resources/data/computercraft/lua/bios.lua index 4407dc99e..f0c364994 100644 --- a/src/main/resources/data/computercraft/lua/bios.lua +++ b/src/main/resources/data/computercraft/lua/bios.lua @@ -338,8 +338,8 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault) redraw() elseif sEvent == "key" then - if param == keys.enter then - -- Enter + if param == keys.enter or param == keys.numPadEnter then + -- Enter/Numpad Enter if nCompletion then clear() uncomplete() From f5eb6ce03e0d9bbbf77130452afd4b49e758f7bd Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 15 Dec 2020 09:31:12 +0000 Subject: [PATCH 393/711] Fix copy-paste error in inventory docs I'm a very silly squid. --- .../shared/peripheral/generic/methods/InventoryMethods.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index b8585f425..c8a1c0749 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -127,7 +127,7 @@ public class InventoryMethods implements GenericSource * @cc.usage Wrap two chests, and push an item from one to another. *
{@code
      * local chest_a = peripheral.wrap("minecraft:chest_0")
-     * local chest_b = peripheral.wrap("minecraft:chest_0")
+     * local chest_b = peripheral.wrap("minecraft:chest_1")
      *
      * chest_a.pushItems(peripheral.getName(chest_b), 1)
      * }
@@ -175,7 +175,7 @@ public class InventoryMethods implements GenericSource * @cc.usage Wrap two chests, and push an item from one to another. *
{@code
      * local chest_a = peripheral.wrap("minecraft:chest_0")
-     * local chest_b = peripheral.wrap("minecraft:chest_0")
+     * local chest_b = peripheral.wrap("minecraft:chest_1")
      *
      * chest_a.pullItems(peripheral.getName(chest_b), 1)
      * }
From 663859d2e5a97edefebf9ac36206903d7dd33a3e Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 20 Dec 2020 19:57:31 +0000 Subject: [PATCH 394/711] Fix double URL decode Closes #613 --- .../core/apis/http/request/HttpRequestHandler.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index fbd102be6..bebfdbea2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -21,10 +21,8 @@ import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import java.io.Closeable; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLDecoder; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.HashMap; @@ -244,9 +242,9 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler Date: Wed, 23 Dec 2020 12:33:47 +0000 Subject: [PATCH 395/711] Fix overflow in os.epoch Closes #611 --- src/main/java/dan200/computercraft/core/apis/OSAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index b0752cdaa..f43d09539 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -412,7 +412,7 @@ public class OSAPI implements ILuaAPI // Get in-game epoch synchronized( m_alarms ) { - return m_day * 86400000 + (int) (m_time * 3600000.0f); + return m_day * 86400000L + (long) (m_time * 3600000.0); } default: throw new LuaException( "Unsupported operation" ); From e3a672099c1b5d2c06f9fe4d8ccd024fef0873a2 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 23 Dec 2020 15:46:27 +0000 Subject: [PATCH 396/711] Fix JEI integration with turtle/pocket upgrades - Remove incorrect impostor recipes for pocket computers. We were generating them from the list of turtle upgrades instead! - Fix JEI plugin not blocking impostor recipes as of the data-generator rewrite. --- .../minecraft/crafting_table.json | 35 ------------------- .../minecraft/diamond_axe.json | 35 ------------------- .../minecraft/diamond_hoe.json | 35 ------------------- .../minecraft/diamond_pickaxe.json | 35 ------------------- .../minecraft/diamond_shovel.json | 35 ------------------- .../minecraft/diamond_sword.json | 35 ------------------- .../minecraft/crafting_table.json | 35 ------------------- .../pocket_normal/minecraft/diamond_axe.json | 35 ------------------- .../pocket_normal/minecraft/diamond_hoe.json | 35 ------------------- .../minecraft/diamond_pickaxe.json | 35 ------------------- .../minecraft/diamond_shovel.json | 35 ------------------- .../minecraft/diamond_sword.json | 35 ------------------- .../minecraft/crafting_table.json | 19 ---------- .../minecraft/diamond_axe.json | 19 ---------- .../minecraft/diamond_hoe.json | 19 ---------- .../minecraft/diamond_pickaxe.json | 19 ---------- .../minecraft/diamond_shovel.json | 19 ---------- .../minecraft/diamond_sword.json | 19 ---------- .../minecraft/crafting_table.json | 19 ---------- .../pocket_normal/minecraft/diamond_axe.json | 19 ---------- .../pocket_normal/minecraft/diamond_hoe.json | 19 ---------- .../minecraft/diamond_pickaxe.json | 19 ---------- .../minecraft/diamond_shovel.json | 19 ---------- .../minecraft/diamond_sword.json | 19 ---------- .../dan200/computercraft/data/Recipes.java | 3 +- .../integration/jei/JEIComputerCraft.java | 7 ++-- 26 files changed, 7 insertions(+), 651 deletions(-) delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json delete mode 100644 src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json delete mode 100644 src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json deleted file mode 100644 index 112ba7081..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/crafting_table.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/crafting_table" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:crafting_table" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/crafting_table" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json deleted file mode 100644 index 7b5c315e4..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_axe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_axe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_axe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_axe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json deleted file mode 100644 index 9f5872d9f..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_hoe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_hoe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_hoe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_hoe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json deleted file mode 100644 index 7e1930b03..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_pickaxe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_pickaxe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_pickaxe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json deleted file mode 100644 index 05222ce97..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_shovel.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_shovel" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_shovel" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_shovel" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json deleted file mode 100644 index 413e0375d..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_advanced/minecraft/diamond_sword.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_advanced/minecraft/diamond_sword" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_advanced" - }, - { - "item": "minecraft:diamond_sword" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_advanced/minecraft/diamond_sword" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json deleted file mode 100644 index c507d2563..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/crafting_table.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/crafting_table" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:crafting_table" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/crafting_table" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json deleted file mode 100644 index a14901a3e..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_axe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_axe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_axe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_axe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json deleted file mode 100644 index 5dba7dcd6..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_hoe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_hoe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_hoe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_hoe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json deleted file mode 100644 index 06a10b8ec..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_pickaxe" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_pickaxe" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_pickaxe" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json deleted file mode 100644 index 22ccd7e60..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_shovel.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_shovel" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_shovel" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_shovel" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json deleted file mode 100644 index 74378a20c..000000000 --- a/src/generated/resources/data/computercraft/advancements/recipes/computercraft/pocket_normal/minecraft/diamond_sword.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "parent": "minecraft:recipes/root", - "rewards": { - "recipes": [ - "computercraft:pocket_normal/minecraft/diamond_sword" - ] - }, - "criteria": { - "has_items": { - "trigger": "minecraft:inventory_changed", - "conditions": { - "items": [ - { - "item": "computercraft:pocket_computer_normal" - }, - { - "item": "minecraft:diamond_sword" - } - ] - } - }, - "has_the_recipe": { - "trigger": "minecraft:recipe_unlocked", - "conditions": { - "recipe": "computercraft:pocket_normal/minecraft/diamond_sword" - } - } - }, - "requirements": [ - [ - "has_items", - "has_the_recipe" - ] - ] -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json deleted file mode 100644 index 0cd065680..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/crafting_table.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "minecraft:crafting_table" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json deleted file mode 100644 index 7b8fa8a24..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_axe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "minecraft:diamond_axe" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json deleted file mode 100644 index 9514a59cd..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_hoe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "minecraft:diamond_hoe" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json deleted file mode 100644 index e28008623..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "minecraft:diamond_pickaxe" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json deleted file mode 100644 index b0ddf3016..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_shovel.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "minecraft:diamond_shovel" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json deleted file mode 100644 index cea0b2a0f..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_advanced/minecraft/diamond_sword.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_advanced", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_advanced" - }, - "P": { - "item": "minecraft:diamond_sword" - } - }, - "result": { - "item": "computercraft:pocket_computer_advanced" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json deleted file mode 100644 index dc1ddd884..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/crafting_table.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "minecraft:crafting_table" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json deleted file mode 100644 index 686d9d890..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_axe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "minecraft:diamond_axe" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json deleted file mode 100644 index 905a2640a..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_hoe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "minecraft:diamond_hoe" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json deleted file mode 100644 index 200d15862..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_pickaxe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "minecraft:diamond_pickaxe" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json deleted file mode 100644 index fcae256c7..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_shovel.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "minecraft:diamond_shovel" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} \ No newline at end of file diff --git a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json b/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json deleted file mode 100644 index 564dbf7e5..000000000 --- a/src/generated/resources/data/computercraft/recipes/pocket_normal/minecraft/diamond_sword.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "type": "computercraft:impostor_shaped", - "group": "computercraft:pocket_normal", - "pattern": [ - "#", - "P" - ], - "key": { - "#": { - "item": "computercraft:pocket_computer_normal" - }, - "P": { - "item": "minecraft:diamond_sword" - } - }, - "result": { - "item": "computercraft:pocket_computer_normal" - } -} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java index a86ac212e..d7dc75d78 100644 --- a/src/main/java/dan200/computercraft/data/Recipes.java +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -8,6 +8,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; import dan200.computercraft.data.Tags.CCTags; +import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -117,7 +118,7 @@ public class Recipes extends RecipeProvider String nameId = family.name().toLowerCase( Locale.ROOT ); - TurtleUpgrades.getVanillaUpgrades().forEach( upgrade -> { + PocketUpgrades.getVanillaUpgrades().forEach( upgrade -> { ItemStack result = PocketComputerItemFactory.create( -1, null, -1, family, null ); ShapedRecipeBuilder .shapedRecipe( result.getItem() ) diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index c7d99cebb..45e0e380b 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -97,8 +97,11 @@ public class JEIComputerCraft implements IModPlugin { if( !(wrapper instanceof IRecipe) ) continue; ResourceLocation id = ((IRecipe) wrapper).getId(); - if( id.getNamespace().equals( ComputerCraft.MOD_ID ) - && (id.getPath().startsWith( "generated/turtle_" ) || id.getPath().startsWith( "generated/pocket_" )) ) + if( !id.getNamespace().equals( ComputerCraft.MOD_ID ) ) continue; + + String path = id.getPath(); + if( path.startsWith( "turtle_normal/" ) || path.startsWith( "turtle_advanced/" ) + || path.startsWith( "pocket_normal/" ) || path.startsWith( "pocket_advanced/" ) ) { registry.hideRecipe( wrapper, VanillaRecipeCategoryUid.CRAFTING ); } From 2f0cae0bc1b038ac092bafa7f65a317537203cd8 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 23 Dec 2020 15:52:33 +0000 Subject: [PATCH 397/711] Make upgrade recipe requirements a little more lax - Move some common upgrade code to IUpgradeBase. 99% sure this this preserves binary compatibility (on the JVM at least). - Instead of requiring the share tag to match, allow upgrades to specify their own predicate. IMO this is a little ugly, but required to fix #614 as other mods chuck their own NBT on items. --- .../computercraft/api/IUpgradeBase.java | 81 +++++++++++++++++++ .../api/pocket/IPocketUpgrade.java | 47 +---------- .../api/turtle/ITurtleUpgrade.java | 38 +-------- .../computercraft/shared/PocketUpgrades.java | 3 +- .../computercraft/shared/TurtleUpgrades.java | 3 +- .../integration/jei/RecipeResolver.java | 37 +++------ .../shared/turtle/upgrades/TurtleTool.java | 20 +++++ .../shared/util/InventoryUtil.java | 30 ------- 8 files changed, 121 insertions(+), 138 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/IUpgradeBase.java diff --git a/src/main/java/dan200/computercraft/api/IUpgradeBase.java b/src/main/java/dan200/computercraft/api/IUpgradeBase.java new file mode 100644 index 000000000..03a90571e --- /dev/null +++ b/src/main/java/dan200/computercraft/api/IUpgradeBase.java @@ -0,0 +1,81 @@ +package dan200.computercraft.api; + +import dan200.computercraft.api.pocket.IPocketUpgrade; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.ResourceLocation; + +import javax.annotation.Nonnull; + +/** + * Common functionality between {@link ITurtleUpgrade} and {@link IPocketUpgrade}. + */ +public interface IUpgradeBase +{ + /** + * Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" + * or "my_mod:my_upgrade". + * + * You should use a unique resource domain to ensure this upgrade is uniquely identified. + * The upgrade will fail registration if an already used ID is specified. + * + * @return The unique ID for this upgrade. + */ + @Nonnull + ResourceLocation getUpgradeID(); + + /** + * Return an unlocalised string to describe this type of computer in item names. + * + * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". + * + * @return The localisation key for this upgrade's adjective. + */ + @Nonnull + String getUnlocalisedAdjective(); + + /** + * Return an item stack representing the type of item that a computer must be crafted + * with to create a version which holds this upgrade. This item stack is also used + * to determine the upgrade given by {@code turtle.equipLeft()} or {@code pocket.equipBack()} + * + * This should be constant over a session (or at least a datapack reload). It is recommended + * that you cache the stack too, in order to prevent constructing it every time the method + * is called. + * + * @return The item stack to craft with, or {@link ItemStack#EMPTY} if it cannot be crafted. + */ + @Nonnull + ItemStack getCraftingItem(); + + /** + * Determine if an item is suitable for being used for this upgrade. + * + * When un-equipping an upgrade, we return {@link #getCraftingItem()} rather than + * the original stack. In order to prevent people losing items with enchantments (or + * repairing items with non-0 damage), we impose additional checks on the item. + * + * The default check requires that any non-capability NBT is exactly the same as the + * crafting item, but this may be relaxed for your upgrade. + * + * @param stack The stack to check. This is guaranteed to be non-empty and have the same item as + * {@link #getCraftingItem()}. + * @return If this stack may be used to equip this upgrade. + * @see net.minecraftforge.common.crafting.NBTIngredient#test(ItemStack) For the implementation of the default + * check. + */ + default boolean isItemSuitable( @Nonnull ItemStack stack ) + { + ItemStack crafting = getCraftingItem(); + + // A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a + // null one. + CompoundNBT shareTag = stack.getItem().getShareTag( stack ); + CompoundNBT craftingShareTag = crafting.getItem().getShareTag( crafting ); + if( shareTag == craftingShareTag ) return true; + if( shareTag == null ) return craftingShareTag.isEmpty(); + if( craftingShareTag == null ) return shareTag.isEmpty(); + return shareTag.equals( craftingShareTag ); + } +} diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index 638f95cc7..c0b761ef2 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -6,10 +6,8 @@ package dan200.computercraft.api.pocket; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.peripheral.IPeripheral; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import javax.annotation.Nonnull; @@ -18,49 +16,10 @@ import javax.annotation.Nullable; /** * Additional peripherals for pocket computers. * - * This is similar to {@link ITurtleUpgrade}. + * @see ComputerCraftAPI#registerPocketUpgrade(IPocketUpgrade) */ -public interface IPocketUpgrade +public interface IPocketUpgrade extends IUpgradeBase { - - /** - * Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" or - * "my_mod:my_upgrade". - * - * You should use a unique resource domain to ensure this upgrade is uniquely identified. The upgrade will fail - * registration if an already used ID is specified. - * - * @return The upgrade's id. - * @see IPocketUpgrade#getUpgradeID() - * @see ComputerCraftAPI#registerPocketUpgrade(IPocketUpgrade) - */ - @Nonnull - ResourceLocation getUpgradeID(); - - /** - * Return an unlocalised string to describe the type of pocket computer this upgrade provides. - * - * An example of a built-in adjectives is "Wireless" - this is converted to "Wireless Pocket Computer". - * - * @return The unlocalised adjective. - * @see ITurtleUpgrade#getUnlocalisedAdjective() - */ - @Nonnull - String getUnlocalisedAdjective(); - - /** - * Return an item stack representing the type of item that a pocket computer must be crafted with to create a - * pocket computer which holds this upgrade. This item stack is also used to determine the upgrade given by - * {@code pocket.equip()}/{@code pocket.unequip()}. - * - * Ideally this should be constant over a session. It is recommended that you cache - * the item too, in order to prevent constructing it every time the method is called. - * - * @return The item stack used for crafting. This can be {@link ItemStack#EMPTY} if crafting is disabled. - */ - @Nonnull - ItemStack getCraftingItem(); - /** * Creates a peripheral for the pocket computer. * diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 70d80e38c..76e53919e 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -6,6 +6,7 @@ package dan200.computercraft.api.turtle; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.client.TransformedModel; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.turtle.event.TurtleAttackEvent; @@ -13,7 +14,6 @@ import dan200.computercraft.api.turtle.event.TurtleBlockEvent; import net.minecraft.client.renderer.model.ModelResourceLocation; import net.minecraft.item.ItemStack; import net.minecraft.util.Direction; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.entity.player.AttackEntityEvent; @@ -28,29 +28,8 @@ import javax.annotation.Nullable; * * @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade) */ -public interface ITurtleUpgrade +public interface ITurtleUpgrade extends IUpgradeBase { - /** - * Gets a unique identifier representing this type of turtle upgrade. eg: "computercraft:wireless_modem" or "my_mod:my_upgrade". - * You should use a unique resource domain to ensure this upgrade is uniquely identified. - * The turtle will fail registration if an already used ID is specified. - * - * @return The unique ID for this upgrade. - * @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade) - */ - @Nonnull - ResourceLocation getUpgradeID(); - - /** - * Return an unlocalised string to describe this type of turtle in turtle item names. - * - * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". - * - * @return The localisation key for this upgrade's adjective. - */ - @Nonnull - String getUnlocalisedAdjective(); - /** * Return whether this turtle adds a tool or a peripheral to the turtle. * @@ -60,19 +39,6 @@ public interface ITurtleUpgrade @Nonnull TurtleUpgradeType getType(); - /** - * Return an item stack representing the type of item that a turtle must be crafted - * with to create a turtle which holds this upgrade. This item stack is also used - * to determine the upgrade given by {@code turtle.equip()} - * - * Ideally this should be constant over a session. It is recommended that you cache - * the item too, in order to prevent constructing it every time the method is called. - * - * @return The item stack to craft with, or {@link ItemStack#EMPTY} if it cannot be crafted. - */ - @Nonnull - ItemStack getCraftingItem(); - /** * Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade. * diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index f46a87820..58494b618 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.pocket.IPocketUpgrade; -import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; @@ -55,7 +54,7 @@ public final class PocketUpgrades for( IPocketUpgrade upgrade : upgrades.values() ) { ItemStack craftingStack = upgrade.getCraftingItem(); - if( !craftingStack.isEmpty() && InventoryUtil.areItemsSimilar( stack, craftingStack ) ) + if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.isItemSuitable( stack ) ) { return upgrade; } diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index d9e4bc30f..76aa1c8a4 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.util.InventoryUtil; import net.minecraft.item.ItemStack; import net.minecraftforge.fml.ModLoadingContext; @@ -83,7 +82,7 @@ public final class TurtleUpgrades if( !wrapper.enabled ) continue; ItemStack craftingStack = wrapper.upgrade.getCraftingItem(); - if( !craftingStack.isEmpty() && InventoryUtil.areItemsSimilar( stack, craftingStack ) ) + if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && wrapper.upgrade.isItemSuitable( stack ) ) { return wrapper.upgrade; } diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java index 31cae9c9c..fa420f3ea 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.integration.jei; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.IUpgradeBase; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; @@ -16,7 +17,6 @@ import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory; import dan200.computercraft.shared.turtle.items.ITurtleItem; import dan200.computercraft.shared.turtle.items.TurtleItemFactory; -import dan200.computercraft.shared.util.InventoryUtil; import mezz.jei.api.constants.VanillaRecipeCategoryUid; import mezz.jei.api.recipe.IFocus; import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin; @@ -83,7 +83,10 @@ class RecipeResolver implements IRecipeManagerPlugin for( UpgradeInfo upgrade : upgrades ) { ItemStack craftingStack = upgrade.stack; - if( !craftingStack.isEmpty() && InventoryUtil.areItemsSimilar( stack, craftingStack ) ) return true; + if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.upgrade.isItemSuitable( stack ) ) + { + return true; + } } return false; @@ -194,11 +197,10 @@ class RecipeResolver implements IRecipeManagerPlugin List recipes = null; boolean multiple = false; - Ingredient ingredient = fromStacks( stack ); for( UpgradeInfo upgrade : upgrades ) { ItemStack craftingStack = upgrade.stack; - if( craftingStack.isEmpty() || !InventoryUtil.areItemsSimilar( stack, craftingStack ) ) + if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.upgrade.isItemSuitable( stack ) ) { continue; } @@ -332,42 +334,29 @@ class RecipeResolver implements IRecipeManagerPlugin } } - private static final class Upgrade - { - final T upgrade; - final ItemStack stack; - final Ingredient ingredient; - - private Upgrade( T upgrade, ItemStack stack ) - { - this.upgrade = upgrade; - this.stack = stack; - ingredient = fromStacks( stack ); - } - } - private static class UpgradeInfo { final ItemStack stack; final Ingredient ingredient; final ITurtleUpgrade turtle; final IPocketUpgrade pocket; + final IUpgradeBase upgrade; ArrayList recipes; UpgradeInfo( ItemStack stack, ITurtleUpgrade turtle ) { this.stack = stack; - ingredient = fromStacks( stack ); - this.turtle = turtle; - pocket = null; + this.ingredient = fromStacks( stack ); + this.upgrade = this.turtle = turtle; + this.pocket = null; } UpgradeInfo( ItemStack stack, IPocketUpgrade pocket ) { this.stack = stack; - ingredient = fromStacks( stack ); - turtle = null; - this.pocket = pocket; + this.ingredient = fromStacks( stack ); + this.turtle = null; + this.upgrade = this.pocket = pocket; } List getRecipes() diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index f76e7b377..04505670e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -28,6 +28,7 @@ import net.minecraft.entity.item.ArmorStandEntity; import net.minecraft.fluid.IFluidState; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; @@ -38,6 +39,7 @@ import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.Constants; import net.minecraftforge.event.entity.player.AttackEntityEvent; import net.minecraftforge.event.world.BlockEvent; import org.apache.commons.lang3.tuple.Pair; @@ -68,6 +70,24 @@ public class TurtleTool extends AbstractTurtleUpgrade this.item = toolItem; } + @Override + public boolean isItemSuitable( @Nonnull ItemStack stack ) + { + CompoundNBT tag = stack.getTag(); + if( tag == null || tag.isEmpty() ) return true; + + // Check we've not got anything vaguely interesting on the item. We allow other mods to add their + // own NBT, with the understanding such details will be lost to the mist of time. + if( stack.isDamaged() || stack.isEnchanted() || stack.hasDisplayName() ) return false; + if( tag.contains( "AttributeModifiers", Constants.NBT.TAG_LIST ) && + !tag.getList( "AttributeModifiers", Constants.NBT.TAG_COMPOUND ).isEmpty() ) + { + return false; + } + + return true; + } + @Nonnull @Override @OnlyIn( Dist.CLIENT ) diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 11b8438ec..8f8cff926 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -9,7 +9,6 @@ import net.minecraft.entity.Entity; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -40,35 +39,6 @@ public final class InventoryUtil return a == b || ItemHandlerHelper.canItemStacksStack( a, b ); } - /** - * Determines if two items are "mostly" equivalent. Namely, they have the same item and damage, and identical - * share stacks. - * - * This is largely based on {@link net.minecraftforge.common.crafting.IngredientNBT#test(ItemStack)}. It is - * sufficient to ensure basic information (such as enchantments) are the same, while not having to worry about - * capabilities. - * - * @param a The first stack to check - * @param b The second stack to check - * @return If these items are largely the same. - */ - public static boolean areItemsSimilar( @Nonnull ItemStack a, @Nonnull ItemStack b ) - { - if( a == b ) return true; - if( a.isEmpty() ) return !b.isEmpty(); - - if( a.getItem() != b.getItem() ) return false; - - // A more expanded form of ItemStack.areShareTagsEqual, but allowing an empty tag to be equal to a - // null one. - CompoundNBT shareTagA = a.getItem().getShareTag( a ); - CompoundNBT shareTagB = b.getItem().getShareTag( b ); - if( shareTagA == shareTagB ) return true; - if( shareTagA == null ) return shareTagB.isEmpty(); - if( shareTagB == null ) return shareTagA.isEmpty(); - return shareTagA.equals( shareTagB ); - } - // Methods for finding inventories: public static IItemHandler getInventory( World world, BlockPos pos, Direction side ) From 24bb92007ac83d22b61559d7d499364fa7c54f53 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 23 Dec 2020 15:58:40 +0000 Subject: [PATCH 398/711] Fix licence issues I knew I shouldn't do modding on things which aren't my main computer. I actually did run checkstyleMain before committing, but entirely forgot about this one. Go me. --- src/main/java/dan200/computercraft/api/IUpgradeBase.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/dan200/computercraft/api/IUpgradeBase.java b/src/main/java/dan200/computercraft/api/IUpgradeBase.java index 03a90571e..d3b4a0af1 100644 --- a/src/main/java/dan200/computercraft/api/IUpgradeBase.java +++ b/src/main/java/dan200/computercraft/api/IUpgradeBase.java @@ -1,3 +1,8 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ package dan200.computercraft.api; import dan200.computercraft.api.pocket.IPocketUpgrade; From 16d74dd2e8709b4df35a826ca053b4a3c332f393 Mon Sep 17 00:00:00 2001 From: Lupus590 Date: Wed, 23 Dec 2020 16:19:54 +0000 Subject: [PATCH 399/711] Add functions to wrap text --- .../lua/rom/modules/main/cc/strings.lua | 102 ++++++++++++++++++ .../test-rom/spec/modules/cc/strings_spec.lua | 41 +++++++ 2 files changed, 143 insertions(+) create mode 100644 src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua create mode 100644 src/test/resources/test-rom/spec/modules/cc/strings_spec.lua diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua new file mode 100644 index 000000000..1e6e6efc8 --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua @@ -0,0 +1,102 @@ +--- Various utilities for working with strings and text. +-- +-- @see textutils For additional string related utilities. + +local expect = require "cc.expect".expect + +--- Wraps a block of text, so that each line fits within the given width. +-- +-- This may be useful if you want to wrap text before displaying it to a +-- @{monitor} or @{printer} without using @{_G.print|print}. +-- +-- @tparam string text The string to wrap. +-- @tparam[opt] number width The width to constrain to, defaults to the width of +-- the terminal. +-- +-- @treturn { string... } The wrapped input string. +-- @usage require "cc.strings".wrap("This is a long piece of text", 10) +local function wrap(text, width) + expect(1, text, "string") + expect(2, width, "number", "nil") + width = width or term.getSize() + + + local lines, lines_n, current_line = {}, 0, "" + local function push_line() + lines_n = lines_n + 1 + lines[lines_n] = current_line + current_line = "" + end + + local pos, length = 1, #text + local sub, match = string.sub, string.match + while pos <= length do + local head = sub(text, pos, pos) + if head == " " or head == "\t" then + local whitespace = match(text, "^[ \t]+", pos) + current_line = current_line .. whitespace + pos = pos + #whitespace + elseif head == "\n" then + push_line() + pos = pos + 1 + else + local word = match(text, "^[^ \t\n]+", pos) + pos = pos + #word + if #word > width then + -- Print a multiline word + while #word > 0 do + local space_remaining = width - #current_line - 1 + if space_remaining <= 0 then + push_line() + space_remaining = width + end + + current_line = current_line .. sub(word, 1, space_remaining) + word = sub(word, space_remaining + 1) + end + else + -- Print a word normally + if width - #current_line < #word then push_line() end + current_line = current_line .. word + end + end + end + + push_line() + + -- Trim whitespace longer than width. + for k, line in pairs(lines) do + line = line:sub(1, width) + lines[k] = line + end + + return lines +end + +--- Makes the input string a fixed width. This either truncates it, or pads it +-- with spaces. +-- +-- @tparam string line The string to normalise. +-- @tparam[opt] number width The width to constrain to, defaults to the width of +-- the terminal. +-- +-- @treturn string The string with a specific width. +-- @usage require "cc.strings".ensure_width("a short string", 20) +-- @usage require "cc.strings".ensure_width("a rather long string which is truncated", 20) +local function ensure_width(line, width) + expect(1, line, "string") + expect(2, width, "number", "nil") + width = width or term.getSize() + + line = line:sub(1, width) + if #line < width then + line = line .. (" "):rep(width - #line) + end + + return line +end + +return { + wrap = wrap, + ensure_width = ensure_width, +} diff --git a/src/test/resources/test-rom/spec/modules/cc/strings_spec.lua b/src/test/resources/test-rom/spec/modules/cc/strings_spec.lua new file mode 100644 index 000000000..900c6fe6f --- /dev/null +++ b/src/test/resources/test-rom/spec/modules/cc/strings_spec.lua @@ -0,0 +1,41 @@ +describe("cc.pretty", function() + local str = require("cc.strings") + + describe("wrap", function() + it("validates arguments", function() + str.wrap("test string is long") + str.wrap("test string is long", 11) + expect.error(str.wrap, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(str.wrap, "", false):eq("bad argument #2 (expected number, got boolean)") + end) + + it("wraps lines", function() + expect(str.wrap("test string is long")[1]):eq("test string is long") + + expect(str.wrap("test string is long", 15)[1]):eq("test string is ") + expect(str.wrap("test string is long", 15)[2]):eq("long") + + expect(str.wrap("test string is long", 12)[1]):eq("test string ") + expect(str.wrap("test string is long", 12)[2]):eq("is long") + + expect(str.wrap("test string is long", 11)[1]):eq("test string") + expect(str.wrap("test string is long", 11)[2]):eq("is long") + end) + end) + + describe("ensure_width", function() + it("validates arguments", function() + str.wrap("test string is long") + str.wrap("test string is long", 11) + expect.error(str.ensure_width, nil):eq("bad argument #1 (expected string, got nil)") + expect.error(str.ensure_width, "", false):eq("bad argument #2 (expected number, got boolean)") + end) + + it("pads lines", function() + expect(str.ensure_width("test string is long", 25)):eq("test string is long ") + end) + it("truncates lines", function() + expect(str.ensure_width("test string is long", 15)):eq("test string is ") + end) + end) +end) From ed3913c1f4959da9df31408af92182603672ad77 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 23 Dec 2020 16:33:58 +0000 Subject: [PATCH 400/711] Manually wrap strings for help (#602) This saves us writing to a buffer multiple times, and so makes things much, much faster. --- .../computercraft/lua/rom/programs/help.lua | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/help.lua b/src/main/resources/data/computercraft/lua/rom/programs/help.lua index 149e9f41e..497a6dff7 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/help.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/help.lua @@ -13,6 +13,19 @@ if sTopic == "index" then return end +local strings = require "cc.strings" +local function word_wrap(text, width) + local lines = strings.wrap(text, width) + + -- Normalise the strings suitable for use with blit. We could skip this and + -- just use term.write, but saves us a clearLine call. + for k, line in pairs(lines) do + lines[k] = strings.ensure_width(line, width) + end + + return lines +end + local sFile = help.lookup(sTopic) local file = sFile ~= nil and io.open(sFile) or nil if not file then @@ -24,37 +37,27 @@ local contents = file:read("*a"):gsub("(\n *)[-*]( +)", "%1\7%2") file:close() local width, height = term.getSize() -local buffer = window.create(term.current(), 1, 1, width, height, false) -local old_term = term.redirect(buffer) - -local print_height = print(contents) + 1 +local lines = word_wrap(contents, width) +local print_height = #lines -- If we fit within the screen, just display without pagination. if print_height <= height then - term.redirect(old_term) print(contents) return end -local function draw_buffer(width) - buffer.reposition(1, 1, width, print_height) - buffer.clear() - buffer.setCursorPos(1, 1) - print(contents) - term.redirect(old_term) -end - local offset = 0 local function draw() + local fg, bg = ("0"):rep(width), ("f"):rep(width) for y = 1, height - 1 do term.setCursorPos(1, y) if y + offset > print_height then - -- Should only happen if we resize the terminal to a larger one - -- than actually needed for the current text. + -- Should only happen if we resize the terminal to a larger one + -- than actually needed for the current text. term.clearLine() else - term.blit(buffer.getLine(y + offset)) + term.blit(lines[y + offset], fg, bg) end end end @@ -73,7 +76,6 @@ local function draw_menu() end end -draw_buffer(width) draw() draw_menu() @@ -114,11 +116,8 @@ while true do local new_width, new_height = term.getSize() if new_width ~= width then - buffer.setCursorPos(1, 1) - buffer.reposition(1, 1, new_width, print_height) - term.redirect(buffer) - print_height = print(contents) + 1 - draw_buffer(new_width) + lines = word_wrap(contents, new_width) + print_height = #lines end width, height = new_width, new_height @@ -128,6 +127,5 @@ while true do end end -term.redirect(old_term) term.setCursorPos(1, 1) term.clear() From 7f9a707f75636d5816f752dc93d7b6b998c61a03 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 25 Dec 2020 16:40:50 +0000 Subject: [PATCH 401/711] Bump version to 1.95.0 As is tradition. --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 22 ++++++++++++++++ .../computercraft/lua/rom/help/whatsnew.txt | 26 +++++++++++++------ 3 files changed, 41 insertions(+), 9 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5c6f6ea2b..147cc11de 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.94.0 +mod_version=1.95.0 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index b173cbceb..52789f9d8 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,25 @@ +# New features in CC: Tweaked 1.95.0 + +* Optimise the paint program's initial render. +* Several documentation improvments (Gibbo3771, MCJack123). +* `fs.combine` now accepts multiple arguments. +* Add a setting (`bios.strict_globals`) to error when accidentally declaring a global. (Lupus590). +* Add an improved help viewer which allows scrolling up and down (MCJack123). +* Add `cc.strings` module, with utilities for wrapping text (Lupus590). +* The `clear` program now allows resetting the palette too (Luca0208). + +And several bug fixes: +* Fix memory leak in generic peripherals. +* Fix crash when a turtle is broken while being ticked. +* `textutils.*tabulate` now accepts strings _or_ numbers. +* We now deny _all_ local IPs, using the magic `$private` host. Previously the IPv6 loopback interface was not blocked. +* Fix crash when rendering monitors if the block has not yet been synced. You will need to regenerate the config file to apply this change. +* `read` now supports numpad enter (TheWireLord) +* Correctly handle HTTP redirects to URLs containing escape characters. +* Fix integer overflow in `os.epoch`. +* Allow using pickaxes (and other items) for turtle upgrades which have mod-specific NBT. +* Fix duplicate turtle/pocket upgrade recipes appearing in JEI. + # New features in CC: Tweaked 1.94.0 * Add getter for window visibility (devomaa) diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 563dc0f69..477a8bbe1 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,13 +1,23 @@ -New features in CC: Tweaked 1.94.0 +New features in CC: Tweaked 1.95.0 -* Add getter for window visibility (devomaa) -* Generic peripherals are no longer experimental, and on by default. -* Use term.blit to draw boxes in paintutils (Lemmmy). +* Optimise the paint program's initial render. +* Several documentation improvments (Gibbo3771, MCJack123). +* `fs.combine` now accepts multiple arguments. +* Add a setting (`bios.strict_globals`) to error when accidentally declaring a global. (Lupus590). +* Add an improved help viewer which allows scrolling up and down (MCJack123). +* Add `cc.strings` module, with utilities for wrapping text (Lupus590). +* The `clear` program now allows resetting the palette too (Luca0208). And several bug fixes: -* Fix turtles not getting advancements when turtles are on. -* Draw in-hand pocket computers with the correct transparent flags enabled. -* Several bug fixes to SNBT parsing. -* Fix several programs using their original name instead of aliases in usage hints (Lupus590). +* Fix memory leak in generic peripherals. +* Fix crash when a turtle is broken while being ticked. +* `textutils.*tabulate` now accepts strings _or_ numbers. +* We now deny _all_ local IPs, using the magic `$private` host. Previously the IPv6 loopback interface was not blocked. +* Fix crash when rendering monitors if the block has not yet been synced. You will need to regenerate the config file to apply this change. +* `read` now supports numpad enter (TheWireLord) +* Correctly handle HTTP redirects to URLs containing escape characters. +* Fix integer overflow in `os.epoch`. +* Allow using pickaxes (and other items) for turtle upgrades which have mod-specific NBT. +* Fix duplicate turtle/pocket upgrade recipes appearing in JEI. Type "help changelog" to see the full version history. From 4af5bcc0b0ff464e7e7428c389d47140580ea7a7 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 25 Dec 2020 16:59:09 +0000 Subject: [PATCH 402/711] Fix serveral 1.15 -> 1.16 issues Well, strictly speaking some mapping changes. --- .../java/dan200/computercraft/data/BlockModelProvider.java | 3 ++- .../shared/peripheral/monitor/MonitorEdgeState.java | 2 +- .../computercraft/shared/peripheral/monitor/TileMonitor.java | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java index 6aea58d25..40b1c0097 100644 --- a/src/main/java/dan200/computercraft/data/BlockModelProvider.java +++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java @@ -17,6 +17,7 @@ import net.minecraft.data.DataGenerator; import net.minecraft.util.Direction; import net.minecraft.util.ResourceLocation; import net.minecraftforge.client.model.generators.*; +import net.minecraftforge.common.data.ExistingFileHelper; import javax.annotation.Nonnull; @@ -95,7 +96,7 @@ public class BlockModelProvider extends BlockStateProvider VariantBlockStateBuilder builder = getVariantBuilder( block ); for( MonitorEdgeState edge : BlockMonitor.STATE.getAllowedValues() ) { - String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getName(); + String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getString(); ModelFile model = models().getBuilder( suffix( block, suffix ) ); for( Direction facing : BlockMonitor.FACING.getAllowedValues() ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java index fb879335a..010033df1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -60,7 +60,7 @@ public enum MonitorEdgeState implements IStringSerializable @Override public String toString() { - return getName(); + return getString(); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index dd0f6638a..1c9973634 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -330,13 +330,13 @@ public class TileMonitor extends TileGeneric // Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's // fun problems with the block being missing on the client. BlockState state = getBlockState(); - return state.has( BlockMonitor.FACING ) ? state.get( BlockMonitor.FACING ) : Direction.NORTH; + return state.hasProperty( BlockMonitor.FACING ) ? state.get( BlockMonitor.FACING ) : Direction.NORTH; } public Direction getOrientation() { BlockState state = getBlockState(); - return state.has( BlockMonitor.ORIENTATION ) ? state.get( BlockMonitor.ORIENTATION ) : Direction.NORTH; + return state.hasProperty( BlockMonitor.ORIENTATION ) ? state.get( BlockMonitor.ORIENTATION ) : Direction.NORTH; } public Direction getFront() From b8d5a89446ac02fc5b38cc5c0b4805de9d11a7d5 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 25 Dec 2020 17:42:53 +0000 Subject: [PATCH 403/711] Add explicit @module annotation This feels like a bug - it should be inferred automatically. --- build.gradle | 2 +- .../data/computercraft/lua/rom/modules/main/cc/strings.lua | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 3ca948a14..01d0ee2f0 100644 --- a/build.gradle +++ b/build.gradle @@ -336,7 +336,7 @@ task minifyWeb(type: Exec, dependsOn: rollup) { inputs.file("package-lock.json").withPropertyName("package-lock.json") outputs.file("$buildDir/rollup/index.min.js").withPropertyName("output") - commandLine mkCommand('"node_modules/.bin/terser"' + " -o $buildDir/rollup/index.min.js $buildDir/rollup/index.js") + commandLine mkCommand('"node_modules/.bin/terser"' + " -o '$buildDir/rollup/index.min.js' '$buildDir/rollup/index.js'") } task illuaminateDocs(type: Exec, dependsOn: [minifyWeb, luaJavadoc]) { diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua index 1e6e6efc8..49f5cd0d4 100644 --- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua +++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua @@ -1,5 +1,6 @@ --- Various utilities for working with strings and text. -- +-- @module cc.strings -- @see textutils For additional string related utilities. local expect = require "cc.expect".expect From 8b17ec76a8e94251803e6f4ba4e65970c6a70b7f Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Mon, 28 Dec 2020 02:02:37 -0500 Subject: [PATCH 404/711] Fixed missing argument names in file handle docs (#632) --- .../core/apis/handles/EncodedWritableHandle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java index 4d548ce03..6aaadcee2 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java @@ -41,7 +41,7 @@ public class EncodedWritableHandle extends HandleGeneric * * @param args The value to write. * @throws LuaException If the file has been closed. - * @cc.param The value to write to the file. + * @cc.param value The value to write to the file. */ @LuaFunction public final void write( IArguments args ) throws LuaException @@ -63,7 +63,7 @@ public class EncodedWritableHandle extends HandleGeneric * * @param args The value to write. * @throws LuaException If the file has been closed. - * @cc.param The value to write to the file. + * @cc.param value The value to write to the file. */ @LuaFunction public final void writeLine( IArguments args ) throws LuaException From f7e3e72a6e8653f192b7dfad6cf4d072232e7259 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Mon, 28 Dec 2020 18:20:13 +0000 Subject: [PATCH 405/711] Update illuaminate again - Generate theme-color. Hopefully this time it works! - Specify a site url. Technically this is wrong (we should use the current git branch), but it's good enough for now. - Move some options into a sub-category. --- doc/head.html | 1 + illuaminate.sexp | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 doc/head.html diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 000000000..efd18a401 --- /dev/null +++ b/doc/head.html @@ -0,0 +1 @@ + diff --git a/illuaminate.sexp b/illuaminate.sexp index 3922ec02b..d37cc401d 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -10,13 +10,18 @@ (doc - (title "CC: Tweaked") (destination build/docs/lua) - (logo src/main/resources/pack.png) (index doc/index.md) - (styles src/web/styles.css) - (scripts build/rollup/index.js) - (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) + + (site + (title "CC: Tweaked") + (logo src/main/resources/pack.png) + (url https://tweaked.cc/) + (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) + + (styles src/web/styles.css) + (scripts build/rollup/index.js) + (head doc/head.html)) (module-kinds (peripheral Peripherals) From e4b0a5b3ce035eb23feb4191432fc49af5772c5b Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 6 Jan 2021 17:13:40 +0000 Subject: [PATCH 406/711] 2020 -> 2021 Oh, the most useless part of my build process. --- src/main/java/dan200/computercraft/ComputerCraft.java | 2 +- src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java | 2 +- src/main/java/dan200/computercraft/api/ComputerCraftAPI.java | 2 +- src/main/java/dan200/computercraft/api/IUpgradeBase.java | 2 +- .../java/dan200/computercraft/api/client/TransformedModel.java | 2 +- .../dan200/computercraft/api/filesystem/FileAttributes.java | 2 +- .../computercraft/api/filesystem/FileOperationException.java | 2 +- .../java/dan200/computercraft/api/filesystem/IFileSystem.java | 2 +- src/main/java/dan200/computercraft/api/filesystem/IMount.java | 2 +- .../dan200/computercraft/api/filesystem/IWritableMount.java | 2 +- src/main/java/dan200/computercraft/api/lua/IArguments.java | 2 +- .../java/dan200/computercraft/api/lua/IComputerSystem.java | 2 +- .../java/dan200/computercraft/api/lua/IDynamicLuaObject.java | 2 +- src/main/java/dan200/computercraft/api/lua/ILuaAPI.java | 2 +- src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java | 2 +- src/main/java/dan200/computercraft/api/lua/ILuaCallback.java | 2 +- src/main/java/dan200/computercraft/api/lua/ILuaContext.java | 2 +- src/main/java/dan200/computercraft/api/lua/ILuaFunction.java | 2 +- src/main/java/dan200/computercraft/api/lua/ILuaTask.java | 2 +- src/main/java/dan200/computercraft/api/lua/LuaException.java | 2 +- src/main/java/dan200/computercraft/api/lua/LuaFunction.java | 2 +- src/main/java/dan200/computercraft/api/lua/LuaValues.java | 2 +- src/main/java/dan200/computercraft/api/lua/MethodResult.java | 2 +- .../java/dan200/computercraft/api/lua/ObjectArguments.java | 2 +- src/main/java/dan200/computercraft/api/media/IMedia.java | 2 +- .../java/dan200/computercraft/api/media/IMediaProvider.java | 2 +- .../java/dan200/computercraft/api/network/IPacketNetwork.java | 2 +- .../java/dan200/computercraft/api/network/IPacketReceiver.java | 2 +- .../java/dan200/computercraft/api/network/IPacketSender.java | 2 +- src/main/java/dan200/computercraft/api/network/Packet.java | 2 +- .../dan200/computercraft/api/network/wired/IWiredElement.java | 2 +- .../dan200/computercraft/api/network/wired/IWiredNetwork.java | 2 +- .../computercraft/api/network/wired/IWiredNetworkChange.java | 2 +- .../dan200/computercraft/api/network/wired/IWiredNode.java | 2 +- .../dan200/computercraft/api/network/wired/IWiredSender.java | 2 +- .../dan200/computercraft/api/peripheral/IComputerAccess.java | 2 +- .../computercraft/api/peripheral/IDynamicPeripheral.java | 2 +- .../java/dan200/computercraft/api/peripheral/IPeripheral.java | 2 +- .../computercraft/api/peripheral/IPeripheralProvider.java | 2 +- .../java/dan200/computercraft/api/peripheral/IWorkMonitor.java | 2 +- .../computercraft/api/peripheral/NotAttachedException.java | 2 +- .../dan200/computercraft/api/pocket/AbstractPocketUpgrade.java | 2 +- .../java/dan200/computercraft/api/pocket/IPocketAccess.java | 2 +- .../java/dan200/computercraft/api/pocket/IPocketUpgrade.java | 2 +- .../computercraft/api/redstone/IBundledRedstoneProvider.java | 2 +- .../dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java | 2 +- .../java/dan200/computercraft/api/turtle/ITurtleAccess.java | 2 +- .../java/dan200/computercraft/api/turtle/ITurtleCommand.java | 2 +- .../java/dan200/computercraft/api/turtle/ITurtleUpgrade.java | 2 +- .../java/dan200/computercraft/api/turtle/TurtleAnimation.java | 2 +- .../dan200/computercraft/api/turtle/TurtleCommandResult.java | 2 +- src/main/java/dan200/computercraft/api/turtle/TurtleSide.java | 2 +- .../dan200/computercraft/api/turtle/TurtleUpgradeType.java | 2 +- src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java | 2 +- .../dan200/computercraft/api/turtle/event/TurtleAction.java | 2 +- .../computercraft/api/turtle/event/TurtleActionEvent.java | 2 +- .../computercraft/api/turtle/event/TurtleAttackEvent.java | 2 +- .../computercraft/api/turtle/event/TurtleBlockEvent.java | 2 +- .../dan200/computercraft/api/turtle/event/TurtleEvent.java | 2 +- .../computercraft/api/turtle/event/TurtleInspectItemEvent.java | 2 +- .../computercraft/api/turtle/event/TurtleInventoryEvent.java | 2 +- .../computercraft/api/turtle/event/TurtlePlayerEvent.java | 2 +- .../computercraft/api/turtle/event/TurtleRefuelEvent.java | 2 +- src/main/java/dan200/computercraft/client/ClientRegistry.java | 2 +- .../java/dan200/computercraft/client/ClientTableFormatter.java | 2 +- src/main/java/dan200/computercraft/client/FrameInfo.java | 2 +- .../computercraft/client/gui/FixedWidthFontRenderer.java | 2 +- src/main/java/dan200/computercraft/client/gui/GuiComputer.java | 2 +- .../java/dan200/computercraft/client/gui/GuiDiskDrive.java | 2 +- src/main/java/dan200/computercraft/client/gui/GuiPrinter.java | 2 +- src/main/java/dan200/computercraft/client/gui/GuiPrintout.java | 2 +- src/main/java/dan200/computercraft/client/gui/GuiTurtle.java | 2 +- .../computercraft/client/gui/widgets/WidgetTerminal.java | 2 +- .../dan200/computercraft/client/gui/widgets/WidgetWrapper.java | 2 +- .../computercraft/client/proxy/ComputerCraftProxyClient.java | 2 +- .../computercraft/client/render/CableHighlightRenderer.java | 2 +- .../computercraft/client/render/ComputerBorderRenderer.java | 3 +-- .../computercraft/client/render/ItemMapLikeRenderer.java | 2 +- .../dan200/computercraft/client/render/ItemPocketRenderer.java | 2 +- .../computercraft/client/render/ItemPrintoutRenderer.java | 2 +- .../computercraft/client/render/MonitorHighlightRenderer.java | 2 +- .../client/render/MonitorTextureBufferShader.java | 3 +-- .../dan200/computercraft/client/render/PrintoutRenderer.java | 2 +- .../computercraft/client/render/TileEntityMonitorRenderer.java | 2 +- .../computercraft/client/render/TileEntityTurtleRenderer.java | 2 +- .../dan200/computercraft/client/render/TurtleModelLoader.java | 2 +- .../dan200/computercraft/client/render/TurtleMultiModel.java | 2 +- .../computercraft/client/render/TurtlePlayerRenderer.java | 3 +-- .../computercraft/client/render/TurtleSmartItemModel.java | 2 +- src/main/java/dan200/computercraft/core/apis/ApiFactories.java | 2 +- .../java/dan200/computercraft/core/apis/ComputerAccess.java | 2 +- src/main/java/dan200/computercraft/core/apis/FSAPI.java | 2 +- .../java/dan200/computercraft/core/apis/FastLuaException.java | 3 +-- src/main/java/dan200/computercraft/core/apis/HTTPAPI.java | 2 +- .../java/dan200/computercraft/core/apis/IAPIEnvironment.java | 2 +- src/main/java/dan200/computercraft/core/apis/LuaDateTime.java | 2 +- src/main/java/dan200/computercraft/core/apis/OSAPI.java | 2 +- .../java/dan200/computercraft/core/apis/PeripheralAPI.java | 2 +- src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java | 2 +- src/main/java/dan200/computercraft/core/apis/TableHelper.java | 2 +- src/main/java/dan200/computercraft/core/apis/TermAPI.java | 2 +- src/main/java/dan200/computercraft/core/apis/TermMethods.java | 3 +-- .../computercraft/core/apis/handles/ArrayByteChannel.java | 2 +- .../computercraft/core/apis/handles/BinaryReadableHandle.java | 2 +- .../computercraft/core/apis/handles/BinaryWritableHandle.java | 2 +- .../computercraft/core/apis/handles/EncodedReadableHandle.java | 2 +- .../computercraft/core/apis/handles/EncodedWritableHandle.java | 2 +- .../dan200/computercraft/core/apis/handles/HandleGeneric.java | 2 +- .../java/dan200/computercraft/core/apis/http/CheckUrl.java | 2 +- .../computercraft/core/apis/http/HTTPRequestException.java | 2 +- .../java/dan200/computercraft/core/apis/http/NetworkUtils.java | 2 +- .../java/dan200/computercraft/core/apis/http/Resource.java | 2 +- .../dan200/computercraft/core/apis/http/ResourceGroup.java | 2 +- .../dan200/computercraft/core/apis/http/ResourceQueue.java | 2 +- .../dan200/computercraft/core/apis/http/options/Action.java | 3 +-- .../computercraft/core/apis/http/options/AddressPredicate.java | 3 +-- .../computercraft/core/apis/http/options/AddressRule.java | 2 +- .../core/apis/http/options/AddressRuleConfig.java | 3 +-- .../dan200/computercraft/core/apis/http/options/Options.java | 3 +-- .../computercraft/core/apis/http/options/PartialOptions.java | 3 +-- .../computercraft/core/apis/http/request/HttpRequest.java | 2 +- .../core/apis/http/request/HttpRequestHandler.java | 2 +- .../core/apis/http/request/HttpResponseHandle.java | 2 +- .../computercraft/core/apis/http/websocket/Websocket.java | 2 +- .../core/apis/http/websocket/WebsocketHandle.java | 2 +- .../core/apis/http/websocket/WebsocketHandler.java | 2 +- .../dan200/computercraft/core/asm/DeclaringClassLoader.java | 3 +-- src/main/java/dan200/computercraft/core/asm/Generator.java | 3 +-- src/main/java/dan200/computercraft/core/asm/GenericSource.java | 3 +-- src/main/java/dan200/computercraft/core/asm/IntCache.java | 3 +-- src/main/java/dan200/computercraft/core/asm/LuaMethod.java | 3 +-- src/main/java/dan200/computercraft/core/asm/NamedMethod.java | 3 +-- src/main/java/dan200/computercraft/core/asm/ObjectSource.java | 3 +-- .../java/dan200/computercraft/core/asm/PeripheralMethod.java | 3 +-- src/main/java/dan200/computercraft/core/asm/Reflect.java | 3 +-- src/main/java/dan200/computercraft/core/asm/TaskCallback.java | 3 +-- .../java/dan200/computercraft/core/computer/ApiWrapper.java | 2 +- src/main/java/dan200/computercraft/core/computer/Computer.java | 2 +- .../dan200/computercraft/core/computer/ComputerExecutor.java | 2 +- .../java/dan200/computercraft/core/computer/ComputerSide.java | 2 +- .../dan200/computercraft/core/computer/ComputerSystem.java | 2 +- .../dan200/computercraft/core/computer/ComputerThread.java | 2 +- .../java/dan200/computercraft/core/computer/Environment.java | 2 +- .../computercraft/core/computer/IComputerEnvironment.java | 2 +- .../java/dan200/computercraft/core/computer/MainThread.java | 2 +- .../dan200/computercraft/core/computer/MainThreadExecutor.java | 2 +- .../java/dan200/computercraft/core/computer/TimeoutState.java | 2 +- .../dan200/computercraft/core/filesystem/ChannelWrapper.java | 2 +- .../java/dan200/computercraft/core/filesystem/ComboMount.java | 2 +- .../java/dan200/computercraft/core/filesystem/EmptyMount.java | 2 +- .../java/dan200/computercraft/core/filesystem/FileMount.java | 2 +- .../java/dan200/computercraft/core/filesystem/FileSystem.java | 2 +- .../computercraft/core/filesystem/FileSystemException.java | 2 +- .../computercraft/core/filesystem/FileSystemWrapper.java | 2 +- .../computercraft/core/filesystem/FileSystemWrapperMount.java | 2 +- .../java/dan200/computercraft/core/filesystem/JarMount.java | 2 +- .../dan200/computercraft/core/filesystem/MountWrapper.java | 2 +- .../dan200/computercraft/core/filesystem/ResourceMount.java | 2 +- .../java/dan200/computercraft/core/filesystem/SubMount.java | 2 +- src/main/java/dan200/computercraft/core/lua/BasicFunction.java | 3 +-- .../java/dan200/computercraft/core/lua/CobaltLuaMachine.java | 2 +- src/main/java/dan200/computercraft/core/lua/ILuaMachine.java | 2 +- src/main/java/dan200/computercraft/core/lua/MachineResult.java | 2 +- .../computercraft/core/lua/ResultInterpreterFunction.java | 3 +-- .../java/dan200/computercraft/core/lua/VarargArguments.java | 3 +-- src/main/java/dan200/computercraft/core/terminal/Terminal.java | 2 +- .../java/dan200/computercraft/core/terminal/TextBuffer.java | 2 +- .../dan200/computercraft/core/tracking/ComputerTracker.java | 2 +- src/main/java/dan200/computercraft/core/tracking/Tracker.java | 2 +- src/main/java/dan200/computercraft/core/tracking/Tracking.java | 2 +- .../dan200/computercraft/core/tracking/TrackingContext.java | 2 +- .../java/dan200/computercraft/core/tracking/TrackingField.java | 2 +- .../java/dan200/computercraft/data/BlockModelProvider.java | 3 +-- src/main/java/dan200/computercraft/data/Generators.java | 3 +-- src/main/java/dan200/computercraft/data/LootTableProvider.java | 3 +-- src/main/java/dan200/computercraft/data/LootTables.java | 3 +-- src/main/java/dan200/computercraft/data/RecipeWrapper.java | 3 +-- src/main/java/dan200/computercraft/data/Recipes.java | 3 +-- src/main/java/dan200/computercraft/data/Tags.java | 3 +-- src/main/java/dan200/computercraft/shared/BundledRedstone.java | 2 +- src/main/java/dan200/computercraft/shared/Capabilities.java | 3 +-- src/main/java/dan200/computercraft/shared/Config.java | 2 +- src/main/java/dan200/computercraft/shared/MediaProviders.java | 2 +- src/main/java/dan200/computercraft/shared/Peripherals.java | 2 +- src/main/java/dan200/computercraft/shared/PocketUpgrades.java | 2 +- src/main/java/dan200/computercraft/shared/Registry.java | 2 +- .../java/dan200/computercraft/shared/TurtlePermissions.java | 2 +- src/main/java/dan200/computercraft/shared/TurtleUpgrades.java | 2 +- .../computercraft/shared/command/CommandComputerCraft.java | 2 +- .../java/dan200/computercraft/shared/command/CommandCopy.java | 2 +- .../java/dan200/computercraft/shared/command/CommandUtils.java | 2 +- .../java/dan200/computercraft/shared/command/Exceptions.java | 2 +- .../java/dan200/computercraft/shared/command/UserLevel.java | 2 +- .../shared/command/arguments/ArgumentSerializers.java | 2 +- .../shared/command/arguments/ChoiceArgumentType.java | 2 +- .../shared/command/arguments/ComputerArgumentType.java | 2 +- .../shared/command/arguments/ComputersArgumentType.java | 2 +- .../shared/command/arguments/RepeatArgumentType.java | 2 +- .../shared/command/arguments/TrackingFieldArgumentType.java | 2 +- .../computercraft/shared/command/builder/ArgCommand.java | 2 +- .../computercraft/shared/command/builder/CommandBuilder.java | 2 +- .../shared/command/builder/CommandNodeBuilder.java | 2 +- .../shared/command/builder/HelpingArgumentBuilder.java | 2 +- .../dan200/computercraft/shared/command/text/ChatHelpers.java | 2 +- .../shared/command/text/ServerTableFormatter.java | 2 +- .../dan200/computercraft/shared/command/text/TableBuilder.java | 2 +- .../computercraft/shared/command/text/TableFormatter.java | 2 +- .../java/dan200/computercraft/shared/common/BlockGeneric.java | 2 +- .../dan200/computercraft/shared/common/ClientTerminal.java | 2 +- .../dan200/computercraft/shared/common/ColourableRecipe.java | 2 +- .../dan200/computercraft/shared/common/ContainerHeldItem.java | 2 +- .../shared/common/DefaultBundledRedstoneProvider.java | 2 +- .../computercraft/shared/common/IBundledRedstoneBlock.java | 2 +- .../java/dan200/computercraft/shared/common/IColouredItem.java | 2 +- .../java/dan200/computercraft/shared/common/ITerminal.java | 2 +- .../dan200/computercraft/shared/common/ServerTerminal.java | 2 +- .../java/dan200/computercraft/shared/common/TileGeneric.java | 2 +- .../dan200/computercraft/shared/computer/apis/CommandAPI.java | 2 +- .../computercraft/shared/computer/blocks/BlockComputer.java | 2 +- .../shared/computer/blocks/BlockComputerBase.java | 2 +- .../shared/computer/blocks/ComputerPeripheral.java | 2 +- .../computercraft/shared/computer/blocks/ComputerProxy.java | 2 +- .../computercraft/shared/computer/blocks/IComputerTile.java | 2 +- .../shared/computer/blocks/TileCommandComputer.java | 2 +- .../computercraft/shared/computer/blocks/TileComputer.java | 2 +- .../computercraft/shared/computer/blocks/TileComputerBase.java | 2 +- .../computercraft/shared/computer/core/ClientComputer.java | 2 +- .../shared/computer/core/ClientComputerRegistry.java | 2 +- .../computercraft/shared/computer/core/ComputerFamily.java | 2 +- .../computercraft/shared/computer/core/ComputerRegistry.java | 2 +- .../computercraft/shared/computer/core/ComputerState.java | 2 +- .../dan200/computercraft/shared/computer/core/IComputer.java | 2 +- .../computercraft/shared/computer/core/IContainerComputer.java | 2 +- .../computercraft/shared/computer/core/InputHandler.java | 2 +- .../dan200/computercraft/shared/computer/core/InputState.java | 2 +- .../computercraft/shared/computer/core/ServerComputer.java | 2 +- .../shared/computer/core/ServerComputerRegistry.java | 2 +- .../shared/computer/inventory/ContainerComputer.java | 2 +- .../shared/computer/inventory/ContainerComputerBase.java | 2 +- .../shared/computer/inventory/ContainerViewComputer.java | 2 +- .../shared/computer/items/ComputerItemFactory.java | 2 +- .../computercraft/shared/computer/items/IComputerItem.java | 2 +- .../computercraft/shared/computer/items/ItemComputer.java | 2 +- .../computercraft/shared/computer/items/ItemComputerBase.java | 2 +- .../shared/computer/recipe/ComputerConvertRecipe.java | 2 +- .../shared/computer/recipe/ComputerFamilyRecipe.java | 2 +- .../shared/computer/recipe/ComputerUpgradeRecipe.java | 2 +- .../shared/data/BlockNamedEntityLootCondition.java | 2 +- .../shared/data/ConstantLootConditionSerializer.java | 2 +- .../computercraft/shared/data/HasComputerIdLootCondition.java | 2 +- .../computercraft/shared/data/PlayerCreativeLootCondition.java | 2 +- .../shared/integration/crafttweaker/TrackingLogger.java | 2 +- .../shared/integration/crafttweaker/TurtleTweaker.java | 2 +- .../shared/integration/crafttweaker/actions/AddTurtleTool.java | 2 +- .../crafttweaker/actions/RemoveTurtleUpgradeByItem.java | 2 +- .../crafttweaker/actions/RemoveTurtleUpgradeByName.java | 2 +- .../computercraft/shared/integration/jei/JEIComputerCraft.java | 2 +- .../computercraft/shared/integration/jei/RecipeResolver.java | 2 +- .../java/dan200/computercraft/shared/media/items/ItemDisk.java | 2 +- .../dan200/computercraft/shared/media/items/ItemPrintout.java | 2 +- .../computercraft/shared/media/items/ItemTreasureDisk.java | 2 +- .../dan200/computercraft/shared/media/items/RecordMedia.java | 2 +- .../dan200/computercraft/shared/media/recipes/DiskRecipe.java | 2 +- .../computercraft/shared/media/recipes/PrintoutRecipe.java | 2 +- .../dan200/computercraft/shared/network/NetworkHandler.java | 2 +- .../dan200/computercraft/shared/network/NetworkMessage.java | 2 +- .../shared/network/client/ChatTableClientMessage.java | 2 +- .../shared/network/client/ComputerClientMessage.java | 2 +- .../shared/network/client/ComputerDataClientMessage.java | 2 +- .../shared/network/client/ComputerDeletedClientMessage.java | 2 +- .../shared/network/client/ComputerTerminalClientMessage.java | 2 +- .../shared/network/client/MonitorClientMessage.java | 3 +-- .../shared/network/client/PlayRecordClientMessage.java | 2 +- .../computercraft/shared/network/client/TerminalState.java | 3 +-- .../shared/network/container/ComputerContainerData.java | 2 +- .../computercraft/shared/network/container/ContainerData.java | 2 +- .../shared/network/container/HeldItemContainerData.java | 2 +- .../shared/network/container/ViewComputerContainerData.java | 2 +- .../shared/network/server/ComputerActionServerMessage.java | 2 +- .../shared/network/server/ComputerServerMessage.java | 2 +- .../shared/network/server/KeyEventServerMessage.java | 2 +- .../shared/network/server/MouseEventServerMessage.java | 2 +- .../shared/network/server/QueueEventServerMessage.java | 2 +- .../shared/network/server/RequestComputerMessage.java | 2 +- .../shared/peripheral/commandblock/CommandBlockPeripheral.java | 2 +- .../shared/peripheral/diskdrive/BlockDiskDrive.java | 2 +- .../shared/peripheral/diskdrive/ContainerDiskDrive.java | 2 +- .../shared/peripheral/diskdrive/DiskDrivePeripheral.java | 2 +- .../shared/peripheral/diskdrive/DiskDriveState.java | 2 +- .../shared/peripheral/diskdrive/TileDiskDrive.java | 2 +- .../shared/peripheral/generic/GenericPeripheral.java | 3 +-- .../shared/peripheral/generic/GenericPeripheralProvider.java | 3 +-- .../shared/peripheral/generic/SaturatedMethod.java | 3 +-- .../shared/peripheral/generic/data/BlockData.java | 3 +-- .../shared/peripheral/generic/data/DataHelpers.java | 3 +-- .../shared/peripheral/generic/data/FluidData.java | 3 +-- .../computercraft/shared/peripheral/generic/data/ItemData.java | 3 +-- .../shared/peripheral/generic/methods/ArgumentHelpers.java | 3 +-- .../shared/peripheral/generic/methods/EnergyMethods.java | 3 +-- .../shared/peripheral/generic/methods/FluidMethods.java | 3 +-- .../shared/peripheral/generic/methods/InventoryMethods.java | 3 +-- .../computercraft/shared/peripheral/modem/ModemPeripheral.java | 2 +- .../computercraft/shared/peripheral/modem/ModemShapes.java | 2 +- .../computercraft/shared/peripheral/modem/ModemState.java | 2 +- .../shared/peripheral/modem/wired/BlockCable.java | 2 +- .../shared/peripheral/modem/wired/BlockWiredModemFull.java | 2 +- .../shared/peripheral/modem/wired/CableModemVariant.java | 2 +- .../shared/peripheral/modem/wired/CableShapes.java | 2 +- .../shared/peripheral/modem/wired/ItemBlockCable.java | 2 +- .../computercraft/shared/peripheral/modem/wired/TileCable.java | 2 +- .../shared/peripheral/modem/wired/TileWiredModemFull.java | 2 +- .../shared/peripheral/modem/wired/WiredModemElement.java | 2 +- .../peripheral/modem/wired/WiredModemLocalPeripheral.java | 2 +- .../shared/peripheral/modem/wired/WiredModemPeripheral.java | 2 +- .../shared/peripheral/modem/wireless/BlockWirelessModem.java | 2 +- .../shared/peripheral/modem/wireless/TileWirelessModem.java | 2 +- .../peripheral/modem/wireless/WirelessModemPeripheral.java | 2 +- .../shared/peripheral/modem/wireless/WirelessNetwork.java | 2 +- .../computercraft/shared/peripheral/monitor/BlockMonitor.java | 2 +- .../computercraft/shared/peripheral/monitor/ClientMonitor.java | 2 +- .../shared/peripheral/monitor/MonitorEdgeState.java | 2 +- .../shared/peripheral/monitor/MonitorPeripheral.java | 2 +- .../shared/peripheral/monitor/MonitorRenderer.java | 3 +-- .../shared/peripheral/monitor/MonitorWatcher.java | 3 +-- .../computercraft/shared/peripheral/monitor/ServerMonitor.java | 2 +- .../computercraft/shared/peripheral/monitor/TileMonitor.java | 2 +- .../dan200/computercraft/shared/peripheral/monitor/XYPair.java | 2 +- .../computercraft/shared/peripheral/printer/BlockPrinter.java | 2 +- .../shared/peripheral/printer/ContainerPrinter.java | 2 +- .../shared/peripheral/printer/PrinterPeripheral.java | 2 +- .../computercraft/shared/peripheral/printer/TilePrinter.java | 2 +- .../computercraft/shared/peripheral/speaker/BlockSpeaker.java | 2 +- .../shared/peripheral/speaker/SpeakerPeripheral.java | 2 +- .../computercraft/shared/peripheral/speaker/TileSpeaker.java | 2 +- .../dan200/computercraft/shared/pocket/apis/PocketAPI.java | 2 +- .../computercraft/shared/pocket/core/PocketServerComputer.java | 2 +- .../shared/pocket/inventory/ContainerPocketComputer.java | 2 +- .../computercraft/shared/pocket/items/ItemPocketComputer.java | 2 +- .../shared/pocket/items/PocketComputerItemFactory.java | 2 +- .../computercraft/shared/pocket/peripherals/PocketModem.java | 2 +- .../shared/pocket/peripherals/PocketModemPeripheral.java | 2 +- .../computercraft/shared/pocket/peripherals/PocketSpeaker.java | 2 +- .../shared/pocket/peripherals/PocketSpeakerPeripheral.java | 2 +- .../shared/pocket/recipes/PocketComputerUpgradeRecipe.java | 2 +- .../computercraft/shared/proxy/ComputerCraftProxyCommon.java | 2 +- .../computercraft/shared/turtle/FurnaceRefuelHandler.java | 2 +- .../dan200/computercraft/shared/turtle/apis/TurtleAPI.java | 2 +- .../dan200/computercraft/shared/turtle/blocks/BlockTurtle.java | 2 +- .../dan200/computercraft/shared/turtle/blocks/ITurtleTile.java | 2 +- .../dan200/computercraft/shared/turtle/blocks/TileTurtle.java | 2 +- .../computercraft/shared/turtle/core/InteractDirection.java | 2 +- .../dan200/computercraft/shared/turtle/core/MoveDirection.java | 2 +- .../dan200/computercraft/shared/turtle/core/TurnDirection.java | 2 +- .../dan200/computercraft/shared/turtle/core/TurtleBrain.java | 2 +- .../shared/turtle/core/TurtleCommandQueueEntry.java | 2 +- .../computercraft/shared/turtle/core/TurtleCompareCommand.java | 2 +- .../shared/turtle/core/TurtleCompareToCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleCraftCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleDetectCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleDropCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleEquipCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleInspectCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleMoveCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtlePlaceCommand.java | 2 +- .../dan200/computercraft/shared/turtle/core/TurtlePlayer.java | 2 +- .../computercraft/shared/turtle/core/TurtleRefuelCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleSuckCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleToolCommand.java | 2 +- .../shared/turtle/core/TurtleTransferToCommand.java | 2 +- .../computercraft/shared/turtle/core/TurtleTurnCommand.java | 2 +- .../computercraft/shared/turtle/inventory/ContainerTurtle.java | 2 +- .../dan200/computercraft/shared/turtle/items/ITurtleItem.java | 2 +- .../dan200/computercraft/shared/turtle/items/ItemTurtle.java | 2 +- .../computercraft/shared/turtle/items/TurtleItemFactory.java | 2 +- .../computercraft/shared/turtle/recipes/TurtleRecipe.java | 2 +- .../shared/turtle/recipes/TurtleUpgradeRecipe.java | 2 +- .../shared/turtle/upgrades/CraftingTablePeripheral.java | 2 +- .../dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java | 2 +- .../shared/turtle/upgrades/TurtleCraftingTable.java | 2 +- .../dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java | 2 +- .../shared/turtle/upgrades/TurtleInventoryCrafting.java | 2 +- .../computercraft/shared/turtle/upgrades/TurtleModem.java | 2 +- .../computercraft/shared/turtle/upgrades/TurtleShovel.java | 2 +- .../computercraft/shared/turtle/upgrades/TurtleSpeaker.java | 3 +-- .../computercraft/shared/turtle/upgrades/TurtleSword.java | 2 +- .../computercraft/shared/turtle/upgrades/TurtleTool.java | 2 +- .../computercraft/shared/util/BasicRecipeSerializer.java | 2 +- .../java/dan200/computercraft/shared/util/CapabilityUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/Colour.java | 2 +- .../java/dan200/computercraft/shared/util/ColourTracker.java | 2 +- .../java/dan200/computercraft/shared/util/ColourUtils.java | 2 +- .../java/dan200/computercraft/shared/util/CreativeTabMain.java | 2 +- .../dan200/computercraft/shared/util/DefaultInventory.java | 2 +- .../computercraft/shared/util/DefaultSidedInventory.java | 2 +- .../java/dan200/computercraft/shared/util/DirectionUtil.java | 2 +- .../java/dan200/computercraft/shared/util/DropConsumer.java | 2 +- .../java/dan200/computercraft/shared/util/FakeNetHandler.java | 2 +- .../computercraft/shared/util/FixedPointTileEntityType.java | 2 +- src/main/java/dan200/computercraft/shared/util/Holiday.java | 2 +- .../java/dan200/computercraft/shared/util/HolidayUtil.java | 2 +- src/main/java/dan200/computercraft/shared/util/IDAssigner.java | 2 +- .../java/dan200/computercraft/shared/util/ImpostorRecipe.java | 2 +- .../computercraft/shared/util/ImpostorShapelessRecipe.java | 2 +- .../dan200/computercraft/shared/util/InventoryDelegate.java | 2 +- .../java/dan200/computercraft/shared/util/InventoryUtil.java | 2 +- src/main/java/dan200/computercraft/shared/util/IoUtil.java | 2 +- src/main/java/dan200/computercraft/shared/util/NBTUtil.java | 2 +- .../java/dan200/computercraft/shared/util/NullStorage.java | 3 +-- src/main/java/dan200/computercraft/shared/util/Palette.java | 2 +- src/main/java/dan200/computercraft/shared/util/RecipeUtil.java | 2 +- src/main/java/dan200/computercraft/shared/util/RecordUtil.java | 2 +- .../java/dan200/computercraft/shared/util/RedstoneUtil.java | 2 +- .../java/dan200/computercraft/shared/util/ServiceUtil.java | 3 +-- src/main/java/dan200/computercraft/shared/util/SidedCaps.java | 3 +-- .../java/dan200/computercraft/shared/util/SingleIntArray.java | 2 +- src/main/java/dan200/computercraft/shared/util/StringUtil.java | 2 +- .../java/dan200/computercraft/shared/util/ThreadUtils.java | 2 +- .../java/dan200/computercraft/shared/util/TickScheduler.java | 2 +- .../java/dan200/computercraft/shared/util/ValidatingSlot.java | 2 +- .../dan200/computercraft/shared/util/WaterloggableHelpers.java | 2 +- src/main/java/dan200/computercraft/shared/util/WorldUtil.java | 2 +- .../dan200/computercraft/shared/wired/InvariantChecker.java | 2 +- .../java/dan200/computercraft/shared/wired/WiredNetwork.java | 2 +- .../dan200/computercraft/shared/wired/WiredNetworkChange.java | 2 +- src/main/java/dan200/computercraft/shared/wired/WiredNode.java | 2 +- src/test/java/dan200/computercraft/ContramapMatcher.java | 3 +-- .../java/dan200/computercraft/core/ComputerTestDelegate.java | 2 +- src/test/java/dan200/computercraft/core/LuaCoverage.java | 3 +-- .../java/dan200/computercraft/core/apis/ObjectWrapper.java | 2 +- .../core/apis/handles/BinaryReadableHandleTest.java | 2 +- .../core/apis/handles/EncodedReadableHandleTest.java | 2 +- .../computercraft/core/apis/http/options/AddressRuleTest.java | 3 +-- src/test/java/dan200/computercraft/core/asm/GeneratorTest.java | 3 +-- src/test/java/dan200/computercraft/core/asm/IntCacheTest.java | 3 +-- src/test/java/dan200/computercraft/core/asm/MethodTest.java | 3 +-- .../dan200/computercraft/core/computer/BasicEnvironment.java | 2 +- .../dan200/computercraft/core/computer/ComputerBootstrap.java | 2 +- .../java/dan200/computercraft/core/computer/ComputerTest.java | 2 +- .../dan200/computercraft/core/filesystem/FileSystemTest.java | 2 +- .../dan200/computercraft/core/filesystem/JarMountTest.java | 2 +- .../java/dan200/computercraft/core/filesystem/MemoryMount.java | 2 +- .../computercraft/core/filesystem/ResourceMountTest.java | 2 +- .../computercraft/shared/network/client/TerminalStateTest.java | 3 +-- .../java/dan200/computercraft/shared/wired/NetworkTest.java | 2 +- 444 files changed, 444 insertions(+), 502 deletions(-) diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 2daa28eb0..70eab1e72 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft; diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java index dcd2c5bdb..6b6db770a 100644 --- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java +++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft; diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 42fa4dcce..f429ca946 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api; diff --git a/src/main/java/dan200/computercraft/api/IUpgradeBase.java b/src/main/java/dan200/computercraft/api/IUpgradeBase.java index d3b4a0af1..24a4a08f9 100644 --- a/src/main/java/dan200/computercraft/api/IUpgradeBase.java +++ b/src/main/java/dan200/computercraft/api/IUpgradeBase.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api; diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java index c4c88eec3..40b2281fd 100644 --- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.client; diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java index 5dcf3e964..82aa83686 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index 70a25fe5f..be6519fbd 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java index 7ef4a1c12..7ce152db7 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java index 258843822..01ef7512c 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java index 5a52b5ae7..3f5efaada 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.filesystem; diff --git a/src/main/java/dan200/computercraft/api/lua/IArguments.java b/src/main/java/dan200/computercraft/api/lua/IArguments.java index c19ed4526..02e8b659d 100644 --- a/src/main/java/dan200/computercraft/api/lua/IArguments.java +++ b/src/main/java/dan200/computercraft/api/lua/IArguments.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java index c0717bcb2..fb76aceb4 100644 --- a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java +++ b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java index 13b2c7a8f..ac3d3ce15 100644 --- a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java +++ b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java index ae405e3aa..e1a1d4a54 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java index 763a8bdaf..7db976eb9 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java index f05d82a73..e999042af 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java index 569b61e5b..3f81f49e4 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java index cd75848e1..7813cbbdc 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java index 4ea060358..808e635b5 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/LuaException.java b/src/main/java/dan200/computercraft/api/lua/LuaException.java index 949a8eeba..9f98ddc09 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaException.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaException.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java index e17e30ac4..5558b153c 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/LuaValues.java b/src/main/java/dan200/computercraft/api/lua/LuaValues.java index f89b24a17..8eec784ff 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaValues.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaValues.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/MethodResult.java b/src/main/java/dan200/computercraft/api/lua/MethodResult.java index fce9f970f..25a8a392d 100644 --- a/src/main/java/dan200/computercraft/api/lua/MethodResult.java +++ b/src/main/java/dan200/computercraft/api/lua/MethodResult.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java index 4ccc50b89..6dd7e3c0f 100644 --- a/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java +++ b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.lua; diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index 3134f5bc6..7dcd688b6 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.media; diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java index a3605f024..f6e1793e6 100644 --- a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.media; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java index b85ac6e38..277150156 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index 49b37d889..1f0081161 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index bb9dc63d1..645d2ca41 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/Packet.java b/src/main/java/dan200/computercraft/api/network/Packet.java index baaaeefa4..7bd159f8b 100644 --- a/src/main/java/dan200/computercraft/api/network/Packet.java +++ b/src/main/java/dan200/computercraft/api/network/Packet.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java index b60f1800c..390bd91e9 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network.wired; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java index d2e046e77..ae18cb691 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network.wired; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java index df90f279f..0663509a6 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network.wired; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java index 061f950f7..e72f25a62 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network.wired; diff --git a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java index ee456f538..f2795eced 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.network.wired; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index fd46dd056..1735422f8 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java index 5e7e8bfcc..695680b94 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 88c8154a4..9c7f2bea5 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index 2be4f613e..2dfc7d676 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java index a68fd58e0..2ec3f3df9 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java index a01efa5a6..96ebd11ac 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java +++ b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.peripheral; diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index 33d756866..75f64d2a0 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.pocket; diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index c2cda5fc7..4c37e6a91 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.pocket; diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index c0b761ef2..89b72ad69 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.pocket; diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index b323b4aeb..e69e76501 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.redstone; diff --git a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java index b3c92271c..2aa7af918 100644 --- a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 85752b15a..2f4f8b69d 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java index 00c17ab54..e7300a02c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 76e53919e..7b90e2b7d 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java index 1e988b91c..dd67a044a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java index c2a7783c2..c4eec6e94 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java index a32f149f4..e944cfe43 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java index 8991551aa..daa036a8a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index 7ea92e182..997eb44c0 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java index f5e347d5a..f8515dff6 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java index 2f95cbb87..fcaf39b41 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java index bcb185101..668486613 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java index efd20fd36..8d061c269 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java index 1a980db85..b7e69ca54 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java index e4eb517e3..721122c02 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java index f01436f6b..0275c7ec3 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java index 476221171..2be611fa9 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java index e9fc0c92e..fe61251fa 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -1,6 +1,6 @@ /* * This file is part of the public ComputerCraft API - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. This API may be redistributed unmodified and in full only. + * Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only. * For help using the API, and posting your mods, visit the forums at computercraft.info. */ package dan200.computercraft.api.turtle.event; diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index 57359e00c..381dc91ce 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client; diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 991fbbb1d..689ce251a 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client; diff --git a/src/main/java/dan200/computercraft/client/FrameInfo.java b/src/main/java/dan200/computercraft/client/FrameInfo.java index 00e72b67a..59479ebb2 100644 --- a/src/main/java/dan200/computercraft/client/FrameInfo.java +++ b/src/main/java/dan200/computercraft/client/FrameInfo.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client; diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index e10c0351a..7ea6a4ad0 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index 3008c9386..ad3a3cc24 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java index 59b6e38d2..f521d07d3 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java index 6073a459f..6f86c09b7 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 37927e62a..08ec7d892 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui; diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 517cf140f..6bec2b78c 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui; diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 79a172129..d64e24e9e 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui.widgets; diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java index 84317f8a3..45ca4617e 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetWrapper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.gui.widgets; diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java index c8c8374c9..50afc8f4f 100644 --- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java +++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.proxy; diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java index f88700b98..f87fa8782 100644 --- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java index 9c784d7fc..4eacb4779 100644 --- a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java index f25deea79..9176dd722 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index 661effe15..0b356f0fe 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java index 5fa6ada5d..4549060df 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java index 54e8c80b9..a954938a3 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java index 570761186..241823f33 100644 --- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java +++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import com.google.common.base.Strings; diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java index 53f1c358e..69a9865a7 100644 --- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index 8f8530360..2fdcd3411 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java index 91162280b..d9717d84a 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java index 41249f178..353166e47 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index 8f9a65cfd..d690c5d40 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java index 4e7cb8e70..7fecf7514 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.client.render; import com.mojang.blaze3d.matrix.MatrixStack; diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index f99b61264..3488cf7b8 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.client.render; diff --git a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java index 32a4faf0c..0f801e865 100644 --- a/src/main/java/dan200/computercraft/core/apis/ApiFactories.java +++ b/src/main/java/dan200/computercraft/core/apis/ApiFactories.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index 1eebc5e01..a0f762070 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 7d189f34a..6ae65f62a 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/FastLuaException.java b/src/main/java/dan200/computercraft/core/apis/FastLuaException.java index 6ef64f275..45e4db0b2 100644 --- a/src/main/java/dan200/computercraft/core/apis/FastLuaException.java +++ b/src/main/java/dan200/computercraft/core/apis/FastLuaException.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.LuaException; diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 71163f064..4363b9684 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 19e2d2f14..25960c580 100644 --- a/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java b/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java index dc5c4fa1f..9ad29ad4c 100644 --- a/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java +++ b/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index f43d09539..5634ed6ed 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index b132ad48c..02e382090 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index ab096fd08..27c13b957 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/TableHelper.java b/src/main/java/dan200/computercraft/core/apis/TableHelper.java index 296bfb0a1..d16083534 100644 --- a/src/main/java/dan200/computercraft/core/apis/TableHelper.java +++ b/src/main/java/dan200/computercraft/core/apis/TableHelper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 243cca146..6b1816096 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/src/main/java/dan200/computercraft/core/apis/TermMethods.java index 43090405d..ce5545124 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermMethods.java +++ b/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis; import dan200.computercraft.api.lua.IArguments; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java b/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java index adcc75ff6..464e23a4e 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/ArrayByteChannel.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java index 807e1c331..553504748 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java index e1a71c964..c494e702f 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java index 3f2080f3f..c64690e62 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java index 6aaadcee2..400393d12 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java index 418ab07dd..d9291c173 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java index 41ddc9390..d3313b1fc 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java +++ b/src/main/java/dan200/computercraft/core/apis/http/CheckUrl.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; diff --git a/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java b/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java index 72655a05c..abf0cdabc 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java +++ b/src/main/java/dan200/computercraft/core/apis/http/HTTPRequestException.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; diff --git a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java index 9dc2309a9..aec3abace 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; diff --git a/src/main/java/dan200/computercraft/core/apis/http/Resource.java b/src/main/java/dan200/computercraft/core/apis/http/Resource.java index 469a57511..b17b06d23 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/Resource.java +++ b/src/main/java/dan200/computercraft/core/apis/http/Resource.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; diff --git a/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java b/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java index cfce1f3ce..6533c3622 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java +++ b/src/main/java/dan200/computercraft/core/apis/http/ResourceGroup.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; diff --git a/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java b/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java index 4159097b0..c0f8c2ac2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java +++ b/src/main/java/dan200/computercraft/core/apis/http/ResourceQueue.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/Action.java b/src/main/java/dan200/computercraft/core/apis/http/options/Action.java index ac23cc575..f994ec3a3 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/Action.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/Action.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.options; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java index b647f73a3..9109a3457 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressPredicate.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.options; import com.google.common.net.InetAddresses; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java index f1884e3f3..955e89d4d 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRule.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.options; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java index db82c06ef..862ff39b6 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/AddressRuleConfig.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.options; import com.electronwill.nightconfig.core.CommentedConfig; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/Options.java b/src/main/java/dan200/computercraft/core/apis/http/options/Options.java index 5dd0e78d1..d6074a9a4 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/Options.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/Options.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.options; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java b/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java index fb7150dd5..ef0801966 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java +++ b/src/main/java/dan200/computercraft/core/apis/http/options/PartialOptions.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.options; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java index 115d8ab04..c6447b77b 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.request; diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index bebfdbea2..db83124e6 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.request; diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java index 89038f99c..5ab40814d 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.request; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java index 0407a198a..296e27eda 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/Websocket.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.websocket; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java index ce8684002..0c74c0c9f 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.websocket; diff --git a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java index 52c27b97c..9cac47ce8 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.http.websocket; diff --git a/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java b/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java index 009a8840e..34e9be132 100644 --- a/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java +++ b/src/main/java/dan200/computercraft/core/asm/DeclaringClassLoader.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import java.security.ProtectionDomain; diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java index 2e80cd86c..a57e8e44e 100644 --- a/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import com.google.common.cache.CacheBuilder; diff --git a/src/main/java/dan200/computercraft/core/asm/GenericSource.java b/src/main/java/dan200/computercraft/core/asm/GenericSource.java index 71cab0b26..ff28ea6e1 100644 --- a/src/main/java/dan200/computercraft/core/asm/GenericSource.java +++ b/src/main/java/dan200/computercraft/core/asm/GenericSource.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/asm/IntCache.java b/src/main/java/dan200/computercraft/core/asm/IntCache.java index 3652a530d..ec634b3cb 100644 --- a/src/main/java/dan200/computercraft/core/asm/IntCache.java +++ b/src/main/java/dan200/computercraft/core/asm/IntCache.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import java.util.Arrays; diff --git a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java index 4bf142903..b0562835c 100644 --- a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.api.lua.*; diff --git a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java index f7d0ffef4..ea72bb7a4 100644 --- a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/core/asm/ObjectSource.java b/src/main/java/dan200/computercraft/core/asm/ObjectSource.java index f05ac7070..06ecbaf03 100644 --- a/src/main/java/dan200/computercraft/core/asm/ObjectSource.java +++ b/src/main/java/dan200/computercraft/core/asm/ObjectSource.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import java.util.function.BiConsumer; diff --git a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java index f92a988f0..38618442f 100644 --- a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.api.lua.IArguments; diff --git a/src/main/java/dan200/computercraft/core/asm/Reflect.java b/src/main/java/dan200/computercraft/core/asm/Reflect.java index 429402206..4517fecc3 100644 --- a/src/main/java/dan200/computercraft/core/asm/Reflect.java +++ b/src/main/java/dan200/computercraft/core/asm/Reflect.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java index af8d8814d..1298391e4 100644 --- a/src/main/java/dan200/computercraft/core/asm/TaskCallback.java +++ b/src/main/java/dan200/computercraft/core/asm/TaskCallback.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.api.lua.*; diff --git a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java index 693045dfe..6265b127d 100644 --- a/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java +++ b/src/main/java/dan200/computercraft/core/computer/ApiWrapper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index 8affb0f01..a40e104e6 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java index 021c4b473..ad9c729c1 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerExecutor.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java index 073a63c98..961738f24 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSide.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSide.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java index ee4917afe..9747f27e4 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerSystem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java index 66ea9e644..b07401adc 100644 --- a/src/main/java/dan200/computercraft/core/computer/ComputerThread.java +++ b/src/main/java/dan200/computercraft/core/computer/ComputerThread.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index 041973fef..3931629f1 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java b/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java index e51054768..3d928ffc2 100644 --- a/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java +++ b/src/main/java/dan200/computercraft/core/computer/IComputerEnvironment.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/MainThread.java b/src/main/java/dan200/computercraft/core/computer/MainThread.java index e2874dadc..8f53541e2 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThread.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThread.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java index baedd3b53..81cfa8893 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThreadExecutor.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/computer/TimeoutState.java b/src/main/java/dan200/computercraft/core/computer/TimeoutState.java index 6bfe804e4..5f2d99265 100644 --- a/src/main/java/dan200/computercraft/core/computer/TimeoutState.java +++ b/src/main/java/dan200/computercraft/core/computer/TimeoutState.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java index 94cd47b19..ab9d532d4 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index ffd7db5cf..17ad177ed 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java index c3ba89855..ab89d3fb8 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/EmptyMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index c1d2a0af6..61a237215 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index bb6c7149c..2556822bc 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java index 2ff07ae5d..482d0d080 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemException.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java index 28841f295..5d1ad2d74 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java index f22e33654..ba2d4008d 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java index d169e8717..f902261a0 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/JarMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/JarMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java index 86a97426d..96b11f24f 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java +++ b/src/main/java/dan200/computercraft/core/filesystem/MountWrapper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index fbc3a5e7d..648a06ed0 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java index 68d2999ee..bc62e875d 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/main/java/dan200/computercraft/core/lua/BasicFunction.java b/src/main/java/dan200/computercraft/core/lua/BasicFunction.java index 6f4b25652..f515cd455 100644 --- a/src/main/java/dan200/computercraft/core/lua/BasicFunction.java +++ b/src/main/java/dan200/computercraft/core/lua/BasicFunction.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.lua; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index e678667e1..2721d10bb 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.lua; diff --git a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java index 5c9de9cb3..3d62c2c43 100644 --- a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.lua; diff --git a/src/main/java/dan200/computercraft/core/lua/MachineResult.java b/src/main/java/dan200/computercraft/core/lua/MachineResult.java index adff1058f..167ec9298 100644 --- a/src/main/java/dan200/computercraft/core/lua/MachineResult.java +++ b/src/main/java/dan200/computercraft/core/lua/MachineResult.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.lua; diff --git a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java index 58c630c28..495d1a2d1 100644 --- a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java +++ b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.lua; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/core/lua/VarargArguments.java b/src/main/java/dan200/computercraft/core/lua/VarargArguments.java index cedba0a80..0079e41c7 100644 --- a/src/main/java/dan200/computercraft/core/lua/VarargArguments.java +++ b/src/main/java/dan200/computercraft/core/lua/VarargArguments.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.lua; import dan200.computercraft.api.lua.IArguments; diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index f3ec0b2cf..7b200ef56 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.terminal; diff --git a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java index 6a8e55355..46f1c9656 100644 --- a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java +++ b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.terminal; diff --git a/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java b/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java index 3cc9886c9..0bc7787ca 100644 --- a/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java +++ b/src/main/java/dan200/computercraft/core/tracking/ComputerTracker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.tracking; diff --git a/src/main/java/dan200/computercraft/core/tracking/Tracker.java b/src/main/java/dan200/computercraft/core/tracking/Tracker.java index b0c0c4743..979f5863f 100644 --- a/src/main/java/dan200/computercraft/core/tracking/Tracker.java +++ b/src/main/java/dan200/computercraft/core/tracking/Tracker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.tracking; diff --git a/src/main/java/dan200/computercraft/core/tracking/Tracking.java b/src/main/java/dan200/computercraft/core/tracking/Tracking.java index 587b242cc..1097e7d8a 100644 --- a/src/main/java/dan200/computercraft/core/tracking/Tracking.java +++ b/src/main/java/dan200/computercraft/core/tracking/Tracking.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.tracking; diff --git a/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java b/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java index d1205c2e2..95621da4d 100644 --- a/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java +++ b/src/main/java/dan200/computercraft/core/tracking/TrackingContext.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.tracking; diff --git a/src/main/java/dan200/computercraft/core/tracking/TrackingField.java b/src/main/java/dan200/computercraft/core/tracking/TrackingField.java index bc3f151ec..c8e13f479 100644 --- a/src/main/java/dan200/computercraft/core/tracking/TrackingField.java +++ b/src/main/java/dan200/computercraft/core/tracking/TrackingField.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.tracking; diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java index 6aea58d25..c336b9948 100644 --- a/src/main/java/dan200/computercraft/data/BlockModelProvider.java +++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/data/Generators.java b/src/main/java/dan200/computercraft/data/Generators.java index 8e8f931f1..4dd693dc3 100644 --- a/src/main/java/dan200/computercraft/data/Generators.java +++ b/src/main/java/dan200/computercraft/data/Generators.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon; diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java index e24d07206..b76ca31bd 100644 --- a/src/main/java/dan200/computercraft/data/LootTableProvider.java +++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import com.google.common.collect.Multimap; diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index b85f0dea1..946d57fac 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/data/RecipeWrapper.java b/src/main/java/dan200/computercraft/data/RecipeWrapper.java index 9451df12e..8fd20d3b5 100644 --- a/src/main/java/dan200/computercraft/data/RecipeWrapper.java +++ b/src/main/java/dan200/computercraft/data/RecipeWrapper.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import com.google.gson.JsonObject; diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java index d7dc75d78..c9d538b17 100644 --- a/src/main/java/dan200/computercraft/data/Recipes.java +++ b/src/main/java/dan200/computercraft/data/Recipes.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java index d822d6150..2556e4fae 100644 --- a/src/main/java/dan200/computercraft/data/Tags.java +++ b/src/main/java/dan200/computercraft/data/Tags.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java index a684ef69b..f2ae897a7 100644 --- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java +++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/Capabilities.java b/src/main/java/dan200/computercraft/shared/Capabilities.java index ba820e183..83c31896b 100644 --- a/src/main/java/dan200/computercraft/shared/Capabilities.java +++ b/src/main/java/dan200/computercraft/shared/Capabilities.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared; import dan200.computercraft.api.network.wired.IWiredElement; diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java index 6655d6fd5..4a61a226a 100644 --- a/src/main/java/dan200/computercraft/shared/Config.java +++ b/src/main/java/dan200/computercraft/shared/Config.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/MediaProviders.java b/src/main/java/dan200/computercraft/shared/MediaProviders.java index 2ef132e52..a54be11c7 100644 --- a/src/main/java/dan200/computercraft/shared/MediaProviders.java +++ b/src/main/java/dan200/computercraft/shared/MediaProviders.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java index 1d93147b4..b30185de9 100644 --- a/src/main/java/dan200/computercraft/shared/Peripherals.java +++ b/src/main/java/dan200/computercraft/shared/Peripherals.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index 58494b618..2358d28be 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index fe8a2d448..5bbdf3bec 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java index 98c7eca75..4593035d9 100644 --- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java +++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index 76aa1c8a4..c13774b5a 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 876dcad5a..95617d03d 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java index adf102649..b5d1a9b80 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command; diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java index c5c6a1ab0..199ebb45a 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command; diff --git a/src/main/java/dan200/computercraft/shared/command/Exceptions.java b/src/main/java/dan200/computercraft/shared/command/Exceptions.java index 46289a773..0edecc53f 100644 --- a/src/main/java/dan200/computercraft/shared/command/Exceptions.java +++ b/src/main/java/dan200/computercraft/shared/command/Exceptions.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command; diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java index 576785b30..3d6885f2e 100644 --- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java +++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java index b52cb26cb..600e72b31 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ArgumentSerializers.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.arguments; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java index 797db6f85..cbed13bb7 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ChoiceArgumentType.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.arguments; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java index 25bfe6256..d7bef738c 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputerArgumentType.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.arguments; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java index 9784556a8..7bdef6342 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.arguments; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java index 8c91be401..d3057a21b 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.arguments; diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java index 6391fd3ef..71b3c9f65 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/TrackingFieldArgumentType.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.arguments; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java index f2dcc4efa..c478b67b5 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/ArgCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.builder; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java index 21998e71f..20e55f936 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.builder; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java index 638a42806..f2e108727 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandNodeBuilder.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.builder; diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java index a90713133..793a75136 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.builder; diff --git a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java index c2948f912..a7f834b77 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ChatHelpers.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.text; diff --git a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java index 02f0270bb..d307272d9 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/ServerTableFormatter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.text; diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java index 8c29ce36e..204922f06 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableBuilder.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.text; diff --git a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java index 683989cd6..6992d2e38 100644 --- a/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java +++ b/src/main/java/dan200/computercraft/shared/command/text/TableFormatter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.command.text; diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java index d83089b7d..bb178aa24 100644 --- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 73b6d6e9a..389d8b4d7 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java index f7bc441b9..50b15c15d 100644 --- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java +++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java index 8514a9133..c9826a32a 100644 --- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java +++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java index 48e4956cd..b2089770f 100644 --- a/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/shared/common/DefaultBundledRedstoneProvider.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java index 27d45b4bb..c9f900546 100644 --- a/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java +++ b/src/main/java/dan200/computercraft/shared/common/IBundledRedstoneBlock.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java index 5795a17cc..aad157282 100644 --- a/src/main/java/dan200/computercraft/shared/common/IColouredItem.java +++ b/src/main/java/dan200/computercraft/shared/common/IColouredItem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/ITerminal.java b/src/main/java/dan200/computercraft/shared/common/ITerminal.java index 2e91b85b4..48577e5da 100644 --- a/src/main/java/dan200/computercraft/shared/common/ITerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ITerminal.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 4f2445ce5..13bb7bc8a 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java index 5d391cf8a..e787bdf13 100644 --- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java +++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.common; diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index ad85cbe79..2788e5368 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.apis; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java index e2386f667..37e4a58af 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java index ac164df1f..ef1f29f82 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java index 8e527be7d..e06db68f2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java index 205161aeb..60ca49169 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java index 7adb7c0a8..40e0dca90 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/IComputerTile.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 20d542463..951dd6091 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index e03862b3f..03eea284e 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index e904e02f4..6179b5393 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.blocks; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index 09a7a43a0..92fc32a4d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java index fe4cf0292..fa87eb642 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java index c5accf370..a68f770d9 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerFamily.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java index 10ad45731..fc7d0ed4a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java index 82f603306..2b6ccc039 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java index 11b3af51f..7398776dc 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java index 981d4d186..164bce6ae 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java index efc401070..c7b630720 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputState.java b/src/main/java/dan200/computercraft/shared/computer/core/InputState.java index 832bc91f2..b1a9d77af 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputState.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/InputState.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 6026eed98..4d1db3f23 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java index ab605420c..fa5a92424 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.core; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java index 9ce948931..f2ead9dad 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.inventory; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index 699474012..a84f1a4fc 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.inventory; diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index ccc8b24d9..59a406576 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.inventory; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index 3be415994..4c23fa27d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.items; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java index df23729b1..3f4f03de3 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.items; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java index c0548e8ce..1dd01ea2b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.items; diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 3ac904dc8..501ae9826 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.items; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java index 7aea4ef38..830efb4f7 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.recipe; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java index 64e6c82ca..b82869dfa 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.recipe; diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java index afd91c89c..cd50542ff 100644 --- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.computer.recipe; diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java index 898c321ce..27e4cae7f 100644 --- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.data; diff --git a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java index 07ac6a830..bad07f669 100644 --- a/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java +++ b/src/main/java/dan200/computercraft/shared/data/ConstantLootConditionSerializer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.data; diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java index 4da10a15c..1f16abec0 100644 --- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.data; diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java index 6a91f90fe..e777cfb26 100644 --- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java +++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.data; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java index 07733df89..329a96b0e 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.crafttweaker; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java index d3b9345d4..80a702bca 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TurtleTweaker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.crafttweaker; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java index df8393cfb..f9f0a6907 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.crafttweaker.actions; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java index 5c1cc0aec..dc1223118 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByItem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.crafttweaker.actions; diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java index 47158be7f..6ea355803 100644 --- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java +++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/RemoveTurtleUpgradeByName.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.crafttweaker.actions; diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java index 45e0e380b..a6ea2fc91 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.jei; diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java index fa420f3ea..0bed3e75c 100644 --- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java +++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.integration.jei; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java index 6ef877402..2394b3e1b 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.media.items; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java index d34d4a897..c54efc754 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.media.items; diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java index 345f36e68..5e7d63187 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java +++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.media.items; diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 28b74e388..32db93c43 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.media.items; diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java index 0e5f81ab5..5640bd2e3 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.media.recipes; diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java index ded19dca8..12fec72e2 100644 --- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java +++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.media.recipes; diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index 5b905a76b..79e49949c 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network; diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java index 404dd1037..da49d0aa7 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index 3cf767f70..bad9f3e1d 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.client; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java index 684f9a8f2..ebdf2cc87 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.client; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java index a6a596160..60e517f4a 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.client; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java index 5c42aa73e..033e8f19a 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.client; diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index de7bf3e85..29eea30ee 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.client; diff --git a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java index 55d4f7406..512bad7f7 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.shared.network.NetworkMessage; diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java index ce1851c85..3f10e09f4 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.client; diff --git a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java index a720bc818..1f88b5696 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java +++ b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java index 0a2b5c643..88f7a2042 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.container; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java index 370f6c139..90787fc0f 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ContainerData.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.container; diff --git a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java index 2088cd240..1bef2de56 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.container; diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java index e1805a517..797c6d61a 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.container; diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java index 9ec56f044..688262a21 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.server; diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index 3a97ab287..637494dfd 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.server; diff --git a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java index 8b56efeda..35a156916 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.server; diff --git a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java index 9ecc612a5..bad6556a8 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.server; diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index f683967cb..792fc4a26 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.server; diff --git a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java index f788f8bbd..91014401c 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.network.server; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java index ff0881f29..0dbf2d709 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.commandblock; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java index 17104f9ec..cf3e5fa24 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.diskdrive; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java index 88725bdfa..5fe4542af 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.diskdrive; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java index bcf7dc82e..9a698a39b 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDrivePeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.diskdrive; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java index 17faae369..a82201bb8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.diskdrive; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 8e53b02b4..1797a02a2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.diskdrive; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java index 9970d66cb..ebfa94a6f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheral.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.lua.IArguments; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java index 260f8d781..6bb25f1b8 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.peripheral.IPeripheral; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java index 6db3f6aa4..31a120e52 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/SaturatedMethod.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic; import dan200.computercraft.api.lua.IArguments; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java index 13d516c8f..ec07302f9 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.data; import com.google.common.collect.ImmutableMap; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java index 5a3f5c4d0..96d0699b1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/DataHelpers.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.data; import net.minecraft.util.ResourceLocation; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java index e5b19af7d..641aa9255 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/FluidData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.data; import net.minecraftforge.fluids.FluidStack; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java index a2e049d9b..2622d654a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.data; import com.google.gson.JsonParseException; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java index d27865ee5..2884815b3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/ArgumentHelpers.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.methods; import dan200.computercraft.api.lua.LuaException; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java index 5eab3f94f..a7ae044af 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/EnergyMethods.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.methods; import com.google.auto.service.AutoService; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java index 1dfe5a2a0..a9d206f5a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.methods; import com.google.auto.service.AutoService; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index c8a1c0749..8aa20a105 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.generic.methods; import com.google.auto.service.AutoService; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 0805406a9..8ef54a91f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java index 77d241b6a..c213e961d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java index d206c1d4b..faea8052d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemState.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java index 3bdbfee7a..2660dac95 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java index 63408e7d6..80cbdc4d3 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java index 22d4b5ead..9e5521bb2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java index 1b96f50ac..01ed76966 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java index d1591bd18..cf44fc4eb 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 7d548ec5a..6756f6e3e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 349cb6d28..b6e0d7029 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java index 510e5e342..52cfd5c47 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemElement.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java index 94e5c7ade..190a99930 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java index bdd1187ca..e9d6d04cf 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wired; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java index f95066025..8a6fd22d2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wireless; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index d13915afc..bf187d494 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wireless; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index 68d77d366..2008a4bec 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wireless; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java index 2300d4e3c..0fd216b61 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.modem.wireless; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java index 345741c59..caa4146b6 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java index 6cb024469..935e1a12e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java index ffc7b22df..30203974c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java index c2e8cb050..7e02f1c28 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java index 0aa86610c..4da4fa79c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorRenderer.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java index 89032b3bb..f05a46c55 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java index 11e404dcf..7dbd2ae65 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 7e9193d91..49ce409a5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java index fce6a7c88..8e4c3e34e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/XYPair.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.monitor; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java index 27bb47348..bdc5bed57 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.printer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java index 8ab37fef9..deb5f09d5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.printer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java index 6e7da2aad..a51849a8e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.printer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index f704c2484..8e63d3ae5 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.printer; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java index bcc2b5149..8e8cfdd08 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.speaker; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 217b5b59f..59316a669 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.speaker; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index 793ef4aad..e0d792284 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.peripheral.speaker; diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 25734108a..2dd3ed61d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.apis; diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index e165daf95..f9dcb00e5 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.core; diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java index 25f0151d8..a762936d1 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.inventory; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index f72b28a31..e969d7cd7 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.items; diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java index 25b2210d1..b6db54f5c 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItemFactory.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.items; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java index d8b626198..ea84a3042 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.peripherals; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java index 12e98c000..484fa0ad3 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.peripherals; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java index 84ed6d85d..4bba1b47c 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.peripherals; diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java index 66182ff4d..f518e4158 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeakerPeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.peripherals; diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java index e2049b6f3..17bad137e 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.pocket.recipes; diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index d4b962cb3..4c5727bfd 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.proxy; diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index d70cbcf9b..4fc159bed 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle; diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index b96e3f999..b09bdc4f9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.apis; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java index 6c1eb4871..7efc6ceb8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.blocks; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java index 541186682..7d27cd93e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/ITurtleTile.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.blocks; diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 2d52d0ef9..cd5d5973a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.blocks; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java index 62bf467e1..feab31a39 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/InteractDirection.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java index 580aacdef..566b33725 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/MoveDirection.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java index cebc87c2b..dafd1dd93 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurnDirection.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 07b3dec26..e09af75cb 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java index 64a2aa655..dfa7d90d7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCommandQueueEntry.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index aff3f883e..01633a247 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java index d1f87c912..b57e471b9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java index 5d2ed6597..a92cbc1f3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index bb3b5126c..3b1c88917 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index e09b6fe92..747062d4c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index 7c4990f35..b11ee4ff2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java index d5f1d2499..bcb596b98 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 0e2d896cc..b7e8c879b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 84dc412fb..a7b739f5a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 4b60932e3..270b25183 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java index 3eb9b8880..58a789979 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index d23b10e98..8ca4b8b26 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java index 9575090e8..e0f67bae9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleToolCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index a1b7a9e7a..82b2417be 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java index 5272af775..05fc7978c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.core; diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index f5d2c7054..c02a6e933 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.inventory; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java index a6cc3de5a..3f043dbda 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ITurtleItem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.items; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java index de0bfec1a..f849357e5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.items; diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index cb472937e..512c82efb 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.items; diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java index 1e92e4db2..05e598bac 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.recipes; diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index 010924cb8..6240ad6a8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.recipes; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java index ebec3f562..f972e0588 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/CraftingTablePeripheral.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java index 523b5f0a5..915db05cc 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleAxe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 5182c01ee..6ef00ad4b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java index 4c4b341e9..903d6677c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index 8e01c80b2..42b063470 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 4632d5db9..4e5f97785 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java index 1cbe660f1..cbec04c14 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index 0a605660e..d11d5b4e4 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.upgrades; import dan200.computercraft.api.client.TransformedModel; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java index 78549c242..425208eb9 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java index 04505670e..96c619a3d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.turtle.upgrades; diff --git a/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java b/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java index 7558549b2..ff55073ca 100644 --- a/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java +++ b/src/main/java/dan200/computercraft/shared/util/BasicRecipeSerializer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java b/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java index 7643eeb2c..baed8c497 100644 --- a/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/CapabilityUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraftforge.common.util.LazyOptional; diff --git a/src/main/java/dan200/computercraft/shared/util/Colour.java b/src/main/java/dan200/computercraft/shared/util/Colour.java index 5c9e6b86d..daba8d632 100644 --- a/src/main/java/dan200/computercraft/shared/util/Colour.java +++ b/src/main/java/dan200/computercraft/shared/util/Colour.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java index 705285d7b..457573e85 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java index 7a595f3c2..55c97e3cd 100644 --- a/src/main/java/dan200/computercraft/shared/util/ColourUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ColourUtils.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java index 19da95ff5..955d52bac 100644 --- a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java +++ b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java index 065471e8e..d23ebfcfb 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java index 7ae4e70f5..92f13dea9 100644 --- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java +++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java index 6e14facf0..65d186659 100644 --- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java index 477ad73de..cb861edba 100644 --- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java +++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java index 02fae31ab..d153b633d 100644 --- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java +++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java index c711c256e..ffc2fc411 100644 --- a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java +++ b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/Holiday.java b/src/main/java/dan200/computercraft/shared/util/Holiday.java index b4728d46c..ce32b0dec 100644 --- a/src/main/java/dan200/computercraft/shared/util/Holiday.java +++ b/src/main/java/dan200/computercraft/shared/util/Holiday.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java b/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java index ea9e5dd74..05ee0143f 100644 --- a/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/HolidayUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java index 229488422..dfa7a8ac4 100644 --- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java +++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java index d5946f19b..eed4f920f 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java index 5553ef484..42b77e9fe 100644 --- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java +++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java index e00616f65..9e07db877 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java index 8f8cff926..46fb5b37e 100644 --- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/IoUtil.java b/src/main/java/dan200/computercraft/shared/util/IoUtil.java index 910a716e2..1e16a3ece 100644 --- a/src/main/java/dan200/computercraft/shared/util/IoUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/IoUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java index 97879a497..2d534ac5b 100644 --- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/NullStorage.java b/src/main/java/dan200/computercraft/shared/util/NullStorage.java index 1c8ab93ae..080f3f968 100644 --- a/src/main/java/dan200/computercraft/shared/util/NullStorage.java +++ b/src/main/java/dan200/computercraft/shared/util/NullStorage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.nbt.INBT; diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index 2f17f08e2..f5647454e 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java index 156378cdd..b142b7f70 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java index 2fdb56422..85715a64c 100644 --- a/src/main/java/dan200/computercraft/shared/util/RecordUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RecordUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java index 25e10cef3..933a287cb 100644 --- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java b/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java index 6ff2d898e..c21861dda 100644 --- a/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/ServiceUtil.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import dan200.computercraft.ComputerCraft; diff --git a/src/main/java/dan200/computercraft/shared/util/SidedCaps.java b/src/main/java/dan200/computercraft/shared/util/SidedCaps.java index 7491416a7..a07fd6707 100644 --- a/src/main/java/dan200/computercraft/shared/util/SidedCaps.java +++ b/src/main/java/dan200/computercraft/shared/util/SidedCaps.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.util; import net.minecraft.util.Direction; diff --git a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java index 3d2297f2b..19f763e67 100644 --- a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java +++ b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/StringUtil.java b/src/main/java/dan200/computercraft/shared/util/StringUtil.java index 64a7f1e2d..cecece354 100644 --- a/src/main/java/dan200/computercraft/shared/util/StringUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/StringUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java b/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java index f03bb4d8e..88b24f5dd 100644 --- a/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java +++ b/src/main/java/dan200/computercraft/shared/util/ThreadUtils.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 2ad3f4ba6..760ad6a8c 100644 --- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java index 40772efcd..ec541024d 100644 --- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java +++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java index 978b78eff..e9d6e9c54 100644 --- a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java +++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java index d483c7d74..d7415a5d5 100644 --- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java +++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.util; diff --git a/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java b/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java index 40084252f..0bff2c83f 100644 --- a/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java +++ b/src/main/java/dan200/computercraft/shared/wired/InvariantChecker.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.wired; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index c66c7e19b..5f6c0f842 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.wired; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java index 144fe6a76..c59640052 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetworkChange.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.wired; diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java index 4ccd80ebc..3900de297 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.wired; diff --git a/src/test/java/dan200/computercraft/ContramapMatcher.java b/src/test/java/dan200/computercraft/ContramapMatcher.java index 35e7117fa..ba3682ee2 100644 --- a/src/test/java/dan200/computercraft/ContramapMatcher.java +++ b/src/test/java/dan200/computercraft/ContramapMatcher.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft; import org.hamcrest.Description; diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 2807f189b..16eab74da 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core; diff --git a/src/test/java/dan200/computercraft/core/LuaCoverage.java b/src/test/java/dan200/computercraft/core/LuaCoverage.java index 92998d629..26044c8e6 100644 --- a/src/test/java/dan200/computercraft/core/LuaCoverage.java +++ b/src/test/java/dan200/computercraft/core/LuaCoverage.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core; import com.google.common.base.Strings; diff --git a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java index a01cc639a..1c50dc779 100644 --- a/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java +++ b/src/test/java/dan200/computercraft/core/apis/ObjectWrapper.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis; diff --git a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java index ad272c9aa..eacd23a41 100644 --- a/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/handles/BinaryReadableHandleTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java b/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java index 5c3e57da0..8937d2588 100644 --- a/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/handles/EncodedReadableHandleTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.apis.handles; diff --git a/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java index 3a8246e7f..4c2e6c233 100644 --- a/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java +++ b/src/test/java/dan200/computercraft/core/apis/http/options/AddressRuleTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.apis.http.options; import dan200.computercraft.ComputerCraft; diff --git a/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java b/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java index 8104fa4a1..4a5db6cdb 100644 --- a/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java +++ b/src/test/java/dan200/computercraft/core/asm/GeneratorTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.api.lua.*; diff --git a/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java b/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java index 94f17da65..822ed790b 100644 --- a/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java +++ b/src/test/java/dan200/computercraft/core/asm/IntCacheTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import org.junit.jupiter.api.Test; diff --git a/src/test/java/dan200/computercraft/core/asm/MethodTest.java b/src/test/java/dan200/computercraft/core/asm/MethodTest.java index cfbbe6b9b..68f516761 100644 --- a/src/test/java/dan200/computercraft/core/asm/MethodTest.java +++ b/src/test/java/dan200/computercraft/core/asm/MethodTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.core.asm; import dan200.computercraft.api.lua.*; diff --git a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java index ccdcc751b..a96e312be 100644 --- a/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java +++ b/src/test/java/dan200/computercraft/core/computer/BasicEnvironment.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java index 3675c14d2..3055c4f65 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerBootstrap.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java index 830e27305..d25458310 100644 --- a/src/test/java/dan200/computercraft/core/computer/ComputerTest.java +++ b/src/test/java/dan200/computercraft/core/computer/ComputerTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.computer; diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java index 73aaaccda..17855cf4a 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java index fbc36dcb8..7d78b0217 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/JarMountTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java index bd16104ac..b2cce2d44 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java +++ b/src/test/java/dan200/computercraft/core/filesystem/MemoryMount.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java index 5c61f24fb..b66d9accb 100644 --- a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java +++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.core.filesystem; diff --git a/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java b/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java index 44427c361..49d11645b 100644 --- a/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java +++ b/src/test/java/dan200/computercraft/shared/network/client/TerminalStateTest.java @@ -1,9 +1,8 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.network.client; import dan200.computercraft.core.terminal.Terminal; diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java index 174558001..a329fb565 100644 --- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java +++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java @@ -1,6 +1,6 @@ /* * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission. + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ package dan200.computercraft.shared.wired; From 542b66c79a9b08e080c39c9a73d74ffe71c0106a Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 6 Jan 2021 17:27:52 +0000 Subject: [PATCH 407/711] Add back command computer block drops This has been broken for almost a year (28th Jan 2020), and I never noticed. Good job me. Fixes #641, closes #648 (basically the same, but targetting 1.15.x) --- .../loot_tables/blocks/computer_command.json | 34 +++++++++++++++++++ .../dan200/computercraft/data/LootTables.java | 1 + 2 files changed, 35 insertions(+) create mode 100644 src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json new file mode 100644 index 000000000..6ca0e4761 --- /dev/null +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_command.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "name": "main", + "rolls": 1, + "entries": [ + { + "type": "minecraft:dynamic", + "name": "computercraft:computer" + } + ], + "conditions": [ + { + "condition": "minecraft:alternative", + "terms": [ + { + "condition": "computercraft:block_named" + }, + { + "condition": "computercraft:has_id" + }, + { + "condition": "minecraft:inverted", + "term": { + "condition": "computercraft:player_creative" + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index 946d57fac..df7d1c8ed 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -42,6 +42,7 @@ public class LootTables extends LootTableProvider computerDrop( add, Registry.ModBlocks.COMPUTER_NORMAL ); computerDrop( add, Registry.ModBlocks.COMPUTER_ADVANCED ); + computerDrop( add, Registry.ModBlocks.COMPUTER_COMMAND ); computerDrop( add, Registry.ModBlocks.TURTLE_NORMAL ); computerDrop( add, Registry.ModBlocks.TURTLE_ADVANCED ); From 72340defe40c3809650fad747a68364e8902dd93 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Wed, 6 Jan 2021 17:42:13 +0000 Subject: [PATCH 408/711] Update illuaminate - Fix doc library-path - Only style
 code blocks as executable. Skip  ones.
 - Document the default parameters in gps. Yes, we should do it
   everywhere, but one has to start somewhere!
---
 illuaminate.sexp                                     | 12 ++++++------
 .../data/computercraft/lua/rom/apis/gps.lua          |  6 +++---
 src/web/styles.css                                   |  2 +-
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/illuaminate.sexp b/illuaminate.sexp
index d37cc401d..0d6850bde 100644
--- a/illuaminate.sexp
+++ b/illuaminate.sexp
@@ -31,13 +31,13 @@
     /doc/stub/
     /build/docs/luaJavadoc/
 
-    /src/main/resources/*/computercraft/lua/rom/apis
-    /src/main/resources/*/computercraft/lua/rom/apis/command
-    /src/main/resources/*/computercraft/lua/rom/apis/turtle
+    /src/main/resources/*/computercraft/lua/rom/apis/
+    /src/main/resources/*/computercraft/lua/rom/apis/command/
+    /src/main/resources/*/computercraft/lua/rom/apis/turtle/
 
-    /src/main/resources/*/computercraft/lua/rom/modules/main
-    /src/main/resources/*/computercraft/lua/rom/modules/command
-    /src/main/resources/*/computercraft/lua/rom/modules/turtle))
+    /src/main/resources/*/computercraft/lua/rom/modules/main/
+    /src/main/resources/*/computercraft/lua/rom/modules/command/
+    /src/main/resources/*/computercraft/lua/rom/modules/turtle/))
 
 (at /
   (linters
diff --git a/src/main/resources/data/computercraft/lua/rom/apis/gps.lua b/src/main/resources/data/computercraft/lua/rom/apis/gps.lua
index 3be8906a5..8cbc63a78 100644
--- a/src/main/resources/data/computercraft/lua/rom/apis/gps.lua
+++ b/src/main/resources/data/computercraft/lua/rom/apis/gps.lua
@@ -83,9 +83,9 @@ end
 
 --- Tries to retrieve the computer or turtles own location.
 --
--- @tparam[opt] number timeout The maximum time taken to establish our
--- position. Defaults to 2 seconds if not specified.
--- @tparam[opt] boolean debug Print debugging messages
+-- @tparam[opt=2] number timeout The maximum time in seconds taken to establish our
+-- position.
+-- @tparam[opt=false] boolean debug Print debugging messages
 -- @treturn[1] number This computer's `x` position.
 -- @treturn[1] number This computer's `y` position.
 -- @treturn[1] number This computer's `z` position.
diff --git a/src/web/styles.css b/src/web/styles.css
index e60e670ee..966453812 100644
--- a/src/web/styles.css
+++ b/src/web/styles.css
@@ -13,7 +13,7 @@ table.pretty-table th {
     background-color: #f0f0f0;
 }
 
-.highlight.highlight-lua {
+pre.highlight.highlight-lua {
     position: relative;
     background: #eee;
     padding: 2px;

From 2c9f51db89ce5f0bbd1470c2ae2b0cbb94738251 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 6 Jan 2021 18:08:19 +0000
Subject: [PATCH 409/711] Don't fatally error if CraftTweaker items have NBT

CT now adds {Damage:0}, which means turtle upgrades not registered any
more for tools. Fixes #647.
---
 .../shared/integration/crafttweaker/TrackingLogger.java         | 1 -
 .../shared/integration/crafttweaker/actions/AddTurtleTool.java  | 2 +-
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java
index 329a96b0e..da1708c00 100644
--- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java
+++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/TrackingLogger.java
@@ -27,7 +27,6 @@ public final class TrackingLogger
 
     public void warning( String message )
     {
-        ok = false;
         logger.warning( message );
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java
index f9f0a6907..38acb1561 100644
--- a/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java
+++ b/src/main/java/dan200/computercraft/shared/integration/crafttweaker/actions/AddTurtleTool.java
@@ -103,7 +103,7 @@ public class AddTurtleTool implements IUndoableAction
     {
         TrackingLogger trackLog = new TrackingLogger( logger );
 
-        if( craftItem.isEmpty() ) trackLog.warning( "Crafting item stack is empty." );
+        if( craftItem.isEmpty() ) trackLog.error( "Crafting item stack is empty." );
 
         if( craftItem.hasTag() && !craftItem.getTag().isEmpty() ) trackLog.warning( "Crafting item has NBT." );
         if( toolItem.isEmpty() ) trackLog.error( "Tool item stack is empty." );

From dd6f97622e6c18ce0d8988da6a5bede45c94ca5d Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 6 Jan 2021 18:21:03 +0000
Subject: [PATCH 410/711] Prevent reflection errors crashing the game

.getMethods() may throw if a method references classes which don't exist
(such as client-only classes on a server). This is an Error, and so is
unchecked - hence us not handling it before.

Fixes #645
---
 .../computercraft/core/asm/Generator.java     | 22 +++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java
index a57e8e44e..c559c4112 100644
--- a/src/main/java/dan200/computercraft/core/asm/Generator.java
+++ b/src/main/java/dan200/computercraft/core/asm/Generator.java
@@ -56,11 +56,11 @@ public final class Generator
 
     private final LoadingCache, List>> classCache = CacheBuilder
         .newBuilder()
-        .build( CacheLoader.from( this::build ) );
+        .build( CacheLoader.from( catching( this::build, Collections.emptyList() ) ) );
 
     private final LoadingCache> methodCache = CacheBuilder
         .newBuilder()
-        .build( CacheLoader.from( this::build ) );
+        .build( CacheLoader.from( catching( this::build, Optional.empty() ) ) );
 
     Generator( Class base, List> context, Function wrap )
     {
@@ -358,4 +358,22 @@ public final class Generator
             arg.getName(), method.getDeclaringClass().getName(), method.getName() );
         return null;
     }
+
+    @SuppressWarnings( "Guava" )
+    private static  com.google.common.base.Function catching( Function function, U def )
+    {
+        return x -> {
+            try
+            {
+                return function.apply( x );
+            }
+            catch( Exception | LinkageError e )
+            {
+                // LinkageError due to possible codegen bugs and NoClassDefFoundError. The latter occurs when fetching
+                // methods on a class which references non-existent (i.e. client-only) types.
+                ComputerCraft.log.error( "Error generating @LuaFunctions", e );
+                return def;
+            }
+        };
+    }
 }

From 92be0126df63927d07fc695945f8b98e328f945a Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 6 Jan 2021 21:17:26 +0000
Subject: [PATCH 411/711] Fix disk recipes

Closes #652. This has been broken since the 1.13 update. Not filling
myself with confidence here.
---
 .../computercraft/shared/common/ColourableRecipe.java      | 6 +-----
 .../computercraft/shared/media/recipes/DiskRecipe.java     | 7 ++-----
 .../dan200/computercraft/shared/util/ColourTracker.java    | 7 +++++++
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java
index 50b15c15d..25a1bf4a6 100644
--- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java
@@ -5,7 +5,6 @@
  */
 package dan200.computercraft.shared.common;
 
-import dan200.computercraft.shared.util.Colour;
 import dan200.computercraft.shared.util.ColourTracker;
 import dan200.computercraft.shared.util.ColourUtils;
 import net.minecraft.inventory.CraftingInventory;
@@ -75,10 +74,7 @@ public final class ColourableRecipe extends SpecialRecipe
             else
             {
                 DyeColor dye = ColourUtils.getStackColour( stack );
-                if( dye == null ) continue;
-
-                Colour colour = Colour.fromInt( 15 - dye.getId() );
-                tracker.addColour( colour.getR(), colour.getG(), colour.getB() );
+                if( dye != null ) tracker.addColour( dye );
             }
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java
index 5640bd2e3..6580f3a3c 100644
--- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java
@@ -55,7 +55,7 @@ public class DiskRecipe extends SpecialRecipe
                     if( redstoneFound ) return false;
                     redstoneFound = true;
                 }
-                else if( ColourUtils.getStackColour( stack ) != null )
+                else if( ColourUtils.getStackColour( stack ) == null )
                 {
                     return false;
                 }
@@ -80,10 +80,7 @@ public class DiskRecipe extends SpecialRecipe
             if( !paper.test( stack ) && !redstone.test( stack ) )
             {
                 DyeColor dye = ColourUtils.getStackColour( stack );
-                if( dye == null ) continue;
-
-                Colour colour = Colour.VALUES[dye.getId()];
-                tracker.addColour( colour.getR(), colour.getG(), colour.getB() );
+                if( dye != null ) tracker.addColour( dye );
             }
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java
index 457573e85..4b4c8838c 100644
--- a/src/main/java/dan200/computercraft/shared/util/ColourTracker.java
+++ b/src/main/java/dan200/computercraft/shared/util/ColourTracker.java
@@ -5,6 +5,7 @@
  */
 package dan200.computercraft.shared.util;
 
+import net.minecraft.item.DyeColor;
 import net.minecraft.item.crafting.ArmorDyeRecipe;
 
 /**
@@ -33,6 +34,12 @@ public class ColourTracker
         addColour( (int) (r * 255), (int) (g * 255), (int) (b * 255) );
     }
 
+    public void addColour( DyeColor dye )
+    {
+        Colour colour = Colour.VALUES[15 - dye.getId()];
+        addColour( colour.getR(), colour.getG(), colour.getB() );
+    }
+
     public boolean hasColour()
     {
         return count > 0;

From cc5e972cfc508896f4e86df0159edccc36cba3c4 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 6 Jan 2021 22:39:26 +0000
Subject: [PATCH 412/711] Bump version to 1.95.1

Will actually release tomorrow - it's getting quite late right now.
---
 build.gradle                                  |  2 +-
 gradle.properties                             |  2 +-
 .../computercraft/lua/rom/help/changelog.txt  |  8 ++++++
 .../computercraft/lua/rom/help/whatsnew.txt   | 26 +++++--------------
 4 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/build.gradle b/build.gradle
index 01d0ee2f0..ddf6d0b2e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,7 +9,7 @@ buildscript {
     }
     dependencies {
         classpath 'com.google.code.gson:gson:2.8.1'
-        classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.187'
+        classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.190'
         classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
         classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
     }
diff --git a/gradle.properties b/gradle.properties
index 147cc11de..7ab23e64e 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,5 @@
 # Mod properties
-mod_version=1.95.0
+mod_version=1.95.1
 
 # Minecraft properties (update mods.toml when changing)
 mc_version=1.15.2
diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
index 52789f9d8..80a5bfdd2 100644
--- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
+++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt
@@ -1,3 +1,11 @@
+# New features in CC: Tweaked 1.95.1
+
+Several bug fixes:
+* Command computers now drop items again.
+* Restore crafting of disks with dyes.
+* Fix CraftTweaker integrations for damageable items.
+* Catch reflection errors in the generic peripheral system, resolving crashes with Botania.
+
 # New features in CC: Tweaked 1.95.0
 
 * Optimise the paint program's initial render.
diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt
index 477a8bbe1..4cc63fb78 100644
--- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt
+++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt
@@ -1,23 +1,9 @@
-New features in CC: Tweaked 1.95.0
+New features in CC: Tweaked 1.95.1
 
-* Optimise the paint program's initial render.
-* Several documentation improvments (Gibbo3771, MCJack123).
-* `fs.combine` now accepts multiple arguments.
-* Add a setting (`bios.strict_globals`) to error when accidentally declaring a global. (Lupus590).
-* Add an improved help viewer which allows scrolling up and down (MCJack123).
-* Add `cc.strings` module, with utilities for wrapping text (Lupus590).
-* The `clear` program now allows resetting the palette too (Luca0208).
-
-And several bug fixes:
-* Fix memory leak in generic peripherals.
-* Fix crash when a turtle is broken while being ticked.
-* `textutils.*tabulate` now accepts strings _or_ numbers.
-* We now deny _all_ local IPs, using the magic `$private` host. Previously the IPv6 loopback interface was not blocked.
-* Fix crash when rendering monitors if the block has not yet been synced. You will need to regenerate the config file to apply this change.
-* `read` now supports numpad enter (TheWireLord)
-* Correctly handle HTTP redirects to URLs containing escape characters.
-* Fix integer overflow in `os.epoch`.
-* Allow using pickaxes (and other items) for turtle upgrades which have mod-specific NBT.
-* Fix duplicate turtle/pocket upgrade recipes appearing in JEI.
+Several bug fixes:
+* Command computers now drop items again.
+* Restore crafting of disks with dyes.
+* Fix CraftTweaker integrations for damageable items.
+* Catch reflection errors in the generic peripheral system, resolving crashes with Botania.
 
 Type "help changelog" to see the full version history.

From 41226371f3b5fd35f48b6d39c2e8e0c277125b21 Mon Sep 17 00:00:00 2001
From: Lupus590 
Date: Thu, 7 Jan 2021 16:36:25 +0000
Subject: [PATCH 413/711] Add isReadOnly to fs.attributes (#639)

---
 src/main/java/dan200/computercraft/core/apis/FSAPI.java | 7 ++++---
 src/test/resources/test-rom/spec/apis/fs_spec.lua       | 4 ++--
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java
index 6ae65f62a..fada96ecd 100644
--- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java
+++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java
@@ -471,8 +471,8 @@ public class FSAPI implements ILuaAPI
     /**
      * Get attributes about a specific file or folder.
      *
-     * The returned attributes table contains information about the size of the file, whether it is a directory, and
-     * when it was created and last modified.
+     * The returned attributes table contains information about the size of the file, whether it is a directory,
+     * when it was created and last modified, and whether it is read only.
      *
      * The creation and modification times are given as the number of milliseconds since the UNIX epoch. This may be
      * given to {@link OSAPI#date} in order to convert it to more usable form.
@@ -480,7 +480,7 @@ public class FSAPI implements ILuaAPI
      * @param path The path to get attributes for.
      * @return The resulting attributes.
      * @throws LuaException If the path does not exist.
-     * @cc.treturn { size = number, isDir = boolean, created = number, modified = number } The resulting attributes.
+     * @cc.treturn { size = number, isDir = boolean, isReadOnly = boolean, created = number, modified = number } The resulting attributes.
      * @see #getSize If you only care about the file's size.
      * @see #isDir If you only care whether a path is a directory or not.
      */
@@ -496,6 +496,7 @@ public class FSAPI implements ILuaAPI
             result.put( "created", getFileTime( attributes.creationTime() ) );
             result.put( "size", attributes.isDirectory() ? 0 : attributes.size() );
             result.put( "isDir", attributes.isDirectory() );
+            result.put( "isReadOnly", fileSystem.isReadOnly( path ) );
             return result;
         }
         catch( FileSystemException e )
diff --git a/src/test/resources/test-rom/spec/apis/fs_spec.lua b/src/test/resources/test-rom/spec/apis/fs_spec.lua
index 9a861af34..32503598e 100644
--- a/src/test/resources/test-rom/spec/apis/fs_spec.lua
+++ b/src/test/resources/test-rom/spec/apis/fs_spec.lua
@@ -194,7 +194,7 @@ describe("The fs library", function()
         end)
 
         it("returns information about read-only mounts", function()
-            expect(fs.attributes("rom")):matches { isDir = true, size = 0 }
+            expect(fs.attributes("rom")):matches { isDir = true, size = 0, isReadOnly = true }
         end)
 
         it("returns information about files", function()
@@ -206,7 +206,7 @@ describe("The fs library", function()
             h.close()
 
             local attributes = fs.attributes("tmp/basic-file")
-            expect(attributes):matches { isDir = false, size = 25 }
+            expect(attributes):matches { isDir = false, size = 25, isReadOnly = false }
 
             if attributes.created - now >= 1000 then
                 fail(("Expected created time (%d) to be within 1000ms of now (%d"):format(attributes.created, now))

From b2e54014869fac4b819b01b6c24e550ca113ce8a Mon Sep 17 00:00:00 2001
From: Wojbie 
Date: Thu, 7 Jan 2021 22:41:04 +0100
Subject: [PATCH 414/711] Added Numpad Enter Support in rom lua programs.
 (#657)

---
 .../resources/data/computercraft/lua/rom/programs/edit.lua    | 4 ++--
 .../computercraft/lua/rom/programs/fun/advanced/paint.lua     | 2 +-
 .../data/computercraft/lua/rom/programs/fun/worm.lua          | 4 ++--
 .../data/computercraft/lua/rom/programs/pocket/falling.lua    | 4 ++--
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
index 8f0af9356..8656798df 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
@@ -667,8 +667,8 @@ while bRunning do
                 end
             end
 
-        elseif param == keys.enter then
-            -- Enter
+        elseif param == keys.enter or param == keys.numPadEnter then
+            -- Enter/Numpad Enter
             if not bMenu and not bReadOnly then
                 -- Newline
                 local sLine = tLines[y]
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua
index 862bc2afe..ad1f96b34 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/paint.lua
@@ -350,7 +350,7 @@ local function accessMenu()
                     selection = #mChoices
                 end
 
-            elseif key == keys.enter then
+            elseif key == keys.enter or key == keys.numPadEnter then
                 -- Select an option
                 return menu_choices[mChoices[selection]]()
             elseif key == keys.leftCtrl or keys == keys.rightCtrl then
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua b/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua
index eaaa54869..9d98ac2fd 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/fun/worm.lua
@@ -199,8 +199,8 @@ while true do
             drawMenu()
             drawFrontend()
         end
-    elseif key == keys.enter then
-        -- Enter
+    elseif key == keys.enter or key == keys.numPadEnter then
+        -- Enter/Numpad Enter
         break
     end
 end
diff --git a/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua b/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua
index deb01c380..62e8e7eae 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/pocket/falling.lua
@@ -546,7 +546,7 @@ local function playGame()
   msgBox("Game Over!")
   while true do
     local _, k = os.pullEvent("key")
-    if k == keys.space or k == keys.enter then
+    if k == keys.space or k == keys.enter or k == keys.numPadEnter then
       break
     end
   end
@@ -627,7 +627,7 @@ local function runMenu()
       elseif key == keys.down or key == keys.s then
         selected = selected % 2 + 1
         drawMenu()
-      elseif key == keys.enter or key == keys.space then
+      elseif key == keys.enter or key == keys.numPadEnter or key == keys.space then
         break --begin play!
       end
     end

From 2232f025b8012c8b7123bb1fa72cd7678f129ac2 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Fri, 8 Jan 2021 16:16:56 +0000
Subject: [PATCH 415/711] Make CC:T work as a non-root project

---
 build.gradle                     | 14 +++++++-------
 config/checkstyle/checkstyle.xml |  2 +-
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/build.gradle b/build.gradle
index ddf6d0b2e..e22fdfdc3 100644
--- a/build.gradle
+++ b/build.gradle
@@ -50,7 +50,7 @@ minecraft {
         }
 
         server {
-            workingDirectory project.file("run/server-${mc_version}")
+            workingDirectory project.file("run/server")
             property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP'
             property 'forge.logging.console.level', 'debug'
 
@@ -388,14 +388,14 @@ license {
     it.configure {
         include("**/*.java")
         exclude("dan200/computercraft/api/**")
-        header rootProject.file('config/license/main.txt')
+        header file('config/license/main.txt')
     }
 }
 
 [licenseTest, licenseFormatTest].forEach {
     it.configure {
         include("**/*.java")
-        header rootProject.file('config/license/main.txt')
+        header file('config/license/main.txt')
     }
 }
 
@@ -412,7 +412,7 @@ task licenseFormatAPI(type: LicenseFormat);
     it.configure {
         source = sourceSets.main.java
         include("dan200/computercraft/api/**")
-        header rootProject.file('config/license/api.txt')
+        header file('config/license/api.txt')
     }
 }
 
@@ -430,7 +430,7 @@ task checkRelease {
         def ok = true
 
         // Check we're targetting the current version
-        def whatsnew = new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt").readLines()
+        def whatsnew = new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt").readLines()
         if (whatsnew[0] != "New features in CC: Tweaked $mod_version") {
             ok = false
             project.logger.error("Expected `whatsnew.txt' to target $mod_version.")
@@ -447,7 +447,7 @@ task checkRelease {
 
         // Check whatsnew and changelog match.
         def versionChangelog = "# " + whatsnew.join("\n")
-        def changelog = new File("src/main/resources/data/computercraft/lua/rom/help/changelog.txt").getText()
+        def changelog = new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/changelog.txt").getText()
         if (!changelog.startsWith(versionChangelog)) {
             ok = false
             project.logger.error("whatsnew and changelog are not in sync")
@@ -535,7 +535,7 @@ githubRelease {
     tagName "v${mc_version}-${mod_version}"
     releaseName "[${mc_version}] ${mod_version}"
     body {
-        "## " + new File("src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
+        "## " + new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
             .readLines()
             .takeWhile { it != 'Type "help changelog" to see the full version history.' }
             .join("\n").trim()
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 03959f78e..89de6f153 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -7,7 +7,7 @@
     
 
     
-        
+	
     
 
     

From 247c05305d106af430fcdaee41371a152bf7c38c Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Fri, 8 Jan 2021 17:49:31 +0000
Subject: [PATCH 416/711] Fix problem with RepeatArgumentType

The whole "flatten" thing can probably be dropped TBH. We don't use it
anywhere. Fixes #661
---
 .../shared/command/arguments/RepeatArgumentType.java            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java
index d3057a21b..f3b016d61 100644
--- a/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java
+++ b/src/main/java/dan200/computercraft/shared/command/arguments/RepeatArgumentType.java
@@ -56,7 +56,7 @@ public final class RepeatArgumentType implements ArgumentType>
 
     public static  RepeatArgumentType some( ArgumentType appender, SimpleCommandExceptionType missing )
     {
-        return new RepeatArgumentType<>( appender, List::add, true, missing );
+        return new RepeatArgumentType<>( appender, List::add, false, missing );
     }
 
     public static  RepeatArgumentType> someFlat( ArgumentType> appender, SimpleCommandExceptionType missing )

From c864576619751077a0d8ac1a18123e14b095ec03 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 18:30:07 +0000
Subject: [PATCH 417/711] Fix impostor recipes for disks

Well, this is embarrassing. See #652
---
 src/generated/resources/data/computercraft/recipes/disk_1.json | 2 +-
 .../resources/data/computercraft/recipes/disk_10.json          | 2 +-
 .../resources/data/computercraft/recipes/disk_11.json          | 2 +-
 .../resources/data/computercraft/recipes/disk_12.json          | 2 +-
 .../resources/data/computercraft/recipes/disk_13.json          | 2 +-
 .../resources/data/computercraft/recipes/disk_14.json          | 2 +-
 .../resources/data/computercraft/recipes/disk_15.json          | 2 +-
 .../resources/data/computercraft/recipes/disk_16.json          | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_2.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_3.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_4.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_5.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_6.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_7.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_8.json | 2 +-
 src/generated/resources/data/computercraft/recipes/disk_9.json | 2 +-
 src/main/java/dan200/computercraft/data/Recipes.java           | 3 ++-
 17 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/src/generated/resources/data/computercraft/recipes/disk_1.json b/src/generated/resources/data/computercraft/recipes/disk_1.json
index 66ce73a90..f062cd66f 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_1.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_1.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:1118481}"
+    "nbt": "{Color:1118481}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_10.json b/src/generated/resources/data/computercraft/recipes/disk_10.json
index 9c064f0fb..45771c169 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_10.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_10.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:15905484}"
+    "nbt": "{Color:15905484}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_11.json b/src/generated/resources/data/computercraft/recipes/disk_11.json
index bfd6b21dc..d86dbf599 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_11.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_11.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:8375321}"
+    "nbt": "{Color:8375321}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_12.json b/src/generated/resources/data/computercraft/recipes/disk_12.json
index 7fa0ff4be..b1306ad27 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_12.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_12.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:14605932}"
+    "nbt": "{Color:14605932}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_13.json b/src/generated/resources/data/computercraft/recipes/disk_13.json
index ab237e75c..3305efea1 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_13.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_13.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:10072818}"
+    "nbt": "{Color:10072818}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_14.json b/src/generated/resources/data/computercraft/recipes/disk_14.json
index 458ad2a71..d5ed6873b 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_14.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_14.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:15040472}"
+    "nbt": "{Color:15040472}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_15.json b/src/generated/resources/data/computercraft/recipes/disk_15.json
index 35147838e..e296c592a 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_15.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_15.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:15905331}"
+    "nbt": "{Color:15905331}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_16.json b/src/generated/resources/data/computercraft/recipes/disk_16.json
index 1f86b573a..e62f6c34f 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_16.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_16.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:15790320}"
+    "nbt": "{Color:15790320}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_2.json b/src/generated/resources/data/computercraft/recipes/disk_2.json
index 40f55f5a4..ee4f4ba1d 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_2.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_2.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:13388876}"
+    "nbt": "{Color:13388876}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_3.json b/src/generated/resources/data/computercraft/recipes/disk_3.json
index 5ed4b4d72..c8a8fae24 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_3.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_3.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:5744206}"
+    "nbt": "{Color:5744206}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_4.json b/src/generated/resources/data/computercraft/recipes/disk_4.json
index ecc80c9e2..109934949 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_4.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_4.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:8349260}"
+    "nbt": "{Color:8349260}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_5.json b/src/generated/resources/data/computercraft/recipes/disk_5.json
index 94beac68a..53b5186b4 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_5.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_5.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:3368652}"
+    "nbt": "{Color:3368652}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_6.json b/src/generated/resources/data/computercraft/recipes/disk_6.json
index 0416fba6e..b45ca974c 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_6.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_6.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:11691749}"
+    "nbt": "{Color:11691749}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_7.json b/src/generated/resources/data/computercraft/recipes/disk_7.json
index 99f64b544..1fb41dea8 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_7.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_7.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:5020082}"
+    "nbt": "{Color:5020082}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_8.json b/src/generated/resources/data/computercraft/recipes/disk_8.json
index be1b7fea9..8043bf87f 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_8.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_8.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:10066329}"
+    "nbt": "{Color:10066329}"
   }
 }
\ No newline at end of file
diff --git a/src/generated/resources/data/computercraft/recipes/disk_9.json b/src/generated/resources/data/computercraft/recipes/disk_9.json
index 48620dbdd..c9593d5f2 100644
--- a/src/generated/resources/data/computercraft/recipes/disk_9.json
+++ b/src/generated/resources/data/computercraft/recipes/disk_9.json
@@ -14,6 +14,6 @@
   ],
   "result": {
     "item": "computercraft:disk",
-    "nbt": "{color:5000268}"
+    "nbt": "{Color:5000268}"
   }
 }
\ No newline at end of file
diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java
index c9d538b17..6c1b62dae 100644
--- a/src/main/java/dan200/computercraft/data/Recipes.java
+++ b/src/main/java/dan200/computercraft/data/Recipes.java
@@ -10,6 +10,7 @@ import dan200.computercraft.data.Tags.CCTags;
 import dan200.computercraft.shared.PocketUpgrades;
 import dan200.computercraft.shared.Registry;
 import dan200.computercraft.shared.TurtleUpgrades;
+import dan200.computercraft.shared.common.IColouredItem;
 import dan200.computercraft.shared.computer.core.ComputerFamily;
 import dan200.computercraft.shared.pocket.items.PocketComputerItemFactory;
 import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
@@ -64,7 +65,7 @@ public class Recipes extends RecipeProvider
                 .addCriterion( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE.get() ) )
                 .build( RecipeWrapper.wrap(
                     ImpostorShapelessRecipe.SERIALIZER, add,
-                    x -> x.putInt( "color", colour.getHex() )
+                    x -> x.putInt( IColouredItem.NBT_COLOUR, colour.getHex() )
                 ), new ResourceLocation( ComputerCraft.MOD_ID, "disk_" + (colour.ordinal() + 1) ) );
         }
     }

From 7b476cb24b1e173d03a42ba79bea5d0acc0f40b0 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 18:49:40 +0000
Subject: [PATCH 418/711] Remove usage of deprecated event constructor

This requires a Forge bump, but probably no harm in doing so anyway.
We're on an ancient (2nd Nov) version. Fixes #665.
---
 gradle.properties                                               | 2 +-
 .../computercraft/shared/turtle/core/TurtlePlaceCommand.java    | 2 +-
 src/main/resources/META-INF/mods.toml                           | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/gradle.properties b/gradle.properties
index 1f603ff9c..d17e38609 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,5 +3,5 @@ mod_version=1.95.1
 
 # Minecraft properties (update mods.toml when changing)
 mc_version=1.16.4
-forge_version=35.0.1
+forge_version=35.1.16
 mappings_version=20201028-1.16.3
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
index d7932fca7..bf1124fb6 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
@@ -353,7 +353,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
         TileEntity existingTile = turtle.getWorld().getTileEntity( position );
 
         // See PlayerInteractionManager.processRightClickBlock
-        PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, Hand.MAIN_HAND, position, side );
+        PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, Hand.MAIN_HAND, position, hit );
         if( !event.isCanceled() )
         {
             if( item.onItemUseFirst( stack, context ).isSuccessOrConsume() )
diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml
index 49042e1d8..ee8b92f44 100644
--- a/src/main/resources/META-INF/mods.toml
+++ b/src/main/resources/META-INF/mods.toml
@@ -20,6 +20,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
 [[dependencies.computercraft]]
     modId="forge"
     mandatory=true
-    versionRange="[35.0.1,36)"
+    versionRange="[35.1.16,36)"
     ordering="NONE"
     side="BOTH"

From 34b5ede326e913676b6f538408e3f82504159c76 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 19:22:58 +0000
Subject: [PATCH 419/711] Switch to Mojang mappings

ForgeGradle (probably sensibly) yells at me about doing this. However:
 - There's a reasonable number of mods doing this, which establishes
   some optimistic precedent.
 - The licence update in Aug 2020 now allows you to use them for
   "development purposes". I guess source code counts??
 - I'm fairly sure this is also compatible with the CCPL - there's an
   exception for Minecraft code.

The main motivation for this is to make the Fabric port a little
easier. Hopefully folks (maybe me in the future, we'll see) will no
longer have to deal with mapping hell when merging - only mod loader
hell.
---
 build.gradle                                  |   2 +-
 gradle.properties                             |   1 -
 .../computercraft/ComputerCraftAPIImpl.java   |   6 +-
 .../api/client/TransformedModel.java          |   2 +-
 .../api/pocket/AbstractPocketUpgrade.java     |   2 +-
 .../api/turtle/AbstractTurtleUpgrade.java     |   2 +-
 .../computercraft/client/ClientRegistry.java  |   8 +-
 .../client/ClientTableFormatter.java          |  18 +-
 .../client/gui/FixedWidthFontRenderer.java    |  66 ++--
 .../computercraft/client/gui/GuiComputer.java |  16 +-
 .../client/gui/GuiDiskDrive.java              |  16 +-
 .../computercraft/client/gui/GuiPrinter.java  |  18 +-
 .../computercraft/client/gui/GuiPrintout.java |  14 +-
 .../computercraft/client/gui/GuiTurtle.java   |  22 +-
 .../client/gui/widgets/WidgetTerminal.java    |   4 +-
 .../proxy/ComputerCraftProxyClient.java       |  24 +-
 .../client/render/CableHighlightRenderer.java |  26 +-
 .../client/render/ComputerBorderRenderer.java |  12 +-
 .../client/render/ItemMapLikeRenderer.java    |  42 +--
 .../client/render/ItemPocketRenderer.java     |  28 +-
 .../client/render/ItemPrintoutRenderer.java   |   6 +-
 .../render/MonitorHighlightRenderer.java      |  30 +-
 .../render/MonitorTextureBufferShader.java    |  32 +-
 .../client/render/PrintoutRenderer.java       |  28 +-
 .../render/TileEntityMonitorRenderer.java     |  66 ++--
 .../render/TileEntityTurtleRenderer.java      |  46 +--
 .../client/render/TurtleModelLoader.java      |   6 +-
 .../client/render/TurtleMultiModel.java       |  20 +-
 .../client/render/TurtlePlayerRenderer.java   |   2 +-
 .../client/render/TurtleSmartItemModel.java   |  26 +-
 .../core/computer/Environment.java            |   2 +
 .../core/filesystem/ResourceMount.java        |   4 +-
 .../data/BlockModelProvider.java              |  14 +-
 .../computercraft/data/LootTableProvider.java |  10 +-
 .../dan200/computercraft/data/LootTables.java |  30 +-
 .../computercraft/data/RecipeWrapper.java     |  20 +-
 .../dan200/computercraft/data/Recipes.java    | 314 +++++++++---------
 .../java/dan200/computercraft/data/Tags.java  |  10 +-
 .../computercraft/shared/BundledRedstone.java |   4 +-
 .../dan200/computercraft/shared/Config.java   |   3 +
 .../computercraft/shared/Peripherals.java     |   4 +-
 .../dan200/computercraft/shared/Registry.java |  32 +-
 .../shared/TurtlePermissions.java             |   4 +-
 .../shared/command/CommandComputerCraft.java  |  38 +--
 .../shared/command/CommandCopy.java           |   4 +-
 .../shared/command/CommandUtils.java          |   2 +-
 .../shared/command/UserLevel.java             |   4 +-
 .../arguments/ComputersArgumentType.java      |   6 +-
 .../command/arguments/RepeatArgumentType.java |  10 +-
 .../builder/HelpingArgumentBuilder.java       |  22 +-
 .../shared/command/text/ChatHelpers.java      |   2 +-
 .../command/text/ServerTableFormatter.java    |   2 +-
 .../shared/command/text/TableFormatter.java   |  16 +-
 .../shared/common/BlockGeneric.java           |  20 +-
 .../shared/common/ColourableRecipe.java       |  12 +-
 .../shared/common/ContainerHeldItem.java      |   8 +-
 .../shared/common/TileGeneric.java            |  18 +-
 .../shared/computer/apis/CommandAPI.java      |  24 +-
 .../shared/computer/blocks/BlockComputer.java |  12 +-
 .../computer/blocks/BlockComputerBase.java    |  52 +--
 .../computer/blocks/TileCommandComputer.java  |  22 +-
 .../shared/computer/blocks/TileComputer.java  |  10 +-
 .../computer/blocks/TileComputerBase.java     |  66 ++--
 .../shared/computer/core/ComputerState.java   |   2 +-
 .../shared/computer/core/ServerComputer.java  |   2 +-
 .../inventory/ContainerComputerBase.java      |   8 +-
 .../shared/computer/items/IComputerItem.java  |   2 +-
 .../shared/computer/items/ItemComputer.java   |   6 +-
 .../computer/items/ItemComputerBase.java      |  10 +-
 .../recipe/ComputerConvertRecipe.java         |  10 +-
 .../computer/recipe/ComputerFamilyRecipe.java |  26 +-
 .../recipe/ComputerUpgradeRecipe.java         |   2 +
 .../data/BlockNamedEntityLootCondition.java   |   6 +-
 .../data/HasComputerIdLootCondition.java      |   6 +-
 .../data/PlayerCreativeLootCondition.java     |   8 +-
 .../integration/jei/RecipeResolver.java       |  28 +-
 .../shared/media/items/ItemDisk.java          |  16 +-
 .../shared/media/items/ItemPrintout.java      |  12 +-
 .../shared/media/items/ItemTreasureDisk.java  |   6 +-
 .../shared/media/items/RecordMedia.java       |   4 +-
 .../shared/media/recipes/DiskRecipe.java      |  18 +-
 .../shared/media/recipes/PrintoutRecipe.java  |  16 +-
 .../shared/network/NetworkHandler.java        |   2 +-
 .../client/ChatTableClientMessage.java        |   8 +-
 .../client/ComputerDataClientMessage.java     |   8 +-
 .../network/client/MonitorClientMessage.java  |   4 +-
 .../client/PlayRecordClientMessage.java       |   8 +-
 .../container/ComputerContainerData.java      |   4 +-
 .../container/HeldItemContainerData.java      |   4 +-
 .../server/ComputerActionServerMessage.java   |   4 +-
 .../server/QueueEventServerMessage.java       |   8 +-
 .../commandblock/CommandBlockPeripheral.java  |  10 +-
 .../peripheral/diskdrive/BlockDiskDrive.java  |  32 +-
 .../diskdrive/ContainerDiskDrive.java         |  20 +-
 .../peripheral/diskdrive/DiskDriveState.java  |   2 +-
 .../peripheral/diskdrive/TileDiskDrive.java   |  92 ++---
 .../generic/GenericPeripheralProvider.java    |   2 +-
 .../peripheral/generic/data/BlockData.java    |   3 +-
 .../peripheral/generic/data/ItemData.java     |  14 +-
 .../shared/peripheral/modem/ModemShapes.java  |  14 +-
 .../peripheral/modem/wired/BlockCable.java    | 106 +++---
 .../modem/wired/BlockWiredModemFull.java      |  10 +-
 .../modem/wired/CableModemVariant.java        |   6 +-
 .../peripheral/modem/wired/CableShapes.java   |  24 +-
 .../modem/wired/ItemBlockCable.java           |  54 +--
 .../peripheral/modem/wired/TileCable.java     |  76 ++---
 .../modem/wired/TileWiredModemFull.java       |  54 +--
 .../wired/WiredModemLocalPeripheral.java      |   2 +-
 .../modem/wireless/BlockWirelessModem.java    |  34 +-
 .../modem/wireless/TileWirelessModem.java     |  16 +-
 .../wireless/WirelessModemPeripheral.java     |   2 +-
 .../modem/wireless/WirelessNetwork.java       |   2 +-
 .../peripheral/monitor/BlockMonitor.java      |  28 +-
 .../peripheral/monitor/ClientMonitor.java     |  12 +-
 .../peripheral/monitor/MonitorEdgeState.java  |   4 +-
 .../peripheral/monitor/MonitorWatcher.java    |  10 +-
 .../peripheral/monitor/TileMonitor.java       |  62 ++--
 .../peripheral/printer/BlockPrinter.java      |  34 +-
 .../peripheral/printer/ContainerPrinter.java  |  24 +-
 .../peripheral/printer/TilePrinter.java       |  52 +--
 .../peripheral/speaker/BlockSpeaker.java      |  10 +-
 .../peripheral/speaker/SpeakerPeripheral.java |   6 +-
 .../peripheral/speaker/TileSpeaker.java       |   4 +-
 .../shared/pocket/apis/PocketAPI.java         |  12 +-
 .../pocket/core/PocketServerComputer.java     |  10 +-
 .../inventory/ContainerPocketComputer.java    |   4 +-
 .../pocket/items/ItemPocketComputer.java      |  44 +--
 .../pocket/peripherals/PocketModem.java       |   2 +-
 .../pocket/peripherals/PocketSpeaker.java     |   2 +-
 .../recipes/PocketComputerUpgradeRecipe.java  |  12 +-
 .../proxy/ComputerCraftProxyCommon.java       |  32 +-
 .../shared/turtle/apis/TurtleAPI.java         |   6 +-
 .../shared/turtle/blocks/BlockTurtle.java     |  34 +-
 .../shared/turtle/blocks/TileTurtle.java      |  84 ++---
 .../shared/turtle/core/TurtleBrain.java       |  84 ++---
 .../turtle/core/TurtleCompareCommand.java     |   8 +-
 .../turtle/core/TurtleCompareToCommand.java   |   4 +-
 .../turtle/core/TurtleDetectCommand.java      |   4 +-
 .../shared/turtle/core/TurtleDropCommand.java |   4 +-
 .../turtle/core/TurtleInspectCommand.java     |   2 +-
 .../shared/turtle/core/TurtleMoveCommand.java |  26 +-
 .../turtle/core/TurtlePlaceCommand.java       | 104 +++---
 .../shared/turtle/core/TurtlePlayer.java      |  58 ++--
 .../turtle/core/TurtleRefuelCommand.java      |   2 +-
 .../shared/turtle/core/TurtleSuckCommand.java |   6 +-
 .../shared/turtle/core/TurtleTurnCommand.java |   4 +-
 .../turtle/inventory/ContainerTurtle.java     |  18 +-
 .../shared/turtle/items/ItemTurtle.java       |  12 +-
 .../shared/turtle/recipes/TurtleRecipe.java   |   2 +
 .../turtle/recipes/TurtleUpgradeRecipe.java   |  12 +-
 .../shared/turtle/upgrades/TurtleHoe.java     |   8 +-
 .../upgrades/TurtleInventoryCrafting.java     |  60 ++--
 .../shared/turtle/upgrades/TurtleModem.java   |   2 +-
 .../shared/turtle/upgrades/TurtleShovel.java  |  12 +-
 .../shared/turtle/upgrades/TurtleSword.java   |   4 +-
 .../shared/turtle/upgrades/TurtleTool.java    |  36 +-
 .../shared/util/CreativeTabMain.java          |   2 +-
 .../shared/util/DefaultInventory.java         |   8 +-
 .../shared/util/DefaultSidedInventory.java    |   6 +-
 .../shared/util/DirectionUtil.java            |   4 +-
 .../shared/util/DropConsumer.java             |   8 +-
 .../shared/util/FakeNetHandler.java           | 110 +++---
 .../shared/util/FixedPointTileEntityType.java |   2 +-
 .../computercraft/shared/util/IDAssigner.java |   2 +-
 .../shared/util/ImpostorRecipe.java           |  26 +-
 .../shared/util/ImpostorShapelessRecipe.java  |  30 +-
 .../shared/util/InventoryDelegate.java        |  56 ++--
 .../shared/util/InventoryUtil.java            |  12 +-
 .../computercraft/shared/util/NBTUtil.java    |  18 +-
 .../computercraft/shared/util/RecipeUtil.java |  10 +-
 .../shared/util/RedstoneUtil.java             |   4 +-
 .../shared/util/SingleIntArray.java           |   2 +-
 .../shared/util/TickScheduler.java            |  12 +-
 .../shared/util/ValidatingSlot.java           |   2 +-
 .../shared/util/WaterloggableHelpers.java     |   8 +-
 .../computercraft/shared/util/WorldUtil.java  |  36 +-
 .../core/filesystem/ResourceMountTest.java    |   2 +-
 .../shared/wired/NetworkTest.java             |   2 +-
 178 files changed, 1789 insertions(+), 1738 deletions(-)

diff --git a/build.gradle b/build.gradle
index e22fdfdc3..559e9b54c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -75,7 +75,7 @@ minecraft {
         }
     }
 
-    mappings channel: 'snapshot', version: "${mappings_version}".toString()
+    mappings channel: 'official', version: project.mc_version
 
     accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg')
 }
diff --git a/gradle.properties b/gradle.properties
index 7ab23e64e..f9ef4fecd 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -4,4 +4,3 @@ mod_version=1.95.1
 # Minecraft properties (update mods.toml when changing)
 mc_version=1.15.2
 forge_version=31.1.41
-mappings_version=20200429-1.15.1
diff --git a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java
index 6b6db770a..116b3135b 100644
--- a/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java
+++ b/src/main/java/dan200/computercraft/ComputerCraftAPIImpl.java
@@ -54,7 +54,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
 
     public static InputStream getResourceFile( String domain, String subPath )
     {
-        IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
+        IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResources();
         try
         {
             return manager.getResource( new ResourceLocation( domain, subPath ) ).getInputStream();
@@ -97,7 +97,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
     @Override
     public IMount createResourceMount( @Nonnull String domain, @Nonnull String subPath )
     {
-        IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResourceManager();
+        IReloadableResourceManager manager = ServerLifecycleHooks.getCurrentServer().getResources();
         ResourceMount mount = ResourceMount.get( domain, subPath, manager );
         return mount.exists( "" ) ? mount : null;
     }
@@ -162,7 +162,7 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
     @Override
     public LazyOptional getWiredElementAt( @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction side )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         return tile == null ? LazyOptional.empty() : tile.getCapability( CAPABILITY_WIRED_ELEMENT, side );
     }
 }
diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java
index 40b2281fd..a130d27a8 100644
--- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java
+++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java
@@ -43,7 +43,7 @@ public final class TransformedModel
 
     public static TransformedModel of( @Nonnull ItemStack item, @Nonnull TransformationMatrix transform )
     {
-        IBakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getItemModel( item );
+        IBakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel( item );
         return new TransformedModel( model, transform );
     }
 
diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java
index 75f64d2a0..6578245cc 100644
--- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java
+++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java
@@ -35,7 +35,7 @@ public abstract class AbstractPocketUpgrade implements IPocketUpgrade
 
     protected AbstractPocketUpgrade( ResourceLocation id, NonNullSupplier item )
     {
-        this( id, Util.makeTranslationKey( "upgrade", id ) + ".adjective", item );
+        this( id, Util.makeDescriptionId( "upgrade", id ) + ".adjective", item );
     }
 
     protected AbstractPocketUpgrade( ResourceLocation id, String adjective, ItemStack stack )
diff --git a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java
index 2aa7af918..72490953a 100644
--- a/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java
+++ b/src/main/java/dan200/computercraft/api/turtle/AbstractTurtleUpgrade.java
@@ -37,7 +37,7 @@ public abstract class AbstractTurtleUpgrade implements ITurtleUpgrade
 
     protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, NonNullSupplier stack )
     {
-        this( id, type, Util.makeTranslationKey( "upgrade", id ) + ".adjective", stack );
+        this( id, type, Util.makeDescriptionId( "upgrade", id ) + ".adjective", stack );
     }
 
     protected AbstractTurtleUpgrade( ResourceLocation id, TurtleUpgradeType type, String adjective, ItemStack stack )
diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java
index 381dc91ce..00bc4ea0c 100644
--- a/src/main/java/dan200/computercraft/client/ClientRegistry.java
+++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java
@@ -78,7 +78,7 @@ public final class ClientRegistry
     @SubscribeEvent
     public static void onTextureStitchEvent( TextureStitchEvent.Pre event )
     {
-        if( !event.getMap().getTextureLocation().equals( PlayerContainer.LOCATION_BLOCKS_TEXTURE ) ) return;
+        if( !event.getMap().location().equals( PlayerContainer.BLOCK_ATLAS ) ) return;
 
         for( String extra : EXTRA_TEXTURES )
         {
@@ -96,10 +96,10 @@ public final class ClientRegistry
         for( String modelName : EXTRA_MODELS )
         {
             ResourceLocation location = new ResourceLocation( ComputerCraft.MOD_ID, "item/" + modelName );
-            IUnbakedModel model = loader.getUnbakedModel( location );
-            model.getTextures( loader::getUnbakedModel, new HashSet<>() );
+            IUnbakedModel model = loader.getModel( location );
+            model.getMaterials( loader::getModel, new HashSet<>() );
 
-            IBakedModel baked = model.bakeModel( loader, ModelLoader.defaultTextureGetter(), SimpleModelTransform.IDENTITY, location );
+            IBakedModel baked = model.bake( loader, ModelLoader.defaultTextureGetter(), SimpleModelTransform.IDENTITY, location );
             if( baked != null )
             {
                 registry.put( new ModelResourceLocation( new ResourceLocation( ComputerCraft.MOD_ID, modelName ), "inventory" ), baked );
diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java
index 689ce251a..164c0f70e 100644
--- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java
+++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java
@@ -29,7 +29,7 @@ public class ClientTableFormatter implements TableFormatter
 
     private static FontRenderer renderer()
     {
-        return Minecraft.getInstance().fontRenderer;
+        return Minecraft.getInstance().font;
     }
 
     @Override
@@ -41,7 +41,7 @@ public class ClientTableFormatter implements TableFormatter
 
         FontRenderer renderer = renderer();
 
-        float spaceWidth = renderer.getStringWidth( " " );
+        float spaceWidth = renderer.width( " " );
         int spaces = MathHelper.floor( extraWidth / spaceWidth );
         int extra = extraWidth - (int) (spaces * spaceWidth);
 
@@ -57,32 +57,32 @@ public class ClientTableFormatter implements TableFormatter
     @Override
     public int getWidth( ITextComponent component )
     {
-        return renderer().getStringWidth( component.getFormattedText() );
+        return renderer().width( component.getColoredString() );
     }
 
     @Override
     public void writeLine( int id, ITextComponent component )
     {
         Minecraft mc = Minecraft.getInstance();
-        NewChatGui chat = mc.ingameGUI.getChatGUI();
+        NewChatGui chat = mc.gui.getChat();
 
         // Trim the text if it goes over the allowed length
-        int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
-        List list = RenderComponentsUtil.splitText( component, maxWidth, mc.fontRenderer, false, false );
-        if( !list.isEmpty() ) chat.printChatMessageWithOptionalDeletion( list.get( 0 ), id );
+        int maxWidth = MathHelper.floor( chat.getWidth() / chat.getScale() );
+        List list = RenderComponentsUtil.wrapComponents( component, maxWidth, mc.font, false, false );
+        if( !list.isEmpty() ) chat.addMessage( list.get( 0 ), id );
     }
 
     @Override
     public int display( TableBuilder table )
     {
-        NewChatGui chat = Minecraft.getInstance().ingameGUI.getChatGUI();
+        NewChatGui chat = Minecraft.getInstance().gui.getChat();
 
         int lastHeight = lastHeights.get( table.getId() );
 
         int height = TableFormatter.super.display( table );
         lastHeights.put( table.getId(), height );
 
-        for( int i = height; i < lastHeight; i++ ) chat.deleteChatLine( i + table.getId() );
+        for( int i = height; i < lastHeight; i++ ) chat.removeById( i + table.getId() );
         return height;
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java
index 7ea6a4ad0..05444fd5b 100644
--- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java
+++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java
@@ -62,22 +62,22 @@ public final class FixedWidthFontRenderer
         int xStart = 1 + column * (FONT_WIDTH + 2);
         int yStart = 1 + row * (FONT_HEIGHT + 2);
 
-        buffer.pos( transform, x, y, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, yStart / WIDTH ).endVertex();
-        buffer.pos( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
-        buffer.pos( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
-        buffer.pos( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
-        buffer.pos( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
-        buffer.pos( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).tex( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
+        buffer.vertex( transform, x, y, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, yStart / WIDTH ).endVertex();
+        buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
+        buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
+        buffer.vertex( transform, x + FONT_WIDTH, y, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, yStart / WIDTH ).endVertex();
+        buffer.vertex( transform, x, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( xStart / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
+        buffer.vertex( transform, x + FONT_WIDTH, y + FONT_HEIGHT, 0f ).color( r, g, b, 1.0f ).uv( (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH ).endVertex();
     }
 
     private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, float r, float g, float b )
     {
-        buffer.pos( transform, x, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_START ).endVertex();
-        buffer.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex();
-        buffer.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex();
-        buffer.pos( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_START ).endVertex();
-        buffer.pos( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_START, BACKGROUND_END ).endVertex();
-        buffer.pos( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).tex( BACKGROUND_END, BACKGROUND_END ).endVertex();
+        buffer.vertex( transform, x, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_START ).endVertex();
+        buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex();
+        buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
+        buffer.vertex( transform, x + width, y, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_START ).endVertex();
+        buffer.vertex( transform, x, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_START, BACKGROUND_END ).endVertex();
+        buffer.vertex( transform, x + width, y + height, 0 ).color( r, g, b, 1.0f ).uv( BACKGROUND_END, BACKGROUND_END ).endVertex();
     }
 
     private static void drawQuad( Matrix4f transform, IVertexBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
@@ -178,9 +178,9 @@ public final class FixedWidthFontRenderer
     {
         bindFont();
 
-        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
+        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
         drawString( IDENTITY, ((IRenderTypeBuffer) renderer).getBuffer( TYPE ), x, y, text, textColour, backgroundColour, palette, greyscale, leftMarginSize, rightMarginSize );
-        renderer.finish();
+        renderer.endBatch();
     }
 
     public static void drawTerminalWithoutCursor(
@@ -263,10 +263,10 @@ public final class FixedWidthFontRenderer
     {
         bindFont();
 
-        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
+        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
         IVertexBuilder buffer = renderer.getBuffer( TYPE );
         drawTerminal( transform, buffer, x, y, terminal, greyscale, topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize );
-        renderer.finish( TYPE );
+        renderer.endBatch( TYPE );
     }
 
     public static void drawTerminal(
@@ -287,9 +287,9 @@ public final class FixedWidthFontRenderer
     {
         bindFont();
 
-        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
+        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
         drawEmptyTerminal( transform, renderer, x, y, width, height );
-        renderer.finish();
+        renderer.endBatch();
     }
 
     public static void drawEmptyTerminal( float x, float y, float width, float height )
@@ -305,7 +305,7 @@ public final class FixedWidthFontRenderer
 
     private static void bindFont()
     {
-        Minecraft.getInstance().getTextureManager().bindTexture( FONT );
+        Minecraft.getInstance().getTextureManager().bind( FONT );
         RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP );
     }
 
@@ -315,26 +315,26 @@ public final class FixedWidthFontRenderer
 
         private static final VertexFormat FORMAT = DefaultVertexFormats.POSITION_COLOR_TEX;
 
-        static final RenderType MAIN = RenderType.makeType(
+        static final RenderType MAIN = RenderType.create(
             "terminal_font", FORMAT, GL_MODE, 1024,
             false, false, // useDelegate, needsSorting
-            RenderType.State.getBuilder()
-                .texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
-                .alpha( DEFAULT_ALPHA )
-                .lightmap( LIGHTMAP_DISABLED )
-                .writeMask( COLOR_WRITE )
-                .build( false )
+            RenderType.State.builder()
+                .setTextureState( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
+                .setAlphaState( DEFAULT_ALPHA )
+                .setLightmapState( NO_LIGHTMAP )
+                .setWriteMaskState( COLOR_WRITE )
+                .createCompositeState( false )
         );
 
-        static final RenderType BLOCKER = RenderType.makeType(
+        static final RenderType BLOCKER = RenderType.create(
             "terminal_blocker", FORMAT, GL_MODE, 256,
             false, false, // useDelegate, needsSorting
-            RenderType.State.getBuilder()
-                .texture( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
-                .alpha( DEFAULT_ALPHA )
-                .writeMask( DEPTH_WRITE )
-                .lightmap( LIGHTMAP_DISABLED )
-                .build( false )
+            RenderType.State.builder()
+                .setTextureState( new RenderState.TextureState( FONT, false, false ) ) // blur, minimap
+                .setAlphaState( DEFAULT_ALPHA )
+                .setWriteMaskState( DEPTH_WRITE )
+                .setLightmapState( NO_LIGHTMAP )
+                .createCompositeState( false )
         );
 
         private Type( String name, Runnable setup, Runnable destroy )
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java
index ad3a3cc24..4996be560 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java
@@ -74,18 +74,18 @@ public final class GuiComputer extends Containe
     @Override
     protected void init()
     {
-        minecraft.keyboardListener.enableRepeatEvents( true );
+        minecraft.keyboardHandler.setSendRepeatsToGui( true );
 
         int termPxWidth = termWidth * FixedWidthFontRenderer.FONT_WIDTH;
         int termPxHeight = termHeight * FixedWidthFontRenderer.FONT_HEIGHT;
 
-        xSize = termPxWidth + MARGIN * 2 + BORDER * 2;
-        ySize = termPxHeight + MARGIN * 2 + BORDER * 2;
+        imageWidth = termPxWidth + MARGIN * 2 + BORDER * 2;
+        imageHeight = termPxHeight + MARGIN * 2 + BORDER * 2;
 
         super.init();
 
         terminal = new WidgetTerminal( minecraft, () -> computer, termWidth, termHeight, MARGIN, MARGIN, MARGIN, MARGIN );
-        terminalWrapper = new WidgetWrapper( terminal, MARGIN + BORDER + guiLeft, MARGIN + BORDER + guiTop, termPxWidth, termPxHeight );
+        terminalWrapper = new WidgetWrapper( terminal, MARGIN + BORDER + leftPos, MARGIN + BORDER + topPos, termPxWidth, termPxHeight );
 
         children.add( terminalWrapper );
         setFocused( terminalWrapper );
@@ -97,7 +97,7 @@ public final class GuiComputer extends Containe
         super.removed();
         children.remove( terminal );
         terminal = null;
-        minecraft.keyboardListener.enableRepeatEvents( false );
+        minecraft.keyboardHandler.setSendRepeatsToGui( false );
     }
 
     @Override
@@ -120,14 +120,14 @@ public final class GuiComputer extends Containe
     }
 
     @Override
-    public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
+    public void renderBg( float partialTicks, int mouseX, int mouseY )
     {
         // Draw terminal
         terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() );
 
         // Draw a border around the terminal
         RenderSystem.color4f( 1, 1, 1, 1 );
-        minecraft.getTextureManager().bindTexture( ComputerBorderRenderer.getTexture( family ) );
+        minecraft.getTextureManager().bind( ComputerBorderRenderer.getTexture( family ) );
         ComputerBorderRenderer.render(
             terminalWrapper.getX() - MARGIN, terminalWrapper.getY() - MARGIN, getBlitOffset(),
             terminalWrapper.getWidth() + MARGIN * 2, terminalWrapper.getHeight() + MARGIN * 2
@@ -139,7 +139,7 @@ public final class GuiComputer extends Containe
     {
         renderBackground();
         super.render( mouseX, mouseY, partialTicks );
-        renderHoveredToolTip( mouseX, mouseY );
+        renderTooltip( mouseX, mouseY );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java
index f521d07d3..6b724a34a 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiDiskDrive.java
@@ -22,19 +22,19 @@ public class GuiDiskDrive extends ContainerScreen
     }
 
     @Override
-    protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY )
+    protected void renderLabels( int mouseX, int mouseY )
     {
-        String title = this.title.getFormattedText();
-        font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 );
-        font.drawString( title, 8, ySize - 96 + 2, 0x404040 );
+        String title = this.title.getColoredString();
+        font.draw( title, (imageWidth - font.width( title )) / 2.0f, 6, 0x404040 );
+        font.draw( title, 8, imageHeight - 96 + 2, 0x404040 );
     }
 
     @Override
-    protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
+    protected void renderBg( float partialTicks, int mouseX, int mouseY )
     {
         RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
-        minecraft.getTextureManager().bindTexture( BACKGROUND );
-        blit( guiLeft, guiTop, 0, 0, xSize, ySize );
+        minecraft.getTextureManager().bind( BACKGROUND );
+        blit( leftPos, topPos, 0, 0, imageWidth, imageHeight );
     }
 
     @Override
@@ -42,6 +42,6 @@ public class GuiDiskDrive extends ContainerScreen
     {
         renderBackground();
         super.render( mouseX, mouseY, partialTicks );
-        renderHoveredToolTip( mouseX, mouseY );
+        renderTooltip( mouseX, mouseY );
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java
index 6f86c09b7..2b38703ee 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiPrinter.java
@@ -23,21 +23,21 @@ public class GuiPrinter extends ContainerScreen
     }
 
     @Override
-    protected void drawGuiContainerForegroundLayer( int mouseX, int mouseY )
+    protected void renderLabels( int mouseX, int mouseY )
     {
-        String title = getTitle().getFormattedText();
-        font.drawString( title, (xSize - font.getStringWidth( title )) / 2.0f, 6, 0x404040 );
-        font.drawString( I18n.format( "container.inventory" ), 8, ySize - 96 + 2, 0x404040 );
+        String title = getTitle().getColoredString();
+        font.draw( title, (imageWidth - font.width( title )) / 2.0f, 6, 0x404040 );
+        font.draw( I18n.get( "container.inventory" ), 8, imageHeight - 96 + 2, 0x404040 );
     }
 
     @Override
-    protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
+    protected void renderBg( float partialTicks, int mouseX, int mouseY )
     {
         RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
-        minecraft.getTextureManager().bindTexture( BACKGROUND );
-        blit( guiLeft, guiTop, 0, 0, xSize, ySize );
+        minecraft.getTextureManager().bind( BACKGROUND );
+        blit( leftPos, topPos, 0, 0, imageWidth, imageHeight );
 
-        if( getContainer().isPrinting() ) blit( guiLeft + 34, guiTop + 21, 176, 0, 25, 45 );
+        if( getMenu().isPrinting() ) blit( leftPos + 34, topPos + 21, 176, 0, 25, 45 );
     }
 
     @Override
@@ -45,6 +45,6 @@ public class GuiPrinter extends ContainerScreen
     {
         renderBackground();
         super.render( mouseX, mouseY, partialTicks );
-        renderHoveredToolTip( mouseX, mouseY );
+        renderTooltip( mouseX, mouseY );
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java
index 08ec7d892..9574d3f04 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java
@@ -34,7 +34,7 @@ public class GuiPrintout extends ContainerScreen
     {
         super( container, player, title );
 
-        ySize = Y_SIZE;
+        imageHeight = Y_SIZE;
 
         String[] text = ItemPrintout.getText( container.getStack() );
         m_text = new TextBuffer[text.length];
@@ -91,16 +91,16 @@ public class GuiPrintout extends ContainerScreen
     }
 
     @Override
-    public void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
+    public void renderBg( float partialTicks, int mouseX, int mouseY )
     {
         // Draw the printout
         RenderSystem.color4f( 1.0f, 1.0f, 1.0f, 1.0f );
         RenderSystem.enableDepthTest();
 
-        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().getRenderTypeBuffers().getBufferSource();
-        drawBorder( IDENTITY, renderer, guiLeft, guiTop, getBlitOffset(), m_page, m_pages, m_book );
-        drawText( IDENTITY, renderer, guiLeft + X_TEXT_MARGIN, guiTop + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
-        renderer.finish();
+        IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource();
+        drawBorder( IDENTITY, renderer, leftPos, topPos, getBlitOffset(), m_page, m_pages, m_book );
+        drawText( IDENTITY, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours );
+        renderer.endBatch();
     }
 
     @Override
@@ -112,6 +112,6 @@ public class GuiPrintout extends ContainerScreen
         setBlitOffset( getBlitOffset() + 1 );
 
         super.render( mouseX, mouseY, partialTicks );
-        renderHoveredToolTip( mouseX, mouseY );
+        renderTooltip( mouseX, mouseY );
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java
index 6bec2b78c..4548bbaa2 100644
--- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java
+++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java
@@ -39,15 +39,15 @@ public class GuiTurtle extends ContainerScreen
         m_family = container.getFamily();
         m_computer = (ClientComputer) container.getComputer();
 
-        xSize = 254;
-        ySize = 217;
+        imageWidth = 254;
+        imageHeight = 217;
     }
 
     @Override
     protected void init()
     {
         super.init();
-        minecraft.keyboardListener.enableRepeatEvents( true );
+        minecraft.keyboardHandler.setSendRepeatsToGui( true );
 
         int termPxWidth = ComputerCraft.turtleTermWidth * FixedWidthFontRenderer.FONT_WIDTH;
         int termPxHeight = ComputerCraft.turtleTermHeight * FixedWidthFontRenderer.FONT_HEIGHT;
@@ -58,7 +58,7 @@ public class GuiTurtle extends ContainerScreen
             ComputerCraft.turtleTermHeight,
             2, 2, 2, 2
         );
-        terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + guiLeft, 2 + 8 + guiTop, termPxWidth, termPxHeight );
+        terminalWrapper = new WidgetWrapper( terminal, 2 + 8 + leftPos, 2 + 8 + topPos, termPxWidth, termPxHeight );
 
         children.add( terminalWrapper );
         setFocused( terminalWrapper );
@@ -70,7 +70,7 @@ public class GuiTurtle extends ContainerScreen
         super.removed();
         children.remove( terminal );
         terminal = null;
-        minecraft.keyboardListener.enableRepeatEvents( false );
+        minecraft.keyboardHandler.setSendRepeatsToGui( false );
     }
 
     @Override
@@ -101,13 +101,13 @@ public class GuiTurtle extends ContainerScreen
             RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
             int slotX = slot % 4;
             int slotY = slot / 4;
-            minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
-            blit( guiLeft + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, guiTop + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 );
+            minecraft.getTextureManager().bind( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
+            blit( leftPos + ContainerTurtle.TURTLE_START_X - 2 + slotX * 18, topPos + ContainerTurtle.PLAYER_START_Y - 2 + slotY * 18, 0, 217, 24, 24 );
         }
     }
 
     @Override
-    protected void drawGuiContainerBackgroundLayer( float partialTicks, int mouseX, int mouseY )
+    protected void renderBg( float partialTicks, int mouseX, int mouseY )
     {
         // Draw term
         boolean advanced = m_family == ComputerFamily.ADVANCED;
@@ -115,8 +115,8 @@ public class GuiTurtle extends ContainerScreen
 
         // Draw border/inventory
         RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F );
-        minecraft.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
-        blit( guiLeft, guiTop, 0, 0, xSize, ySize );
+        minecraft.getTextureManager().bind( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
+        blit( leftPos, topPos, 0, 0, imageWidth, imageHeight );
 
         drawSelectionSlot( advanced );
     }
@@ -126,7 +126,7 @@ public class GuiTurtle extends ContainerScreen
     {
         renderBackground();
         super.render( mouseX, mouseY, partialTicks );
-        renderHoveredToolTip( mouseX, mouseY );
+        renderTooltip( mouseX, mouseY );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java
index d64e24e9e..343e5229e 100644
--- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java
+++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java
@@ -91,7 +91,7 @@ public class WidgetTerminal implements IGuiEventListener
 
                 case GLFW.GLFW_KEY_V:
                     // Ctrl+V for paste
-                    String clipboard = client.keyboardListener.getClipboardString();
+                    String clipboard = client.keyboardHandler.getClipboard();
                     if( clipboard != null )
                     {
                         // Clip to the first occurrence of \r or \n
@@ -111,7 +111,7 @@ public class WidgetTerminal implements IGuiEventListener
                         }
 
                         // Filter the string
-                        clipboard = SharedConstants.filterAllowedCharacters( clipboard );
+                        clipboard = SharedConstants.filterText( clipboard );
                         if( !clipboard.isEmpty() )
                         {
                             // Clip to 512 characters and queue the event
diff --git a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
index 50afc8f4f..e0b01fd0f 100644
--- a/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
+++ b/src/main/java/dan200/computercraft/client/proxy/ComputerCraftProxyClient.java
@@ -35,12 +35,12 @@ public final class ComputerCraftProxyClient
         registerContainers();
 
         // While turtles themselves are not transparent, their upgrades may be.
-        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.TURTLE_NORMAL.get(), RenderType.getTranslucent() );
-        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.TURTLE_ADVANCED.get(), RenderType.getTranslucent() );
+        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.TURTLE_NORMAL.get(), RenderType.translucent() );
+        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.TURTLE_ADVANCED.get(), RenderType.translucent() );
 
         // Monitors' textures have transparent fronts and so count as cutouts.
-        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.MONITOR_NORMAL.get(), RenderType.getCutout() );
-        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.MONITOR_ADVANCED.get(), RenderType.getCutout() );
+        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.MONITOR_NORMAL.get(), RenderType.cutout() );
+        RenderTypeLookup.setRenderLayer( Registry.ModBlocks.MONITOR_ADVANCED.get(), RenderType.cutout() );
 
         // Setup TESRs
         ClientRegistry.bindTileEntityRenderer( Registry.ModTiles.MONITOR_NORMAL.get(), TileEntityMonitorRenderer::new );
@@ -55,15 +55,15 @@ public final class ComputerCraftProxyClient
     {
         // My IDE doesn't think so, but we do actually need these generics.
 
-        ScreenManager.>registerFactory( Registry.ModContainers.COMPUTER.get(), GuiComputer::create );
-        ScreenManager.>registerFactory( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::createPocket );
-        ScreenManager.registerFactory( Registry.ModContainers.TURTLE.get(), GuiTurtle::new );
+        ScreenManager.>register( Registry.ModContainers.COMPUTER.get(), GuiComputer::create );
+        ScreenManager.>register( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::createPocket );
+        ScreenManager.register( Registry.ModContainers.TURTLE.get(), GuiTurtle::new );
 
-        ScreenManager.registerFactory( Registry.ModContainers.PRINTER.get(), GuiPrinter::new );
-        ScreenManager.registerFactory( Registry.ModContainers.DISK_DRIVE.get(), GuiDiskDrive::new );
-        ScreenManager.registerFactory( Registry.ModContainers.PRINTOUT.get(), GuiPrintout::new );
+        ScreenManager.register( Registry.ModContainers.PRINTER.get(), GuiPrinter::new );
+        ScreenManager.register( Registry.ModContainers.DISK_DRIVE.get(), GuiDiskDrive::new );
+        ScreenManager.register( Registry.ModContainers.PRINTOUT.get(), GuiPrintout::new );
 
-        ScreenManager.>registerFactory( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::createView );
+        ScreenManager.>register( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::createView );
     }
 
     @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
@@ -72,7 +72,7 @@ public final class ComputerCraftProxyClient
         @SubscribeEvent
         public static void onWorldUnload( WorldEvent.Unload event )
         {
-            if( event.getWorld().isRemote() )
+            if( event.getWorld().isClientSide() )
             {
                 ClientMonitor.destroyAll();
             }
diff --git a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java
index f87fa8782..5f517b1d1 100644
--- a/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/CableHighlightRenderer.java
@@ -45,35 +45,35 @@ public final class CableHighlightRenderer
     public static void drawHighlight( DrawHighlightEvent.HighlightBlock event )
     {
         BlockRayTraceResult hit = event.getTarget();
-        BlockPos pos = hit.getPos();
-        World world = event.getInfo().getRenderViewEntity().getEntityWorld();
+        BlockPos pos = hit.getBlockPos();
+        World world = event.getInfo().getEntity().getCommandSenderWorld();
         ActiveRenderInfo info = event.getInfo();
 
         BlockState state = world.getBlockState( pos );
 
         // We only care about instances with both cable and modem.
-        if( state.getBlock() != Registry.ModBlocks.CABLE.get() || state.get( BlockCable.MODEM ).getFacing() == null || !state.get( BlockCable.CABLE ) )
+        if( state.getBlock() != Registry.ModBlocks.CABLE.get() || state.getValue( BlockCable.MODEM ).getFacing() == null || !state.getValue( BlockCable.CABLE ) )
         {
             return;
         }
 
         event.setCanceled( true );
 
-        VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
+        VoxelShape shape = WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
             ? CableShapes.getModemShape( state )
             : CableShapes.getCableShape( state );
 
-        Vec3d cameraPos = info.getProjectedView();
-        double xOffset = pos.getX() - cameraPos.getX();
-        double yOffset = pos.getY() - cameraPos.getY();
-        double zOffset = pos.getZ() - cameraPos.getZ();
+        Vec3d cameraPos = info.getPosition();
+        double xOffset = pos.getX() - cameraPos.x();
+        double yOffset = pos.getY() - cameraPos.y();
+        double zOffset = pos.getZ() - cameraPos.z();
 
-        IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.getLines() );
-        Matrix4f matrix4f = event.getMatrix().getLast().getMatrix();
-        shape.forEachEdge( ( x1, y1, z1, x2, y2, z2 ) -> {
-            buffer.pos( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) )
+        IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.lines() );
+        Matrix4f matrix4f = event.getMatrix().last().pose();
+        shape.forAllEdges( ( x1, y1, z1, x2, y2, z2 ) -> {
+            buffer.vertex( matrix4f, (float) (x1 + xOffset), (float) (y1 + yOffset), (float) (z1 + zOffset) )
                 .color( 0, 0, 0, 0.4f ).endVertex();
-            buffer.pos( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) )
+            buffer.vertex( matrix4f, (float) (x2 + xOffset), (float) (y2 + yOffset), (float) (z2 + zOffset) )
                 .color( 0, 0, 0, 0.4f ).endVertex();
         } );
     }
diff --git a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java
index 4eacb4779..a7357f0d2 100644
--- a/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/ComputerBorderRenderer.java
@@ -85,13 +85,13 @@ public class ComputerBorderRenderer
     public static void render( int x, int y, int z, int width, int height )
     {
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBuffer();
+        BufferBuilder buffer = tessellator.getBuilder();
         buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
 
         render( IDENTITY, buffer, x, y, z, width, height );
 
         RenderSystem.enableAlphaTest();
-        tessellator.draw();
+        tessellator.end();
     }
 
     public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height )
@@ -166,9 +166,9 @@ public class ComputerBorderRenderer
 
     private void renderTexture( int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight )
     {
-        builder.pos( transform, x, y + height, z ).color( r, g, b, 1.0f ).tex( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex();
-        builder.pos( transform, x + width, y + height, z ).color( r, g, b, 1.0f ).tex( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex();
-        builder.pos( transform, x + width, y, z ).color( r, g, b, 1.0f ).tex( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).endVertex();
-        builder.pos( transform, x, y, z ).color( r, g, b, 1.0f ).tex( u * TEX_SCALE, v * TEX_SCALE ).endVertex();
+        builder.vertex( transform, x, y + height, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex();
+        builder.vertex( transform, x + width, y + height, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, (v + textureHeight) * TEX_SCALE ).endVertex();
+        builder.vertex( transform, x + width, y, z ).color( r, g, b, 1.0f ).uv( (u + textureWidth) * TEX_SCALE, v * TEX_SCALE ).endVertex();
+        builder.vertex( transform, x, y, z ).color( r, g, b, 1.0f ).uv( u * TEX_SCALE, v * TEX_SCALE ).endVertex();
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java
index 9176dd722..af0248b02 100644
--- a/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/ItemMapLikeRenderer.java
@@ -33,8 +33,8 @@ public abstract class ItemMapLikeRenderer
     {
         PlayerEntity player = Minecraft.getInstance().player;
 
-        transform.push();
-        if( hand == Hand.MAIN_HAND && player.getHeldItemOffhand().isEmpty() )
+        transform.pushPose();
+        if( hand == Hand.MAIN_HAND && player.getOffhandItem().isEmpty() )
         {
             renderItemFirstPersonCenter( transform, render, lightTexture, pitch, equipProgress, swingProgress, stack );
         }
@@ -42,11 +42,11 @@ public abstract class ItemMapLikeRenderer
         {
             renderItemFirstPersonSide(
                 transform, render, lightTexture,
-                hand == Hand.MAIN_HAND ? player.getPrimaryHand() : player.getPrimaryHand().opposite(),
+                hand == Hand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(),
                 equipProgress, swingProgress, stack
             );
         }
-        transform.pop();
+        transform.popPose();
     }
 
     /**
@@ -70,15 +70,15 @@ public abstract class ItemMapLikeRenderer
         // If the player is not invisible then render a single arm
         if( !minecraft.player.isInvisible() )
         {
-            transform.push();
-            transform.rotate( Vector3f.ZP.rotationDegrees( offset * 10f ) );
-            minecraft.getFirstPersonRenderer().renderArmFirstPerson( transform, render, combinedLight, equipProgress, swingProgress, side );
-            transform.pop();
+            transform.pushPose();
+            transform.mulPose( Vector3f.ZP.rotationDegrees( offset * 10f ) );
+            minecraft.getItemInHandRenderer().renderPlayerArm( transform, render, combinedLight, equipProgress, swingProgress, side );
+            transform.popPose();
         }
 
         // Setup the appropriate transformations. This is just copied from the
         // corresponding method in ItemRenderer.
-        transform.push();
+        transform.pushPose();
         transform.translate( offset * 0.51f, -0.08f + equipProgress * -1.2f, -0.75f );
         float f1 = MathHelper.sqrt( swingProgress );
         float f2 = MathHelper.sin( f1 * (float) Math.PI );
@@ -86,12 +86,12 @@ public abstract class ItemMapLikeRenderer
         float f4 = 0.4f * MathHelper.sin( f1 * ((float) Math.PI * 2f) );
         float f5 = -0.3f * MathHelper.sin( swingProgress * (float) Math.PI );
         transform.translate( offset * f3, f4 - 0.3f * f2, f5 );
-        transform.rotate( Vector3f.XP.rotationDegrees( f2 * -45f ) );
-        transform.rotate( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) );
+        transform.mulPose( Vector3f.XP.rotationDegrees( f2 * -45f ) );
+        transform.mulPose( Vector3f.YP.rotationDegrees( offset * f2 * -30f ) );
 
         renderItem( transform, render, stack );
 
-        transform.pop();
+        transform.popPose();
     }
 
     /**
@@ -109,7 +109,7 @@ public abstract class ItemMapLikeRenderer
     private void renderItemFirstPersonCenter( MatrixStack transform, IRenderTypeBuffer render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack )
     {
         Minecraft minecraft = Minecraft.getInstance();
-        FirstPersonRenderer renderer = minecraft.getFirstPersonRenderer();
+        FirstPersonRenderer renderer = minecraft.getItemInHandRenderer();
 
         // Setup the appropriate transformations. This is just copied from the
         // corresponding method in ItemRenderer.
@@ -118,20 +118,20 @@ public abstract class ItemMapLikeRenderer
         float tZ = -0.4f * MathHelper.sin( swingRt * (float) Math.PI );
         transform.translate( 0, -tX / 2, tZ );
 
-        float pitchAngle = renderer.getMapAngleFromPitch( pitch );
+        float pitchAngle = renderer.calculateMapTilt( pitch );
         transform.translate( 0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f );
-        transform.rotate( Vector3f.XP.rotationDegrees( pitchAngle * -85.0f ) );
+        transform.mulPose( Vector3f.XP.rotationDegrees( pitchAngle * -85.0f ) );
         if( !minecraft.player.isInvisible() )
         {
-            transform.push();
-            transform.rotate( Vector3f.YP.rotationDegrees( 90.0F ) );
-            renderer.renderArm( transform, render, combinedLight, HandSide.RIGHT );
-            renderer.renderArm( transform, render, combinedLight, HandSide.LEFT );
-            transform.pop();
+            transform.pushPose();
+            transform.mulPose( Vector3f.YP.rotationDegrees( 90.0F ) );
+            renderer.renderMapHand( transform, render, combinedLight, HandSide.RIGHT );
+            renderer.renderMapHand( transform, render, combinedLight, HandSide.LEFT );
+            transform.popPose();
         }
 
         float rX = MathHelper.sin( swingRt * (float) Math.PI );
-        transform.rotate( Vector3f.XP.rotationDegrees( rX * 20.0F ) );
+        transform.mulPose( Vector3f.XP.rotationDegrees( rX * 20.0F ) );
         transform.scale( 2.0F, 2.0F, 2.0F );
 
         renderItem( transform, render, stack );
diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java
index 0b356f0fe..499d82202 100644
--- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java
@@ -79,9 +79,9 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
 
         // Setup various transformations. Note that these are partially adapted from the corresponding method
         // in ItemRenderer
-        transform.push();
-        transform.rotate( Vector3f.YP.rotationDegrees( 180f ) );
-        transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) );
+        transform.pushPose();
+        transform.mulPose( Vector3f.YP.rotationDegrees( 180f ) );
+        transform.mulPose( Vector3f.ZP.rotationDegrees( 180f ) );
         transform.scale( 0.5f, 0.5f, 0.5f );
 
         float scale = 0.75f / Math.max( width + BORDER * 2, height + BORDER * 2 + LIGHT_HEIGHT );
@@ -93,7 +93,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
         ComputerFamily family = item.getFamily();
         int frameColour = item.getColour( stack );
 
-        Matrix4f matrix = transform.getLast().getMatrix();
+        Matrix4f matrix = transform.last().pose();
         renderFrame( matrix, family, frameColour, width, height );
 
         // Render the light
@@ -110,26 +110,26 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
             FixedWidthFontRenderer.drawEmptyTerminal( matrix, 0, 0, width, height );
         }
 
-        transform.pop();
+        transform.popPose();
     }
 
     private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height )
     {
         RenderSystem.enableBlend();
         Minecraft.getInstance().getTextureManager()
-            .bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) );
+            .bind( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) );
 
         float r = ((colour >>> 16) & 0xFF) / 255.0f;
         float g = ((colour >>> 8) & 0xFF) / 255.0f;
         float b = (colour & 0xFF) / 255.0f;
 
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBuffer();
+        BufferBuilder buffer = tessellator.getBuilder();
         buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
 
         ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, LIGHT_HEIGHT, r, g, b );
 
-        tessellator.draw();
+        tessellator.end();
     }
 
     private static void renderLight( Matrix4f transform, int colour, int width, int height )
@@ -141,14 +141,14 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
         float b = (colour & 0xFF) / 255.0f;
 
         Tessellator tessellator = Tessellator.getInstance();
-        BufferBuilder buffer = tessellator.getBuffer();
+        BufferBuilder buffer = tessellator.getBuilder();
         buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
-        buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
-        buffer.pos( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
-        buffer.pos( transform, width, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
-        buffer.pos( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
+        buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
+        buffer.vertex( transform, width, height + LIGHT_HEIGHT + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
+        buffer.vertex( transform, width, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
+        buffer.vertex( transform, width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0 ).color( r, g, b, 1.0f ).endVertex();
 
-        tessellator.draw();
+        tessellator.end();
         RenderSystem.enableTexture();
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java
index 4549060df..fcf52f2e1 100644
--- a/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/ItemPrintoutRenderer.java
@@ -52,7 +52,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
     @Override
     protected void renderItem( MatrixStack transform, IRenderTypeBuffer render, ItemStack stack )
     {
-        transform.rotate( Vector3f.XP.rotationDegrees( 180f ) );
+        transform.mulPose( Vector3f.XP.rotationDegrees( 180f ) );
         transform.scale( 0.42f, 0.42f, -0.42f );
         transform.translate( -0.5f, -0.48f, 0.0f );
 
@@ -70,7 +70,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
 
         // Move a little bit forward to ensure we're not clipping with the frame
         transform.translate( 0.0f, 0.0f, -0.001f );
-        transform.rotate( Vector3f.ZP.rotationDegrees( 180f ) );
+        transform.mulPose( Vector3f.ZP.rotationDegrees( 180f ) );
         transform.scale( 0.95f, 0.95f, -0.95f );
         transform.translate( -0.5f, -0.5f, 0.0f );
 
@@ -104,7 +104,7 @@ public final class ItemPrintoutRenderer extends ItemMapLikeRenderer
         transform.scale( scale, scale, scale );
         transform.translate( (max - width) / 2.0, (max - height) / 2.0, 0.0 );
 
-        Matrix4f matrix = transform.getLast().getMatrix();
+        Matrix4f matrix = transform.last().pose();
         drawBorder( matrix, render, 0, 0, -0.01f, 0, pages, book );
         drawText( matrix, render,
             X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, ItemPrintout.getText( stack ), ItemPrintout.getColours( stack )
diff --git a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java
index a954938a3..35a6c0dbb 100644
--- a/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/MonitorHighlightRenderer.java
@@ -40,12 +40,12 @@ public final class MonitorHighlightRenderer
     public static void drawHighlight( DrawHighlightEvent.HighlightBlock event )
     {
         // Preserve normal behaviour when crouching.
-        if( event.getInfo().getRenderViewEntity().isCrouching() ) return;
+        if( event.getInfo().getEntity().isCrouching() ) return;
 
-        World world = event.getInfo().getRenderViewEntity().getEntityWorld();
-        BlockPos pos = event.getTarget().getPos();
+        World world = event.getInfo().getEntity().getCommandSenderWorld();
+        BlockPos pos = event.getTarget().getBlockPos();
 
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( !(tile instanceof TileMonitor) ) return;
 
         TileMonitor monitor = (TileMonitor) tile;
@@ -61,13 +61,13 @@ public final class MonitorHighlightRenderer
         if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
 
         MatrixStack transformStack = event.getMatrix();
-        Vec3d cameraPos = event.getInfo().getProjectedView();
-        transformStack.push();
-        transformStack.translate( pos.getX() - cameraPos.getX(), pos.getY() - cameraPos.getY(), pos.getZ() - cameraPos.getZ() );
+        Vec3d cameraPos = event.getInfo().getPosition();
+        transformStack.pushPose();
+        transformStack.translate( pos.getX() - cameraPos.x(), pos.getY() - cameraPos.y(), pos.getZ() - cameraPos.z() );
 
         // I wish I could think of a better way to do this
-        IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.getLines() );
-        Matrix4f transform = transformStack.getLast().getMatrix();
+        IVertexBuilder buffer = event.getBuffers().getBuffer( RenderType.lines() );
+        Matrix4f transform = transformStack.last().pose();
         if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 0, UP );
         if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, transform, 0, 0, 1, UP );
         if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, transform, 1, 0, 0, UP );
@@ -81,16 +81,16 @@ public final class MonitorHighlightRenderer
         if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, transform, 0, 1, 0, SOUTH );
         if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, transform, 1, 1, 0, SOUTH );
 
-        transformStack.pop();
+        transformStack.popPose();
     }
 
     private static void line( IVertexBuilder buffer, Matrix4f transform, float x, float y, float z, Direction direction )
     {
-        buffer.pos( transform, x, y, z ).color( 0, 0, 0, 0.4f ).endVertex();
-        buffer.pos( transform,
-            x + direction.getXOffset(),
-            y + direction.getYOffset(),
-            z + direction.getZOffset()
+        buffer.vertex( transform, x, y, z ).color( 0, 0, 0, 0.4f ).endVertex();
+        buffer.vertex( transform,
+            x + direction.getStepX(),
+            y + direction.getStepY(),
+            z + direction.getStepZ()
         ).color( 0, 0, 0, 0.4f ).endVertex();
     }
 }
diff --git a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java
index 241823f33..2e669f79b 100644
--- a/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java
+++ b/src/main/java/dan200/computercraft/client/render/MonitorTextureBufferShader.java
@@ -42,7 +42,7 @@ class MonitorTextureBufferShader
     static void setupUniform( Matrix4f transform, int width, int height, Palette palette, boolean greyscale )
     {
         MATRIX_BUFFER.rewind();
-        transform.write( MATRIX_BUFFER );
+        transform.store( MATRIX_BUFFER );
         MATRIX_BUFFER.rewind();
         RenderSystem.glUniformMatrix4( uniformMv, false, MATRIX_BUFFER );
 
@@ -71,7 +71,7 @@ class MonitorTextureBufferShader
     {
         if( initialised )
         {
-            if( ok ) GlStateManager.useProgram( program );
+            if( ok ) GlStateManager._glUseProgram( program );
             return ok;
         }
 
@@ -94,14 +94,14 @@ class MonitorTextureBufferShader
             int vertexShader = loadShader( GL20.GL_VERTEX_SHADER, "assets/computercraft/shaders/monitor.vert" );
             int fragmentShader = loadShader( GL20.GL_FRAGMENT_SHADER, "assets/computercraft/shaders/monitor.frag" );
 
-            program = GlStateManager.createProgram();
-            GlStateManager.attachShader( program, vertexShader );
-            GlStateManager.attachShader( program, fragmentShader );
+            program = GlStateManager.glCreateProgram();
+            GlStateManager.glAttachShader( program, vertexShader );
+            GlStateManager.glAttachShader( program, fragmentShader );
             GL20.glBindAttribLocation( program, 0, "v_pos" );
 
-            GlStateManager.linkProgram( program );
-            boolean ok = GlStateManager.getProgram( program, GL20.GL_LINK_STATUS ) != 0;
-            String log = GlStateManager.getProgramInfoLog( program, Short.MAX_VALUE ).trim();
+            GlStateManager.glLinkProgram( program );
+            boolean ok = GlStateManager.glGetProgrami( program, GL20.GL_LINK_STATUS ) != 0;
+            String log = GlStateManager.glGetProgramInfoLog( program, Short.MAX_VALUE ).trim();
             if( !Strings.isNullOrEmpty( log ) )
             {
                 ComputerCraft.log.warn( "Problems when linking monitor shader: {}", log );
@@ -109,8 +109,8 @@ class MonitorTextureBufferShader
 
             GL20.glDetachShader( program, vertexShader );
             GL20.glDetachShader( program, fragmentShader );
-            GlStateManager.deleteShader( vertexShader );
-            GlStateManager.deleteShader( fragmentShader );
+            GlStateManager.glDeleteShader( vertexShader );
+            GlStateManager.glDeleteShader( fragmentShader );
 
             if( !ok ) return false;
 
@@ -137,13 +137,13 @@ class MonitorTextureBufferShader
         if( stream == null ) throw new IllegalArgumentException( "Cannot find " + path );
         String contents = TextureUtil.readResourceAsString( stream );
 
-        int shader = GlStateManager.createShader( kind );
+        int shader = GlStateManager.glCreateShader( kind );
 
-        GlStateManager.shaderSource( shader, contents );
-        GlStateManager.compileShader( shader );
+        GlStateManager.glShaderSource( shader, contents );
+        GlStateManager.glCompileShader( shader );
 
-        boolean ok = GlStateManager.getShader( shader, GL20.GL_COMPILE_STATUS ) != 0;
-        String log = GlStateManager.getShaderInfoLog( shader, Short.MAX_VALUE ).trim();
+        boolean ok = GlStateManager.glGetShaderi( shader, GL20.GL_COMPILE_STATUS ) != 0;
+        String log = GlStateManager.glGetShaderInfoLog( shader, Short.MAX_VALUE ).trim();
         if( !Strings.isNullOrEmpty( log ) )
         {
             ComputerCraft.log.warn( "Problems when loading monitor shader {}: {}", path, log );
@@ -155,7 +155,7 @@ class MonitorTextureBufferShader
 
     private static int getUniformLocation( int program, String name )
     {
-        int uniform = GlStateManager.getUniformLocation( program, name );
+        int uniform = GlStateManager._glGetUniformLocation( program, name );
         if( uniform == -1 ) throw new IllegalStateException( "Cannot find uniform " + name );
         return uniform;
     }
diff --git a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java
index 69a9865a7..9127cb426 100644
--- a/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/PrintoutRenderer.java
@@ -146,18 +146,18 @@ public final class PrintoutRenderer
 
     private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float u, float v, float width, float height )
     {
-        buffer.pos( matrix, x, y + height, z ).tex( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
-        buffer.pos( matrix, x + width, y + height, z ).tex( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
-        buffer.pos( matrix, x + width, y, z ).tex( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
-        buffer.pos( matrix, x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x, y + height, z ).uv( u / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x + width, y + height, z ).uv( (u + width) / BG_SIZE, (v + height) / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x + width, y, z ).uv( (u + width) / BG_SIZE, v / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x, y, z ).uv( u / BG_SIZE, v / BG_SIZE ).endVertex();
     }
 
     private static void drawTexture( Matrix4f matrix, IVertexBuilder buffer, float x, float y, float z, float width, float height, float u, float v, float tWidth, float tHeight )
     {
-        buffer.pos( matrix, x, y + height, z ).tex( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
-        buffer.pos( matrix, x + width, y + height, z ).tex( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
-        buffer.pos( matrix, x + width, y, z ).tex( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
-        buffer.pos( matrix, x, y, z ).tex( u / BG_SIZE, v / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x, y + height, z ).uv( u / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x + width, y + height, z ).uv( (u + tWidth) / BG_SIZE, (v + tHeight) / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x + width, y, z ).uv( (u + tWidth) / BG_SIZE, v / BG_SIZE ).endVertex();
+        buffer.vertex( matrix, x, y, z ).uv( u / BG_SIZE, v / BG_SIZE ).endVertex();
     }
 
     public static float offsetAt( int page )
@@ -167,14 +167,14 @@ public final class PrintoutRenderer
 
     private static final class Type extends RenderState
     {
-        static final RenderType TYPE = RenderType.makeType(
+        static final RenderType TYPE = RenderType.create(
             "printout_background", DefaultVertexFormats.POSITION_TEX, GL11.GL_QUADS, 1024,
             false, false, // useDelegate, needsSorting
-            RenderType.State.getBuilder()
-                .texture( new RenderState.TextureState( BG, false, false ) ) // blur, minimap
-                .alpha( DEFAULT_ALPHA )
-                .lightmap( LIGHTMAP_DISABLED )
-                .build( false )
+            RenderType.State.builder()
+                .setTextureState( new RenderState.TextureState( BG, false, false ) ) // blur, minimap
+                .setAlphaState( DEFAULT_ALPHA )
+                .setLightmapState( NO_LIGHTMAP )
+                .createCompositeState( false )
         );
 
         private Type( String name, Runnable setup, Runnable destroy )
diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java
index 2fdcd3411..66f528e4b 100644
--- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java
@@ -58,7 +58,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
 
         if( originTerminal == null ) return;
         TileMonitor origin = originTerminal.getOrigin();
-        BlockPos monitorPos = monitor.getPos();
+        BlockPos monitorPos = monitor.getBlockPos();
 
         // Ensure each monitor terminal is rendered only once. We allow rendering a specific tile
         // multiple times in a single frame to ensure compatibility with shaders which may run a
@@ -72,24 +72,24 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
         originTerminal.lastRenderFrame = renderFrame;
         originTerminal.lastRenderPos = monitorPos;
 
-        BlockPos originPos = origin.getPos();
+        BlockPos originPos = origin.getBlockPos();
 
         // Determine orientation
         Direction dir = origin.getDirection();
         Direction front = origin.getFront();
-        float yaw = dir.getHorizontalAngle();
+        float yaw = dir.toYRot();
         float pitch = DirectionUtil.toPitchAngle( front );
 
         // Setup initial transform
-        transform.push();
+        transform.pushPose();
         transform.translate(
             originPos.getX() - monitorPos.getX() + 0.5,
             originPos.getY() - monitorPos.getY() + 0.5,
             originPos.getZ() - monitorPos.getZ() + 0.5
         );
 
-        transform.rotate( Vector3f.YN.rotationDegrees( yaw ) );
-        transform.rotate( Vector3f.XP.rotationDegrees( pitch ) );
+        transform.mulPose( Vector3f.YN.rotationDegrees( yaw ) );
+        transform.mulPose( Vector3f.XP.rotationDegrees( pitch ) );
         transform.translate(
             -0.5 + TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN,
             origin.getHeight() - 0.5 - (TileMonitor.RENDER_BORDER + TileMonitor.RENDER_MARGIN) + 0,
@@ -107,10 +107,10 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
             int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
             double xScale = xSize / pixelWidth;
             double yScale = ySize / pixelHeight;
-            transform.push();
+            transform.pushPose();
             transform.scale( (float) xScale, (float) -yScale, 1.0f );
 
-            Matrix4f matrix = transform.getLast().getMatrix();
+            Matrix4f matrix = transform.last().pose();
 
             // Sneaky hack here: we get a buffer now in order to flush existing ones and set up the appropriate
             // render state. I've no clue how well this'll work in future versions of Minecraft, but it does the trick
@@ -124,24 +124,24 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
             // reasonable.
             FixedWidthFontRenderer.drawCursor( matrix, buffer, 0, 0, terminal, !originTerminal.isColour() );
 
-            transform.pop();
+            transform.popPose();
         }
         else
         {
             FixedWidthFontRenderer.drawEmptyTerminal(
-                transform.getLast().getMatrix(), renderer,
+                transform.last().pose(), renderer,
                 -MARGIN, MARGIN,
                 (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
             );
         }
 
         FixedWidthFontRenderer.drawBlocker(
-            transform.getLast().getMatrix(), renderer,
+            transform.last().pose(), renderer,
             (float) -TileMonitor.RENDER_MARGIN, (float) TileMonitor.RENDER_MARGIN,
             (float) (xSize + 2 * TileMonitor.RENDER_MARGIN), (float) -(ySize + TileMonitor.RENDER_MARGIN * 2)
         );
 
-        transform.pop();
+        transform.popPose();
     }
 
     private static void renderTerminal( Matrix4f matrix, ClientMonitor monitor, float xMargin, float yMargin )
@@ -166,7 +166,7 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
                     int size = width * height * 3;
                     if( tboContents == null || tboContents.capacity() < size )
                     {
-                        tboContents = GLAllocation.createDirectByteBuffer( size );
+                        tboContents = GLAllocation.createByteBuffer( size );
                     }
 
                     ByteBuffer monitorBuffer = tboContents;
@@ -183,28 +183,28 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
                     }
                     monitorBuffer.flip();
 
-                    GlStateManager.bindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
-                    GlStateManager.bufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW );
-                    GlStateManager.bindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
+                    GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, monitor.tboBuffer );
+                    GlStateManager._glBufferData( GL31.GL_TEXTURE_BUFFER, monitorBuffer, GL20.GL_STATIC_DRAW );
+                    GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
                 }
 
                 // Nobody knows what they're doing!
-                GlStateManager.activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX );
+                GlStateManager._activeTexture( MonitorTextureBufferShader.TEXTURE_INDEX );
                 GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, monitor.tboTexture );
-                GlStateManager.activeTexture( GL13.GL_TEXTURE0 );
+                GlStateManager._activeTexture( GL13.GL_TEXTURE0 );
 
                 MonitorTextureBufferShader.setupUniform( matrix, width, height, terminal.getPalette(), !monitor.isColour() );
 
                 Tessellator tessellator = Tessellator.getInstance();
-                BufferBuilder buffer = tessellator.getBuffer();
+                BufferBuilder buffer = tessellator.getBuilder();
                 buffer.begin( GL11.GL_TRIANGLE_STRIP, DefaultVertexFormats.POSITION );
-                buffer.pos( -xMargin, -yMargin, 0 ).endVertex();
-                buffer.pos( -xMargin, pixelHeight + yMargin, 0 ).endVertex();
-                buffer.pos( pixelWidth + xMargin, -yMargin, 0 ).endVertex();
-                buffer.pos( pixelWidth + xMargin, pixelHeight + yMargin, 0 ).endVertex();
-                tessellator.draw();
+                buffer.vertex( -xMargin, -yMargin, 0 ).endVertex();
+                buffer.vertex( -xMargin, pixelHeight + yMargin, 0 ).endVertex();
+                buffer.vertex( pixelWidth + xMargin, -yMargin, 0 ).endVertex();
+                buffer.vertex( pixelWidth + xMargin, pixelHeight + yMargin, 0 ).endVertex();
+                tessellator.end();
 
-                GlStateManager.useProgram( 0 );
+                GlStateManager._glUseProgram( 0 );
                 break;
             }
 
@@ -214,22 +214,22 @@ public class TileEntityMonitorRenderer extends TileEntityRenderer
                 if( redraw )
                 {
                     Tessellator tessellator = Tessellator.getInstance();
-                    BufferBuilder builder = tessellator.getBuffer();
-                    builder.begin( FixedWidthFontRenderer.TYPE.getDrawMode(), FixedWidthFontRenderer.TYPE.getVertexFormat() );
+                    BufferBuilder builder = tessellator.getBuilder();
+                    builder.begin( FixedWidthFontRenderer.TYPE.mode(), FixedWidthFontRenderer.TYPE.format() );
                     FixedWidthFontRenderer.drawTerminalWithoutCursor(
                         IDENTITY, builder, 0, 0,
                         terminal, !monitor.isColour(), yMargin, yMargin, xMargin, xMargin
                     );
 
-                    builder.finishDrawing();
+                    builder.end();
                     vbo.upload( builder );
                 }
 
-                vbo.bindBuffer();
-                FixedWidthFontRenderer.TYPE.getVertexFormat().setupBufferState( 0L );
-                vbo.draw( matrix, FixedWidthFontRenderer.TYPE.getDrawMode() );
-                VertexBuffer.unbindBuffer();
-                FixedWidthFontRenderer.TYPE.getVertexFormat().clearBufferState();
+                vbo.bind();
+                FixedWidthFontRenderer.TYPE.format().setupBufferState( 0L );
+                vbo.draw( matrix, FixedWidthFontRenderer.TYPE.mode() );
+                VertexBuffer.unbind();
+                FixedWidthFontRenderer.TYPE.format().clearBufferState();
                 break;
             }
         }
diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java
index d9717d84a..eee5c6b25 100644
--- a/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/TileEntityTurtleRenderer.java
@@ -72,31 +72,31 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer
     }
 
     @Override
-    public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer renderer, int lightmapCoord, int overlayLight )
+    public void render( @Nonnull TileTurtle turtle, float partialTicks, @Nonnull MatrixStack transform, @Nonnull IRenderTypeBuffer buffers, int lightmapCoord, int overlayLight )
     {
         // Render the label
         String label = turtle.createProxy().getLabel();
-        RayTraceResult hit = renderDispatcher.cameraHitResult;
-        if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getPos().equals( ((BlockRayTraceResult) hit).getPos() ) )
+        RayTraceResult hit = renderer.cameraHitResult;
+        if( label != null && hit.getType() == RayTraceResult.Type.BLOCK && turtle.getBlockPos().equals( ((BlockRayTraceResult) hit).getBlockPos() ) )
         {
             Minecraft mc = Minecraft.getInstance();
-            FontRenderer font = renderDispatcher.fontRenderer;
+            FontRenderer font = renderer.font;
 
-            transform.push();
+            transform.pushPose();
             transform.translate( 0.5, 1.2, 0.5 );
-            transform.rotate( mc.getRenderManager().getCameraOrientation() );
+            transform.mulPose( mc.getEntityRenderDispatcher().cameraOrientation() );
             transform.scale( -0.025f, -0.025f, 0.025f );
 
-            Matrix4f matrix = transform.getLast().getMatrix();
-            int opacity = (int) (mc.gameSettings.getTextBackgroundOpacity( 0.25f ) * 255) << 24;
-            float width = -font.getStringWidth( label ) / 2.0f;
-            font.renderString( label, width, (float) 0, 0x20ffffff, false, matrix, renderer, true, opacity, lightmapCoord );
-            font.renderString( label, width, (float) 0, 0xffffffff, false, matrix, renderer, false, 0, lightmapCoord );
+            Matrix4f matrix = transform.last().pose();
+            int opacity = (int) (mc.options.getBackgroundOpacity( 0.25f ) * 255) << 24;
+            float width = -font.width( label ) / 2.0f;
+            font.drawInBatch( label, width, (float) 0, 0x20ffffff, false, matrix, buffers, true, opacity, lightmapCoord );
+            font.drawInBatch( label, width, (float) 0, 0xffffffff, false, matrix, buffers, false, 0, lightmapCoord );
 
-            transform.pop();
+            transform.popPose();
         }
 
-        transform.push();
+        transform.pushPose();
 
         // Setup the transform.
         Vec3d offset = turtle.getRenderOffset( partialTicks );
@@ -104,7 +104,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer
         transform.translate( offset.x, offset.y, offset.z );
 
         transform.translate( 0.5f, 0.5f, 0.5f );
-        transform.rotate( Vector3f.YP.rotationDegrees( 180.0f - yaw ) );
+        transform.mulPose( Vector3f.YP.rotationDegrees( 180.0f - yaw ) );
         if( label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )) )
         {
             // Flip the model
@@ -117,7 +117,7 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer
         ComputerFamily family = turtle.getFamily();
         ResourceLocation overlay = turtle.getOverlay();
 
-        IVertexBuilder buffer = renderer.getBuffer( Atlases.getTranslucentCullBlockType() );
+        IVertexBuilder buffer = buffers.getBuffer( Atlases.translucentCullBlockSheet() );
         renderModel( transform, buffer, lightmapCoord, overlayLight, getTurtleModel( family, colour != -1 ), colour == -1 ? null : new int[] { colour } );
 
         // Render the overlay
@@ -131,31 +131,31 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer
         renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks );
         renderUpgrade( transform, buffer, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks );
 
-        transform.pop();
+        transform.popPose();
     }
 
     private void renderUpgrade( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, TileTurtle turtle, TurtleSide side, float f )
     {
         ITurtleUpgrade upgrade = turtle.getUpgrade( side );
         if( upgrade == null ) return;
-        transform.push();
+        transform.pushPose();
 
         float toolAngle = turtle.getToolRenderAngle( side, f );
         transform.translate( 0.0f, 0.5f, 0.5f );
-        transform.rotate( Vector3f.XN.rotationDegrees( toolAngle ) );
+        transform.mulPose( Vector3f.XN.rotationDegrees( toolAngle ) );
         transform.translate( 0.0f, -0.5f, -0.5f );
 
         TransformedModel model = upgrade.getModel( turtle.getAccess(), side );
         model.getMatrix().push( transform );
         renderModel( transform, renderer, lightmapCoord, overlayLight, model.getModel(), null );
-        transform.pop();
+        transform.popPose();
 
-        transform.pop();
+        transform.popPose();
     }
 
     private void renderModel( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder renderer, int lightmapCoord, int overlayLight, ModelResourceLocation modelLocation, int[] tints )
     {
-        ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelMesher().getModelManager();
+        ModelManager modelManager = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getModelManager();
         renderModel( transform, renderer, lightmapCoord, overlayLight, modelManager.getModel( modelLocation ), tints );
     }
 
@@ -171,12 +171,12 @@ public class TileEntityTurtleRenderer extends TileEntityRenderer
 
     private static void renderQuads( @Nonnull MatrixStack transform, @Nonnull IVertexBuilder buffer, int lightmapCoord, int overlayLight, List quads, int[] tints )
     {
-        MatrixStack.Entry matrix = transform.getLast();
+        MatrixStack.Entry matrix = transform.last();
 
         for( BakedQuad bakedquad : quads )
         {
             int tint = -1;
-            if( tints != null && bakedquad.hasTintIndex() )
+            if( tints != null && bakedquad.isTinted() )
             {
                 int idx = bakedquad.getTintIndex();
                 if( idx >= 0 && idx < tints.length ) tint = tints[bakedquad.getTintIndex()];
diff --git a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java
index 353166e47..d1eb8a585 100644
--- a/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java
+++ b/src/main/java/dan200/computercraft/client/render/TurtleModelLoader.java
@@ -43,7 +43,7 @@ public final class TurtleModelLoader implements IModelLoader getTextures( IModelConfiguration owner, Function modelGetter, Set> missingTextureErrors )
         {
             Set materials = new HashSet<>();
-            materials.addAll( modelGetter.apply( family ).getTextures( modelGetter, missingTextureErrors ) );
-            materials.addAll( modelGetter.apply( COLOUR_TURTLE_MODEL ).getTextures( modelGetter, missingTextureErrors ) );
+            materials.addAll( modelGetter.apply( family ).getMaterials( modelGetter, missingTextureErrors ) );
+            materials.addAll( modelGetter.apply( COLOUR_TURTLE_MODEL ).getMaterials( modelGetter, missingTextureErrors ) );
             return materials;
         }
 
diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java
index d690c5d40..b099ce309 100644
--- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java
+++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java
@@ -90,9 +90,9 @@ public class TurtleMultiModel implements IBakedModel
     }
 
     @Override
-    public boolean isAmbientOcclusion()
+    public boolean useAmbientOcclusion()
     {
-        return m_baseModel.isAmbientOcclusion();
+        return m_baseModel.useAmbientOcclusion();
     }
 
     @Override
@@ -102,31 +102,31 @@ public class TurtleMultiModel implements IBakedModel
     }
 
     @Override
-    public boolean isBuiltInRenderer()
+    public boolean isCustomRenderer()
     {
-        return m_baseModel.isBuiltInRenderer();
+        return m_baseModel.isCustomRenderer();
     }
 
     @Override
-    public boolean func_230044_c_()
+    public boolean usesBlockLight()
     {
-        return m_baseModel.func_230044_c_();
+        return m_baseModel.usesBlockLight();
     }
 
     @Nonnull
     @Override
     @Deprecated
-    public TextureAtlasSprite getParticleTexture()
+    public TextureAtlasSprite getParticleIcon()
     {
-        return m_baseModel.getParticleTexture();
+        return m_baseModel.getParticleIcon();
     }
 
     @Nonnull
     @Override
     @Deprecated
-    public net.minecraft.client.renderer.model.ItemCameraTransforms getItemCameraTransforms()
+    public net.minecraft.client.renderer.model.ItemCameraTransforms getTransforms()
     {
-        return m_baseModel.getItemCameraTransforms();
+        return m_baseModel.getTransforms();
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java
index 7fecf7514..ef05a8c92 100644
--- a/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java
+++ b/src/main/java/dan200/computercraft/client/render/TurtlePlayerRenderer.java
@@ -23,7 +23,7 @@ public class TurtlePlayerRenderer extends EntityRenderer
 
     @Nonnull
     @Override
-    public ResourceLocation getEntityTexture( @Nonnull TurtlePlayer entity )
+    public ResourceLocation getTextureLocation( @Nonnull TurtlePlayer entity )
     {
         return ComputerBorderRenderer.BACKGROUND_NORMAL;
     }
diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java
index 3488cf7b8..047e5470c 100644
--- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java
+++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java
@@ -42,7 +42,7 @@ public class TurtleSmartItemModel implements IBakedModel
         stack.translate( 0, 0, 1 );
 
         identity = TransformationMatrix.identity();
-        flip = new TransformationMatrix( stack.getLast().getMatrix() );
+        flip = new TransformationMatrix( stack.last().pose() );
     }
 
     private static class TurtleModelCombination
@@ -109,7 +109,7 @@ public class TurtleSmartItemModel implements IBakedModel
         {
             @Nonnull
             @Override
-            public IBakedModel getModelWithOverrides( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable LivingEntity entity )
+            public IBakedModel resolve( @Nonnull IBakedModel originalModel, @Nonnull ItemStack stack, @Nullable World world, @Nullable LivingEntity entity )
             {
                 ItemTurtle turtle = (ItemTurtle) stack.getItem();
                 int colour = turtle.getColour( stack );
@@ -138,7 +138,7 @@ public class TurtleSmartItemModel implements IBakedModel
     private IBakedModel buildModel( TurtleModelCombination combo )
     {
         Minecraft mc = Minecraft.getInstance();
-        ModelManager modelManager = mc.getItemRenderer().getItemModelMesher().getModelManager();
+        ModelManager modelManager = mc.getItemRenderer().getItemModelShaper().getModelManager();
         ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_overlay, combo.m_christmas );
 
         IBakedModel baseModel = combo.m_colour ? colourModel : familyModel;
@@ -166,9 +166,9 @@ public class TurtleSmartItemModel implements IBakedModel
     }
 
     @Override
-    public boolean isAmbientOcclusion()
+    public boolean useAmbientOcclusion()
     {
-        return familyModel.isAmbientOcclusion();
+        return familyModel.useAmbientOcclusion();
     }
 
     @Override
@@ -178,31 +178,31 @@ public class TurtleSmartItemModel implements IBakedModel
     }
 
     @Override
-    public boolean isBuiltInRenderer()
+    public boolean isCustomRenderer()
     {
-        return familyModel.isBuiltInRenderer();
+        return familyModel.isCustomRenderer();
     }
 
     @Override
-    public boolean func_230044_c_()
+    public boolean usesBlockLight()
     {
-        return familyModel.func_230044_c_();
+        return familyModel.usesBlockLight();
     }
 
     @Nonnull
     @Override
     @Deprecated
-    public TextureAtlasSprite getParticleTexture()
+    public TextureAtlasSprite getParticleIcon()
     {
-        return familyModel.getParticleTexture();
+        return familyModel.getParticleIcon();
     }
 
     @Nonnull
     @Override
     @Deprecated
-    public ItemCameraTransforms getItemCameraTransforms()
+    public ItemCameraTransforms getTransforms()
     {
-        return familyModel.getItemCameraTransforms();
+        return familyModel.getTransforms();
     }
 
 }
diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java
index 3931629f1..9aebcfd33 100644
--- a/src/main/java/dan200/computercraft/core/computer/Environment.java
+++ b/src/main/java/dan200/computercraft/core/computer/Environment.java
@@ -20,6 +20,8 @@ import javax.annotation.Nonnull;
 import java.util.Arrays;
 import java.util.Iterator;
 
+import dan200.computercraft.core.apis.IAPIEnvironment.IPeripheralChangeListener;
+
 /**
  * Represents the "environment" that a {@link Computer} exists in.
  *
diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
index 648a06ed0..ed21df789 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
@@ -104,7 +104,7 @@ public final class ResourceMount implements IMount
     {
         boolean hasAny = false;
         FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
-        for( ResourceLocation file : manager.getAllResourceLocations( subPath, s -> true ) )
+        for( ResourceLocation file : manager.listResources( subPath, s -> true ) )
         {
             if( !file.getNamespace().equals( namespace ) ) continue;
 
@@ -297,7 +297,7 @@ public final class ResourceMount implements IMount
 
         synchronized void add( IReloadableResourceManager manager, ResourceMount mount )
         {
-            if( managers.add( manager ) ) manager.addReloadListener( this );
+            if( managers.add( manager ) ) manager.registerReloadListener( this );
             mounts.add( mount );
         }
     }
diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java
index c336b9948..e0091c24e 100644
--- a/src/main/java/dan200/computercraft/data/BlockModelProvider.java
+++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java
@@ -52,7 +52,7 @@ public class BlockModelProvider extends BlockStateProvider
     private void registerComputer( BlockComputer block )
     {
         VariantBlockStateBuilder builder = getVariantBuilder( block );
-        for( ComputerState state : BlockComputer.STATE.getAllowedValues() )
+        for( ComputerState state : BlockComputer.STATE.getPossibleValues() )
         {
             BlockModelBuilder model = models()
                 .getBuilder( suffix( block, "_" + state ) )
@@ -61,7 +61,7 @@ public class BlockModelProvider extends BlockStateProvider
                 .texture( "side", suffix( block, "_side" ) )
                 .texture( "front", suffix( block, "_front" + toSuffix( state ) ) );
 
-            for( Direction facing : BlockComputer.FACING.getAllowedValues() )
+            for( Direction facing : BlockComputer.FACING.getPossibleValues() )
             {
                 builder.partialState()
                     .with( BlockComputer.STATE, state )
@@ -92,14 +92,14 @@ public class BlockModelProvider extends BlockStateProvider
         registerMonitorModel( name, "_ud", 21, 6, 0, 37 );
 
         VariantBlockStateBuilder builder = getVariantBuilder( block );
-        for( MonitorEdgeState edge : BlockMonitor.STATE.getAllowedValues() )
+        for( MonitorEdgeState edge : BlockMonitor.STATE.getPossibleValues() )
         {
-            String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getName();
+            String suffix = edge == MonitorEdgeState.NONE ? "" : "_" + edge.getSerializedName();
             ModelFile model = models().getBuilder( suffix( block, suffix ) );
 
-            for( Direction facing : BlockMonitor.FACING.getAllowedValues() )
+            for( Direction facing : BlockMonitor.FACING.getPossibleValues() )
             {
-                for( Direction orientation : BlockMonitor.ORIENTATION.getAllowedValues() )
+                for( Direction orientation : BlockMonitor.ORIENTATION.getPossibleValues() )
                 {
                     builder.partialState()
                         .with( BlockMonitor.STATE, edge )
@@ -137,7 +137,7 @@ public class BlockModelProvider extends BlockStateProvider
 
     private static int toYAngle( Direction direction )
     {
-        return ((int) direction.getHorizontalAngle() + 180) % 360;
+        return ((int) direction.toYRot() + 180) % 360;
     }
 
     private static String toSuffix( ComputerState state )
diff --git a/src/main/java/dan200/computercraft/data/LootTableProvider.java b/src/main/java/dan200/computercraft/data/LootTableProvider.java
index b76ca31bd..3345bafea 100644
--- a/src/main/java/dan200/computercraft/data/LootTableProvider.java
+++ b/src/main/java/dan200/computercraft/data/LootTableProvider.java
@@ -40,17 +40,17 @@ public abstract class LootTableProvider implements IDataProvider
     }
 
     @Override
-    public void act( @Nonnull DirectoryCache cache )
+    public void run( @Nonnull DirectoryCache cache )
     {
         Map tables = new HashMap<>();
-        ValidationTracker validation = new ValidationTracker( LootParameterSets.GENERIC, x -> null, tables::get );
+        ValidationTracker validation = new ValidationTracker( LootParameterSets.ALL_PARAMS, x -> null, tables::get );
 
         registerLoot( ( id, table ) -> {
-            if( tables.containsKey( id ) ) validation.addProblem( "Duplicate loot tables for " + id );
+            if( tables.containsKey( id ) ) validation.reportProblem( "Duplicate loot tables for " + id );
             tables.put( id, table );
         } );
 
-        tables.forEach( ( key, value ) -> LootTableManager.func_227508_a_( validation, key, value ) );
+        tables.forEach( ( key, value ) -> LootTableManager.validate( validation, key, value ) );
 
         Multimap problems = validation.getProblems();
         if( !problems.isEmpty() )
@@ -64,7 +64,7 @@ public abstract class LootTableProvider implements IDataProvider
             Path path = getPath( key );
             try
             {
-                IDataProvider.save( GSON, cache, LootTableManager.toJson( value ), path );
+                IDataProvider.save( GSON, cache, LootTableManager.serialize( value ), path );
             }
             catch( IOException e )
             {
diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java
index df7d1c8ed..9c3f9639e 100644
--- a/src/main/java/dan200/computercraft/data/LootTables.java
+++ b/src/main/java/dan200/computercraft/data/LootTables.java
@@ -47,8 +47,8 @@ public class LootTables extends LootTableProvider
         computerDrop( add, Registry.ModBlocks.TURTLE_ADVANCED );
 
         add.accept( ComputerCraftProxyCommon.ForgeHandlers.LOOT_TREASURE_DISK, LootTable
-            .builder()
-            .setParameterSet( LootParameterSets.GENERIC )
+            .lootTable()
+            .setParamSet( LootParameterSets.ALL_PARAMS )
             .build() );
     }
 
@@ -56,13 +56,13 @@ public class LootTables extends LootTableProvider
     {
         Block block = wrapper.get();
         add.accept( block.getLootTable(), LootTable
-            .builder()
-            .setParameterSet( LootParameterSets.BLOCK )
-            .addLootPool( LootPool.builder()
+            .lootTable()
+            .setParamSet( LootParameterSets.BLOCK )
+            .withPool( LootPool.lootPool()
                 .name( "main" )
-                .rolls( ConstantRange.of( 1 ) )
-                .addEntry( ItemLootEntry.builder( block ) )
-                .acceptCondition( SurvivesExplosion.builder() )
+                .setRolls( ConstantRange.exactly( 1 ) )
+                .add( ItemLootEntry.lootTableItem( block ) )
+                .when( SurvivesExplosion.survivesExplosion() )
             ).build() );
     }
 
@@ -70,16 +70,16 @@ public class LootTables extends LootTableProvider
     {
         Block block = wrapper.get();
         add.accept( block.getLootTable(), LootTable
-            .builder()
-            .setParameterSet( LootParameterSets.BLOCK )
-            .addLootPool( LootPool.builder()
+            .lootTable()
+            .setParamSet( LootParameterSets.BLOCK )
+            .withPool( LootPool.lootPool()
                 .name( "main" )
-                .rolls( ConstantRange.of( 1 ) )
-                .addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) )
-                .acceptCondition( Alternative.builder(
+                .setRolls( ConstantRange.exactly( 1 ) )
+                .add( DynamicLootEntry.dynamicEntry( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) )
+                .when( Alternative.alternative(
                     BlockNamedEntityLootCondition.builder(),
                     HasComputerIdLootCondition.builder(),
-                    PlayerCreativeLootCondition.builder().inverted()
+                    PlayerCreativeLootCondition.builder().invert()
                 ) )
             ).build() );
     }
diff --git a/src/main/java/dan200/computercraft/data/RecipeWrapper.java b/src/main/java/dan200/computercraft/data/RecipeWrapper.java
index 8fd20d3b5..160a24ec6 100644
--- a/src/main/java/dan200/computercraft/data/RecipeWrapper.java
+++ b/src/main/java/dan200/computercraft/data/RecipeWrapper.java
@@ -50,42 +50,42 @@ public final class RecipeWrapper implements IFinishedRecipe
     }
 
     @Override
-    public void serialize( @Nonnull JsonObject jsonObject )
+    public void serializeRecipeData( @Nonnull JsonObject jsonObject )
     {
-        recipe.serialize( jsonObject );
+        recipe.serializeRecipeData( jsonObject );
 
         if( resultData != null )
         {
-            JsonObject object = JSONUtils.getJsonObject( jsonObject, "result" );
+            JsonObject object = JSONUtils.getAsJsonObject( jsonObject, "result" );
             object.addProperty( "nbt", resultData.toString() );
         }
     }
 
     @Nonnull
     @Override
-    public ResourceLocation getID()
+    public ResourceLocation getId()
     {
-        return recipe.getID();
+        return recipe.getId();
     }
 
     @Nonnull
     @Override
-    public IRecipeSerializer getSerializer()
+    public IRecipeSerializer getType()
     {
         return serializer;
     }
 
     @Nullable
     @Override
-    public JsonObject getAdvancementJson()
+    public JsonObject serializeAdvancement()
     {
-        return recipe.getAdvancementJson();
+        return recipe.serializeAdvancement();
     }
 
     @Nullable
     @Override
-    public ResourceLocation getAdvancementID()
+    public ResourceLocation getAdvancementId()
     {
-        return recipe.getAdvancementID();
+        return recipe.getAdvancementId();
     }
 }
diff --git a/src/main/java/dan200/computercraft/data/Recipes.java b/src/main/java/dan200/computercraft/data/Recipes.java
index 6c1b62dae..d8b294170 100644
--- a/src/main/java/dan200/computercraft/data/Recipes.java
+++ b/src/main/java/dan200/computercraft/data/Recipes.java
@@ -39,7 +39,7 @@ public class Recipes extends RecipeProvider
     }
 
     @Override
-    protected void registerRecipes( @Nonnull Consumer add )
+    protected void buildShapelessRecipes( @Nonnull Consumer add )
     {
         basicRecipes( add );
         diskColours( add );
@@ -57,13 +57,13 @@ public class Recipes extends RecipeProvider
         for( Colour colour : Colour.VALUES )
         {
             ShapelessRecipeBuilder
-                .shapelessRecipe( Registry.ModItems.DISK.get() )
-                .addIngredient( Tags.Items.DUSTS_REDSTONE )
-                .addIngredient( Items.PAPER )
-                .addIngredient( DyeItem.getItem( ofColour( colour ) ) )
-                .setGroup( "computercraft:disk" )
-                .addCriterion( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE.get() ) )
-                .build( RecipeWrapper.wrap(
+                .shapeless( Registry.ModItems.DISK.get() )
+                .requires( Tags.Items.DUSTS_REDSTONE )
+                .requires( Items.PAPER )
+                .requires( DyeItem.byColor( ofColour( colour ) ) )
+                .group( "computercraft:disk" )
+                .unlocks( "has_drive", inventoryChange( Registry.ModBlocks.DISK_DRIVE.get() ) )
+                .save( RecipeWrapper.wrap(
                     ImpostorShapelessRecipe.SERIALIZER, add,
                     x -> x.putInt( IColouredItem.NBT_COLOUR, colour.getHex() )
                 ), new ResourceLocation( ComputerCraft.MOD_ID, "disk_" + (colour.ordinal() + 1) ) );
@@ -87,14 +87,14 @@ public class Recipes extends RecipeProvider
             TurtleUpgrades.getVanillaUpgrades().forEach( upgrade -> {
                 ItemStack result = TurtleItemFactory.create( -1, null, -1, family, null, upgrade, -1, null );
                 ShapedRecipeBuilder
-                    .shapedRecipe( result.getItem() )
-                    .setGroup( String.format( "%s:turtle_%s", ComputerCraft.MOD_ID, nameId ) )
-                    .patternLine( "#T" )
-                    .key( '#', base.getItem() )
-                    .key( 'T', upgrade.getCraftingItem().getItem() )
-                    .addCriterion( "has_items",
+                    .shaped( result.getItem() )
+                    .group( String.format( "%s:turtle_%s", ComputerCraft.MOD_ID, nameId ) )
+                    .pattern( "#T" )
+                    .define( '#', base.getItem() )
+                    .define( 'T', upgrade.getCraftingItem().getItem() )
+                    .unlocks( "has_items",
                         inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) )
-                    .build(
+                    .save(
                         RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ),
                         new ResourceLocation( ComputerCraft.MOD_ID, String.format( "turtle_%s/%s/%s",
                             nameId, upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath()
@@ -121,15 +121,15 @@ public class Recipes extends RecipeProvider
             PocketUpgrades.getVanillaUpgrades().forEach( upgrade -> {
                 ItemStack result = PocketComputerItemFactory.create( -1, null, -1, family, null );
                 ShapedRecipeBuilder
-                    .shapedRecipe( result.getItem() )
-                    .setGroup( String.format( "%s:pocket_%s", ComputerCraft.MOD_ID, nameId ) )
-                    .patternLine( "#" )
-                    .patternLine( "P" )
-                    .key( '#', base.getItem() )
-                    .key( 'P', upgrade.getCraftingItem().getItem() )
-                    .addCriterion( "has_items",
+                    .shaped( result.getItem() )
+                    .group( String.format( "%s:pocket_%s", ComputerCraft.MOD_ID, nameId ) )
+                    .pattern( "#" )
+                    .pattern( "P" )
+                    .define( '#', base.getItem() )
+                    .define( 'P', upgrade.getCraftingItem().getItem() )
+                    .unlocks( "has_items",
                         inventoryChange( base.getItem(), upgrade.getCraftingItem().getItem() ) )
-                    .build(
+                    .save(
                         RecipeWrapper.wrap( ImpostorRecipe.SERIALIZER, add, result.getTag() ),
                         new ResourceLocation( ComputerCraft.MOD_ID, String.format( "pocket_%s/%s/%s",
                             nameId, upgrade.getUpgradeID().getNamespace(), upgrade.getUpgradeID().getPath()
@@ -142,167 +142,167 @@ public class Recipes extends RecipeProvider
     private void basicRecipes( @Nonnull Consumer add )
     {
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModItems.CABLE.get(), 6 )
-            .patternLine( " # " )
-            .patternLine( "#R#" )
-            .patternLine( " # " )
-            .key( '#', Tags.Items.STONE )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .addCriterion( "has_modem", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModItems.CABLE.get(), 6 )
+            .pattern( " # " )
+            .pattern( "#R#" )
+            .pattern( " # " )
+            .define( '#', Tags.Items.STONE )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .unlocks( "has_modem", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.COMPUTER_NORMAL.get() )
-            .patternLine( "###" )
-            .patternLine( "#R#" )
-            .patternLine( "#G#" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_redstone", inventoryChange( Tags.Items.DUSTS_REDSTONE ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.COMPUTER_NORMAL.get() )
+            .pattern( "###" )
+            .pattern( "#R#" )
+            .pattern( "#G#" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_redstone", inventoryChange( Tags.Items.DUSTS_REDSTONE ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.COMPUTER_ADVANCED.get() )
-            .patternLine( "###" )
-            .patternLine( "#R#" )
-            .patternLine( "#G#" )
-            .key( '#', Tags.Items.INGOTS_GOLD )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.COMPUTER_ADVANCED.get() )
+            .pattern( "###" )
+            .pattern( "#R#" )
+            .pattern( "#G#" )
+            .define( '#', Tags.Items.INGOTS_GOLD )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_components", inventoryChange( Items.REDSTONE, Items.GOLD_INGOT ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.COMPUTER_COMMAND.get() )
-            .patternLine( "###" )
-            .patternLine( "#R#" )
-            .patternLine( "#G#" )
-            .key( '#', Tags.Items.INGOTS_GOLD )
-            .key( 'R', Blocks.COMMAND_BLOCK )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.COMPUTER_COMMAND.get() )
+            .pattern( "###" )
+            .pattern( "#R#" )
+            .pattern( "#G#" )
+            .define( '#', Tags.Items.INGOTS_GOLD )
+            .define( 'R', Blocks.COMMAND_BLOCK )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_components", inventoryChange( Blocks.COMMAND_BLOCK ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.DISK_DRIVE.get() )
-            .patternLine( "###" )
-            .patternLine( "#R#" )
-            .patternLine( "#R#" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.DISK_DRIVE.get() )
+            .pattern( "###" )
+            .pattern( "#R#" )
+            .pattern( "#R#" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.MONITOR_NORMAL.get() )
-            .patternLine( "###" )
-            .patternLine( "#G#" )
-            .patternLine( "###" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.MONITOR_NORMAL.get() )
+            .pattern( "###" )
+            .pattern( "#G#" )
+            .pattern( "###" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.MONITOR_ADVANCED.get(), 4 )
-            .patternLine( "###" )
-            .patternLine( "#G#" )
-            .patternLine( "###" )
-            .key( '#', Tags.Items.INGOTS_GOLD )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.MONITOR_ADVANCED.get(), 4 )
+            .pattern( "###" )
+            .pattern( "#G#" )
+            .pattern( "###" )
+            .define( '#', Tags.Items.INGOTS_GOLD )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModItems.POCKET_COMPUTER_NORMAL.get() )
-            .patternLine( "###" )
-            .patternLine( "#A#" )
-            .patternLine( "#G#" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'A', Items.GOLDEN_APPLE )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .addCriterion( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
-            .build( add );
+            .shaped( Registry.ModItems.POCKET_COMPUTER_NORMAL.get() )
+            .pattern( "###" )
+            .pattern( "#A#" )
+            .pattern( "#G#" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'A', Items.GOLDEN_APPLE )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .unlocks( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModItems.POCKET_COMPUTER_ADVANCED.get() )
-            .patternLine( "###" )
-            .patternLine( "#A#" )
-            .patternLine( "#G#" )
-            .key( '#', Tags.Items.INGOTS_GOLD )
-            .key( 'A', Items.GOLDEN_APPLE )
-            .key( 'G', Tags.Items.GLASS_PANES )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .addCriterion( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
-            .build( add );
+            .shaped( Registry.ModItems.POCKET_COMPUTER_ADVANCED.get() )
+            .pattern( "###" )
+            .pattern( "#A#" )
+            .pattern( "#G#" )
+            .define( '#', Tags.Items.INGOTS_GOLD )
+            .define( 'A', Items.GOLDEN_APPLE )
+            .define( 'G', Tags.Items.GLASS_PANES )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .unlocks( "has_apple", inventoryChange( Items.GOLDEN_APPLE ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.PRINTER.get() )
-            .patternLine( "###" )
-            .patternLine( "#R#" )
-            .patternLine( "#D#" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .key( 'D', Tags.Items.DYES )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.PRINTER.get() )
+            .pattern( "###" )
+            .pattern( "#R#" )
+            .pattern( "#D#" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .define( 'D', Tags.Items.DYES )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.SPEAKER.get() )
-            .patternLine( "###" )
-            .patternLine( "#N#" )
-            .patternLine( "#R#" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'N', Blocks.NOTE_BLOCK )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.SPEAKER.get() )
+            .pattern( "###" )
+            .pattern( "#N#" )
+            .pattern( "#R#" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'N', Blocks.NOTE_BLOCK )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModItems.WIRED_MODEM.get() )
-            .patternLine( "###" )
-            .patternLine( "#R#" )
-            .patternLine( "###" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'R', Tags.Items.DUSTS_REDSTONE )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .addCriterion( "has_cable", inventoryChange( Registry.ModItems.CABLE.get() ) )
-            .build( add );
+            .shaped( Registry.ModItems.WIRED_MODEM.get() )
+            .pattern( "###" )
+            .pattern( "#R#" )
+            .pattern( "###" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'R', Tags.Items.DUSTS_REDSTONE )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .unlocks( "has_cable", inventoryChange( Registry.ModItems.CABLE.get() ) )
+            .save( add );
 
         ShapelessRecipeBuilder
-            .shapelessRecipe( Registry.ModBlocks.WIRED_MODEM_FULL.get() )
-            .addIngredient( Registry.ModItems.WIRED_MODEM.get() )
-            .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
-            .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) );
+            .shapeless( Registry.ModBlocks.WIRED_MODEM_FULL.get() )
+            .requires( Registry.ModItems.WIRED_MODEM.get() )
+            .unlocks( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
+            .save( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_from" ) );
         ShapelessRecipeBuilder
-            .shapelessRecipe( Registry.ModItems.WIRED_MODEM.get() )
-            .addIngredient( Registry.ModBlocks.WIRED_MODEM_FULL.get() )
-            .addCriterion( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
-            .build( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) );
+            .shapeless( Registry.ModItems.WIRED_MODEM.get() )
+            .requires( Registry.ModBlocks.WIRED_MODEM_FULL.get() )
+            .unlocks( "has_modem", inventoryChange( CCTags.WIRED_MODEM ) )
+            .save( add, new ResourceLocation( ComputerCraft.MOD_ID, "wired_modem_full_to" ) );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() )
-            .patternLine( "###" )
-            .patternLine( "#E#" )
-            .patternLine( "###" )
-            .key( '#', Tags.Items.STONE )
-            .key( 'E', Tags.Items.ENDER_PEARLS )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() )
+            .pattern( "###" )
+            .pattern( "#E#" )
+            .pattern( "###" )
+            .define( '#', Tags.Items.STONE )
+            .define( 'E', Tags.Items.ENDER_PEARLS )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .save( add );
 
         ShapedRecipeBuilder
-            .shapedRecipe( Registry.ModBlocks.WIRELESS_MODEM_ADVANCED.get() )
-            .patternLine( "###" )
-            .patternLine( "#E#" )
-            .patternLine( "###" )
-            .key( '#', Tags.Items.INGOTS_GOLD )
-            .key( 'E', Items.ENDER_EYE )
-            .addCriterion( "has_computer", inventoryChange( CCTags.COMPUTER ) )
-            .addCriterion( "has_wireless", inventoryChange( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() ) )
-            .build( add );
+            .shaped( Registry.ModBlocks.WIRELESS_MODEM_ADVANCED.get() )
+            .pattern( "###" )
+            .pattern( "#E#" )
+            .pattern( "###" )
+            .define( '#', Tags.Items.INGOTS_GOLD )
+            .define( 'E', Items.ENDER_EYE )
+            .unlocks( "has_computer", inventoryChange( CCTags.COMPUTER ) )
+            .unlocks( "has_wireless", inventoryChange( Registry.ModBlocks.WIRELESS_MODEM_NORMAL.get() ) )
+            .save( add );
     }
 
     private static DyeColor ofColour( Colour colour )
@@ -312,11 +312,11 @@ public class Recipes extends RecipeProvider
 
     private static InventoryChangeTrigger.Instance inventoryChange( Tag stack )
     {
-        return InventoryChangeTrigger.Instance.forItems( ItemPredicate.Builder.create().tag( stack ).build() );
+        return InventoryChangeTrigger.Instance.hasItem( ItemPredicate.Builder.item().of( stack ).build() );
     }
 
     private static InventoryChangeTrigger.Instance inventoryChange( IItemProvider... stack )
     {
-        return InventoryChangeTrigger.Instance.forItems( stack );
+        return InventoryChangeTrigger.Instance.hasItem( stack );
     }
 }
diff --git a/src/main/java/dan200/computercraft/data/Tags.java b/src/main/java/dan200/computercraft/data/Tags.java
index 2556e4fae..12f17b59e 100644
--- a/src/main/java/dan200/computercraft/data/Tags.java
+++ b/src/main/java/dan200/computercraft/data/Tags.java
@@ -32,15 +32,15 @@ public class Tags extends ItemTagsProvider
     }
 
     @Override
-    protected void registerTags()
+    protected void addTags()
     {
-        getBuilder( COMPUTER )
+        tag( COMPUTER )
             .add( Registry.ModItems.COMPUTER_NORMAL.get() )
             .add( Registry.ModItems.COMPUTER_ADVANCED.get() )
             .add( Registry.ModItems.COMPUTER_COMMAND.get() );
-        getBuilder( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() );
-        getBuilder( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() );
-        getBuilder( MONITOR )
+        tag( TURTLE ).add( Registry.ModItems.TURTLE_NORMAL.get(), Registry.ModItems.TURTLE_ADVANCED.get() );
+        tag( WIRED_MODEM ).add( Registry.ModItems.WIRED_MODEM.get(), Registry.ModItems.WIRED_MODEM_FULL.get() );
+        tag( MONITOR )
             .add( Registry.ModItems.MONITOR_NORMAL.get() )
             .add( Registry.ModItems.MONITOR_ADVANCED.get() );
     }
diff --git a/src/main/java/dan200/computercraft/shared/BundledRedstone.java b/src/main/java/dan200/computercraft/shared/BundledRedstone.java
index f2ae897a7..d6894fc2a 100644
--- a/src/main/java/dan200/computercraft/shared/BundledRedstone.java
+++ b/src/main/java/dan200/computercraft/shared/BundledRedstone.java
@@ -31,12 +31,12 @@ public final class BundledRedstone
 
     public static int getDefaultOutput( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
     {
-        return World.isValid( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1;
+        return World.isInWorldBounds( pos ) ? DefaultBundledRedstoneProvider.getDefaultBundledRedstoneOutput( world, pos, side ) : -1;
     }
 
     private static int getUnmaskedOutput( World world, BlockPos pos, Direction side )
     {
-        if( !World.isValid( pos ) ) return -1;
+        if( !World.isInWorldBounds( pos ) ) return -1;
 
         // Try the providers in order:
         int combinedSignal = -1;
diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java
index 4a61a226a..a3e43029b 100644
--- a/src/main/java/dan200/computercraft/shared/Config.java
+++ b/src/main/java/dan200/computercraft/shared/Config.java
@@ -31,6 +31,9 @@ import java.util.stream.Collectors;
 import static net.minecraftforge.common.ForgeConfigSpec.Builder;
 import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
 
+import net.minecraftforge.common.ForgeConfigSpec.Builder;
+import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
+
 @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD )
 public final class Config
 {
diff --git a/src/main/java/dan200/computercraft/shared/Peripherals.java b/src/main/java/dan200/computercraft/shared/Peripherals.java
index b30185de9..1f809ccb9 100644
--- a/src/main/java/dan200/computercraft/shared/Peripherals.java
+++ b/src/main/java/dan200/computercraft/shared/Peripherals.java
@@ -40,13 +40,13 @@ public final class Peripherals
     @Nullable
     public static IPeripheral getPeripheral( World world, BlockPos pos, Direction side, NonNullConsumer> invalidate )
     {
-        return World.isValid( pos ) && !world.isRemote ? getPeripheralAt( world, pos, side, invalidate ) : null;
+        return World.isInWorldBounds( pos ) && !world.isClientSide ? getPeripheralAt( world, pos, side, invalidate ) : null;
     }
 
     @Nullable
     private static IPeripheral getPeripheralAt( World world, BlockPos pos, Direction side, NonNullConsumer> invalidate )
     {
-        TileEntity block = world.getTileEntity( pos );
+        TileEntity block = world.getBlockEntity( pos );
         if( block != null )
         {
             LazyOptional peripheral = block.getCapability( CAPABILITY_PERIPHERAL, side );
diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java
index 5bbdf3bec..dd9240465 100644
--- a/src/main/java/dan200/computercraft/shared/Registry.java
+++ b/src/main/java/dan200/computercraft/shared/Registry.java
@@ -96,17 +96,17 @@ public final class Registry
 
         private static Block.Properties properties()
         {
-            return Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2 );
+            return Block.Properties.of( Material.STONE ).strength( 2 );
         }
 
         private static Block.Properties turtleProperties()
         {
-            return Block.Properties.create( Material.ROCK ).hardnessAndResistance( 2.5f );
+            return Block.Properties.of( Material.STONE ).strength( 2.5f );
         }
 
         private static Block.Properties modemProperties()
         {
-            return Block.Properties.create( Material.ROCK ).hardnessAndResistance( 1.5f );
+            return Block.Properties.of( Material.STONE ).strength( 1.5f );
         }
 
         public static final RegistryObject COMPUTER_NORMAL = BLOCKS.register( "computer_normal",
@@ -115,7 +115,7 @@ public final class Registry
             () -> new BlockComputer( properties(), ComputerFamily.ADVANCED, ModTiles.COMPUTER_ADVANCED ) );
 
         public static final RegistryObject COMPUTER_COMMAND = BLOCKS.register( "computer_command", () -> new BlockComputer(
-            Block.Properties.create( Material.ROCK ).hardnessAndResistance( -1, 6000000.0F ),
+            Block.Properties.of( Material.STONE ).strength( -1, 6000000.0F ),
             ComputerFamily.COMMAND, ModTiles.COMPUTER_COMMAND
         ) );
 
@@ -187,7 +187,7 @@ public final class Registry
 
         private static Item.Properties properties()
         {
-            return new Item.Properties().group( mainItemGroup );
+            return new Item.Properties().tab( mainItemGroup );
         }
 
         private static  RegistryObject ofBlock( RegistryObject parent, BiFunction supplier )
@@ -200,24 +200,24 @@ public final class Registry
         public static final RegistryObject COMPUTER_COMMAND = ofBlock( ModBlocks.COMPUTER_COMMAND, ItemComputer::new );
 
         public static final RegistryObject POCKET_COMPUTER_NORMAL = ITEMS.register( "pocket_computer_normal",
-            () -> new ItemPocketComputer( properties().maxStackSize( 1 ), ComputerFamily.NORMAL ) );
+            () -> new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.NORMAL ) );
         public static final RegistryObject POCKET_COMPUTER_ADVANCED = ITEMS.register( "pocket_computer_advanced",
-            () -> new ItemPocketComputer( properties().maxStackSize( 1 ), ComputerFamily.ADVANCED ) );
+            () -> new ItemPocketComputer( properties().stacksTo( 1 ), ComputerFamily.ADVANCED ) );
 
         public static final RegistryObject TURTLE_NORMAL = ofBlock( ModBlocks.TURTLE_NORMAL, ItemTurtle::new );
         public static final RegistryObject TURTLE_ADVANCED = ofBlock( ModBlocks.TURTLE_ADVANCED, ItemTurtle::new );
 
         public static final RegistryObject DISK =
-            ITEMS.register( "disk", () -> new ItemDisk( properties().maxStackSize( 1 ) ) );
+            ITEMS.register( "disk", () -> new ItemDisk( properties().stacksTo( 1 ) ) );
         public static final RegistryObject TREASURE_DISK =
-            ITEMS.register( "treasure_disk", () -> new ItemTreasureDisk( properties().maxStackSize( 1 ) ) );
+            ITEMS.register( "treasure_disk", () -> new ItemTreasureDisk( properties().stacksTo( 1 ) ) );
 
         public static final RegistryObject PRINTED_PAGE = ITEMS.register( "printed_page",
-            () -> new ItemPrintout( properties().maxStackSize( 1 ), ItemPrintout.Type.PAGE ) );
+            () -> new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGE ) );
         public static final RegistryObject PRINTED_PAGES = ITEMS.register( "printed_pages",
-            () -> new ItemPrintout( properties().maxStackSize( 1 ), ItemPrintout.Type.PAGES ) );
+            () -> new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.PAGES ) );
         public static final RegistryObject PRINTED_BOOK = ITEMS.register( "printed_book",
-            () -> new ItemPrintout( properties().maxStackSize( 1 ), ItemPrintout.Type.BOOK ) );
+            () -> new ItemPrintout( properties().stacksTo( 1 ), ItemPrintout.Type.BOOK ) );
 
         public static final RegistryObject SPEAKER = ofBlock( ModBlocks.SPEAKER, BlockItem::new );
         public static final RegistryObject DISK_DRIVE = ofBlock( ModBlocks.DISK_DRIVE, BlockItem::new );
@@ -284,10 +284,10 @@ public final class Registry
         static final DeferredRegister> ENTITIES = new DeferredRegister<>( ForgeRegistries.ENTITIES, ComputerCraft.MOD_ID );
 
         public static final RegistryObject> TURTLE_PLAYER = ENTITIES.register( "turtle_player", () ->
-            EntityType.Builder.create( EntityClassification.MISC )
-                .disableSerialization()
-                .disableSummoning()
-                .size( 0, 0 )
+            EntityType.Builder.createNothing( EntityClassification.MISC )
+                .noSave()
+                .noSummon()
+                .sized( 0, 0 )
                 .build( ComputerCraft.MOD_ID + ":turtle_player" ) );
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java
index 4593035d9..7fd6b9b6a 100644
--- a/src/main/java/dan200/computercraft/shared/TurtlePermissions.java
+++ b/src/main/java/dan200/computercraft/shared/TurtlePermissions.java
@@ -20,13 +20,13 @@ public final class TurtlePermissions
     public static boolean isBlockEnterable( World world, BlockPos pos, PlayerEntity player )
     {
         MinecraftServer server = world.getServer();
-        return server == null || world.isRemote || !server.isBlockProtected( world, pos, player );
+        return server == null || world.isClientSide || !server.isUnderSpawnProtection( world, pos, player );
     }
 
     public static boolean isBlockEditable( World world, BlockPos pos, PlayerEntity player )
     {
         MinecraftServer server = world.getServer();
-        return server == null || world.isRemote || !server.isBlockProtected( world, pos, player );
+        return server == null || world.isClientSide || !server.isUnderSpawnProtection( world, pos, player );
     }
 
     @SubscribeEvent
diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java
index 95617d03d..33ae57947 100644
--- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java
+++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java
@@ -75,13 +75,13 @@ public final class CommandComputerCraft
                     List computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
 
                     // Unless we're on a server, limit the number of rows we can send.
-                    World world = source.getWorld();
-                    BlockPos pos = new BlockPos( source.getPos() );
+                    World world = source.getLevel();
+                    BlockPos pos = new BlockPos( source.getPosition() );
 
                     computers.sort( ( a, b ) -> {
                         if( a.getWorld() == b.getWorld() && a.getWorld() == world )
                         {
-                            return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) );
+                            return Double.compare( a.getPosition().distSqr( pos ), b.getPosition().distSqr( pos ) );
                         }
                         else if( a.getWorld() == world )
                         {
@@ -145,7 +145,7 @@ public final class CommandComputerCraft
                         if( computer.isOn() ) shutdown++;
                         computer.shutdown();
                     }
-                    context.getSource().sendFeedback( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false );
+                    context.getSource().sendSuccess( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false );
                     return shutdown;
                 } ) )
 
@@ -159,7 +159,7 @@ public final class CommandComputerCraft
                         if( !computer.isOn() ) on++;
                         computer.turnOn();
                     }
-                    context.getSource().sendFeedback( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false );
+                    context.getSource().sendSuccess( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false );
                     return on;
                 } ) )
 
@@ -173,20 +173,20 @@ public final class CommandComputerCraft
 
                     if( world == null || pos == null ) throw TP_NOT_THERE.create();
 
-                    Entity entity = context.getSource().assertIsEntity();
+                    Entity entity = context.getSource().getEntityOrException();
                     if( !(entity instanceof ServerPlayerEntity) ) throw TP_NOT_PLAYER.create();
 
                     ServerPlayerEntity player = (ServerPlayerEntity) entity;
-                    if( player.getEntityWorld() == world )
+                    if( player.getCommandSenderWorld() == world )
                     {
-                        player.connection.setPlayerLocation(
+                        player.connection.teleport(
                             pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0,
                             EnumSet.noneOf( SPlayerPositionLookPacket.Flags.class )
                         );
                     }
                     else
                     {
-                        player.teleport( (ServerWorld) world,
+                        player.teleportTo( (ServerWorld) world,
                             pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0
                         );
                     }
@@ -219,7 +219,7 @@ public final class CommandComputerCraft
                 .requires( UserLevel.OP )
                 .arg( "computer", oneComputer() )
                 .executes( context -> {
-                    ServerPlayerEntity player = context.getSource().asPlayer();
+                    ServerPlayerEntity player = context.getSource().getPlayerOrException();
                     ServerComputer computer = getComputerArgument( context, "computer" );
                     new ViewComputerContainerData( computer ).open( player, new INamedContainerProvider()
                     {
@@ -247,7 +247,7 @@ public final class CommandComputerCraft
                         getTimingContext( context.getSource() ).start();
 
                         String stopCommand = "/computercraft track stop";
-                        context.getSource().sendFeedback( translate( "commands.computercraft.track.start.stop",
+                        context.getSource().sendSuccess( translate( "commands.computercraft.track.start.stop",
                             link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) ), false );
                         return 1;
                     } ) )
@@ -288,11 +288,11 @@ public final class CommandComputerCraft
         // Append the computer instance
         if( serverComputer == null )
         {
-            out.appendSibling( text( "?" ) );
+            out.append( text( "?" ) );
         }
         else
         {
-            out.appendSibling( link(
+            out.append( link(
                 text( Integer.toString( serverComputer.getInstanceID() ) ),
                 "/computercraft dump " + serverComputer.getInstanceID(),
                 translate( "commands.computercraft.dump.action" )
@@ -300,20 +300,20 @@ public final class CommandComputerCraft
         }
 
         // And ID
-        out.appendText( " (id " + computerId + ")" );
+        out.append( " (id " + computerId + ")" );
 
         // And, if we're a player, some useful links
         if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) )
         {
             out
-                .appendText( " " )
-                .appendSibling( link(
+                .append( " " )
+                .append( link(
                     text( "\u261b" ),
                     "/computercraft tp " + serverComputer.getInstanceID(),
                     translate( "commands.computercraft.tp.action" )
                 ) )
-                .appendText( " " )
-                .appendSibling( link(
+                .append( " " )
+                .append( link(
                     text( "\u20e2" ),
                     "/computercraft view " + serverComputer.getInstanceID(),
                     translate( "commands.computercraft.view.action" )
@@ -343,7 +343,7 @@ public final class CommandComputerCraft
     private static TrackingContext getTimingContext( CommandSource source )
     {
         Entity entity = source.getEntity();
-        return entity instanceof PlayerEntity ? Tracking.getContext( entity.getUniqueID() ) : Tracking.getContext( SYSTEM_UUID );
+        return entity instanceof PlayerEntity ? Tracking.getContext( entity.getUUID() ) : Tracking.getContext( SYSTEM_UUID );
     }
 
     private static final List DEFAULT_FIELDS = Arrays.asList( TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME );
diff --git a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java
index b5d1a9b80..435346c20 100644
--- a/src/main/java/dan200/computercraft/shared/command/CommandCopy.java
+++ b/src/main/java/dan200/computercraft/shared/command/CommandCopy.java
@@ -38,7 +38,7 @@ public final class CommandCopy
             .then( literal( "copy" ) )
             .then( argument( "message", StringArgumentType.greedyString() ) )
             .executes( context -> {
-                Minecraft.getInstance().keyboardListener.setClipboardString( context.getArgument( "message", String.class ) );
+                Minecraft.getInstance().keyboardHandler.setClipboard( context.getArgument( "message", String.class ) );
                 return 1;
             } )
         );
@@ -50,7 +50,7 @@ public final class CommandCopy
         // Emulate the command on the client side
         if( event.getMessage().startsWith( PREFIX ) )
         {
-            Minecraft.getInstance().keyboardListener.setClipboardString( event.getMessage().substring( PREFIX.length() ) );
+            Minecraft.getInstance().keyboardHandler.setClipboard( event.getMessage().substring( PREFIX.length() ) );
             event.setCanceled( true );
         }
     }
diff --git a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java
index 199ebb45a..85dc4d566 100644
--- a/src/main/java/dan200/computercraft/shared/command/CommandUtils.java
+++ b/src/main/java/dan200/computercraft/shared/command/CommandUtils.java
@@ -45,7 +45,7 @@ public final class CommandUtils
         }
         else
         {
-            return ((ISuggestionProvider) source).getSuggestionsFromServer( (CommandContext) context, builder );
+            return ((ISuggestionProvider) source).customSuggestion( (CommandContext) context, builder );
         }
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/command/UserLevel.java b/src/main/java/dan200/computercraft/shared/command/UserLevel.java
index 3d6885f2e..2492bd119 100644
--- a/src/main/java/dan200/computercraft/shared/command/UserLevel.java
+++ b/src/main/java/dan200/computercraft/shared/command/UserLevel.java
@@ -61,12 +61,12 @@ public enum UserLevel implements Predicate
         MinecraftServer server = source.getServer();
         Entity sender = source.getEntity();
 
-        if( server.isSinglePlayer() && sender instanceof PlayerEntity &&
+        if( server.isSingleplayer() && sender instanceof PlayerEntity &&
             ((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
         {
             if( this == OWNER || this == OWNER_OP ) return true;
         }
 
-        return source.hasPermissionLevel( toLevel() );
+        return source.hasPermission( toLevel() );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java
index 7bdef6342..2262871e3 100644
--- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java
+++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java
@@ -175,20 +175,20 @@ public final class ComputersArgumentType implements ArgumentType implements ArgumentType>
     public static class Serializer implements IArgumentSerializer>
     {
         @Override
-        public void write( @Nonnull RepeatArgumentType arg, @Nonnull PacketBuffer buf )
+        public void serializeToNetwork( @Nonnull RepeatArgumentType arg, @Nonnull PacketBuffer buf )
         {
             buf.writeBoolean( arg.flatten );
             ArgumentTypes.serialize( buf, arg.child );
-            buf.writeTextComponent( getMessage( arg ) );
+            buf.writeComponent( getMessage( arg ) );
         }
 
         @Nonnull
         @Override
         @SuppressWarnings( { "unchecked", "rawtypes" } )
-        public RepeatArgumentType read( @Nonnull PacketBuffer buf )
+        public RepeatArgumentType deserializeFromNetwork( @Nonnull PacketBuffer buf )
         {
             boolean isList = buf.readBoolean();
             ArgumentType child = ArgumentTypes.deserialize( buf );
-            ITextComponent message = buf.readTextComponent();
+            ITextComponent message = buf.readComponent();
             BiConsumer, ?> appender = isList ? ( list, x ) -> list.addAll( (Collection) x ) : List::add;
             return new RepeatArgumentType( child, appender, isList, new SimpleCommandExceptionType( message ) );
         }
 
         @Override
-        public void write( @Nonnull RepeatArgumentType arg, @Nonnull JsonObject json )
+        public void serializeToJson( @Nonnull RepeatArgumentType arg, @Nonnull JsonObject json )
         {
             json.addProperty( "flatten", arg.flatten );
             json.addProperty( "child", "<>" ); // TODO: Potentially serialize this using reflection.
diff --git a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java
index 793a75136..96f253f7e 100644
--- a/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java
+++ b/src/main/java/dan200/computercraft/shared/command/builder/HelpingArgumentBuilder.java
@@ -151,7 +151,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder context )
         {
-            context.getSource().sendFeedback( getHelp( context, node, id, command ), false );
+            context.getSource().sendSuccess( getHelp( context, node, id, command ), false );
             return 0;
         }
     }
@@ -159,7 +159,7 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder helpForChild( CommandNode node, String id, String command )
     {
         return context -> {
-            context.getSource().sendFeedback( getHelp( context, node, id + "." + node.getName().replace( '-', '_' ), command + " " + node.getName() ), false );
+            context.getSource().sendSuccess( getHelp( context, node, id + "." + node.getName().replace( '-', '_' ), command + " " + node.getName() ), false );
             return 0;
         };
     }
@@ -168,17 +168,17 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder dispatcher = context.getSource().getServer().getCommandManager().getDispatcher();
+        CommandDispatcher dispatcher = context.getSource().getServer().getCommands().getDispatcher();
         CommandNode temp = new LiteralCommandNode<>( "_", null, x -> true, null, null, false );
         temp.addChild( node );
         String usage = dispatcher.getSmartUsage( temp, context.getSource() ).get( node ).substring( node.getName().length() );
 
         ITextComponent output = new StringTextComponent( "" )
-            .appendSibling( coloured( "/" + command + usage, HEADER ) )
-            .appendText( " " )
-            .appendSibling( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
-            .appendText( "\n" )
-            .appendSibling( translate( "commands." + id + ".desc" ) );
+            .append( coloured( "/" + command + usage, HEADER ) )
+            .append( " " )
+            .append( coloured( translate( "commands." + id + ".synopsis" ), SYNOPSIS ) )
+            .append( "\n" )
+            .append( translate( "commands." + id + ".desc" ) );
 
         for( CommandNode child : node.getChildren() )
         {
@@ -187,16 +187,16 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder> type;
@@ -36,22 +38,22 @@ public abstract class BlockGeneric extends Block
 
     @Override
     @Deprecated
-    public final void onReplaced( @Nonnull BlockState block, @Nonnull World world, @Nonnull BlockPos pos, BlockState replace, boolean bool )
+    public final void onRemove( @Nonnull BlockState block, @Nonnull World world, @Nonnull BlockPos pos, BlockState replace, boolean bool )
     {
         if( block.getBlock() == replace.getBlock() ) return;
 
-        TileEntity tile = world.getTileEntity( pos );
-        super.onReplaced( block, world, pos, replace, bool );
-        world.removeTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
+        super.onRemove( block, world, pos, replace, bool );
+        world.removeBlockEntity( pos );
         if( tile instanceof TileGeneric ) ((TileGeneric) tile).destroy();
     }
 
     @Nonnull
     @Override
     @Deprecated
-    public final ActionResultType onBlockActivated( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull PlayerEntity player, @Nonnull Hand hand, @Nonnull BlockRayTraceResult hit )
+    public final ActionResultType use( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull PlayerEntity player, @Nonnull Hand hand, @Nonnull BlockRayTraceResult hit )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         return tile instanceof TileGeneric ? ((TileGeneric) tile).onActivate( player, hand, hit ) : ActionResultType.PASS;
     }
 
@@ -59,14 +61,14 @@ public abstract class BlockGeneric extends Block
     @Deprecated
     public final void neighborChanged( @Nonnull BlockState state, World world, @Nonnull BlockPos pos, @Nonnull Block neighbourBlock, @Nonnull BlockPos neighbourPos, boolean isMoving )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourChange( neighbourPos );
     }
 
     @Override
     public final void onNeighborChange( BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbour )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileGeneric ) ((TileGeneric) tile).onNeighbourTileEntityChange( neighbour );
     }
 
@@ -74,7 +76,7 @@ public abstract class BlockGeneric extends Block
     @Deprecated
     public void tick( @Nonnull BlockState state, ServerWorld world, @Nonnull BlockPos pos, @Nonnull Random rand )
     {
-        TileEntity te = world.getTileEntity( pos );
+        TileEntity te = world.getBlockEntity( pos );
         if( te instanceof TileGeneric ) ((TileGeneric) te).blockTick();
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java
index 25a1bf4a6..130767be9 100644
--- a/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/common/ColourableRecipe.java
@@ -30,9 +30,9 @@ public final class ColourableRecipe extends SpecialRecipe
     {
         boolean hasColourable = false;
         boolean hasDye = false;
-        for( int i = 0; i < inv.getSizeInventory(); i++ )
+        for( int i = 0; i < inv.getContainerSize(); i++ )
         {
-            ItemStack stack = inv.getStackInSlot( i );
+            ItemStack stack = inv.getItem( i );
             if( stack.isEmpty() ) continue;
 
             if( stack.getItem() instanceof IColouredItem )
@@ -55,15 +55,15 @@ public final class ColourableRecipe extends SpecialRecipe
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inv )
+    public ItemStack assemble( @Nonnull CraftingInventory inv )
     {
         ItemStack colourable = ItemStack.EMPTY;
 
         ColourTracker tracker = new ColourTracker();
 
-        for( int i = 0; i < inv.getSizeInventory(); i++ )
+        for( int i = 0; i < inv.getContainerSize(); i++ )
         {
-            ItemStack stack = inv.getStackInSlot( i );
+            ItemStack stack = inv.getItem( i );
 
             if( stack.isEmpty() ) continue;
 
@@ -83,7 +83,7 @@ public final class ColourableRecipe extends SpecialRecipe
     }
 
     @Override
-    public boolean canFit( int x, int y )
+    public boolean canCraftInDimensions( int x, int y )
     {
         return x >= 2 && y >= 2;
     }
diff --git a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java
index c9826a32a..6a7830b1a 100644
--- a/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java
+++ b/src/main/java/dan200/computercraft/shared/common/ContainerHeldItem.java
@@ -29,7 +29,7 @@ public class ContainerHeldItem extends Container
         super( type, id );
 
         this.hand = hand;
-        stack = player.getHeldItem( hand ).copy();
+        stack = player.getItemInHand( hand ).copy();
     }
 
     public static ContainerHeldItem createPrintout( int id, PlayerInventory inventory, HeldItemContainerData data )
@@ -44,11 +44,11 @@ public class ContainerHeldItem extends Container
     }
 
     @Override
-    public boolean canInteractWith( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
         if( !player.isAlive() ) return false;
 
-        ItemStack stack = player.getHeldItem( hand );
+        ItemStack stack = player.getItemInHand( hand );
         return stack == this.stack || !stack.isEmpty() && !this.stack.isEmpty() && stack.getItem() == this.stack.getItem();
     }
 
@@ -61,7 +61,7 @@ public class ContainerHeldItem extends Container
         public Factory( ContainerType type, ItemStack stack, Hand hand )
         {
             this.type = type;
-            this.name = stack.getDisplayName();
+            this.name = stack.getHoverName();
             this.hand = hand;
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java
index e787bdf13..ffb0685da 100644
--- a/src/main/java/dan200/computercraft/shared/common/TileGeneric.java
+++ b/src/main/java/dan200/computercraft/shared/common/TileGeneric.java
@@ -32,10 +32,10 @@ public abstract class TileGeneric extends TileEntity
 
     public final void updateBlock()
     {
-        markDirty();
-        BlockPos pos = getPos();
+        setChanged();
+        BlockPos pos = getBlockPos();
         BlockState state = getBlockState();
-        getWorld().notifyBlockUpdate( pos, state, state, 3 );
+        getLevel().sendBlockUpdated( pos, state, state, 3 );
     }
 
     @Nonnull
@@ -63,13 +63,13 @@ public abstract class TileGeneric extends TileEntity
 
     public boolean isUsable( PlayerEntity player, boolean ignoreRange )
     {
-        if( player == null || !player.isAlive() || getWorld().getTileEntity( getPos() ) != this ) return false;
+        if( player == null || !player.isAlive() || getLevel().getBlockEntity( getBlockPos() ) != this ) return false;
         if( ignoreRange ) return true;
 
         double range = getInteractRange( player );
-        BlockPos pos = getPos();
-        return player.getEntityWorld() == getWorld() &&
-            player.getDistanceSq( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range;
+        BlockPos pos = getBlockPos();
+        return player.getCommandSenderWorld() == getLevel() &&
+            player.distanceToSqr( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ) <= range * range;
     }
 
     protected void writeDescription( @Nonnull CompoundNBT nbt )
@@ -86,13 +86,13 @@ public abstract class TileGeneric extends TileEntity
     {
         CompoundNBT nbt = new CompoundNBT();
         writeDescription( nbt );
-        return new SUpdateTileEntityPacket( pos, 0, nbt );
+        return new SUpdateTileEntityPacket( worldPosition, 0, nbt );
     }
 
     @Override
     public final void onDataPacket( NetworkManager net, SUpdateTileEntityPacket packet )
     {
-        if( packet.getTileEntityType() == 0 ) readDescription( packet.getNbtCompound() );
+        if( packet.getType() == 0 ) readDescription( packet.getTag() );
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java
index 2788e5368..16e2e839f 100644
--- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java
+++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java
@@ -48,18 +48,18 @@ public class CommandAPI implements ILuaAPI
 
     private Object[] doCommand( String command )
     {
-        MinecraftServer server = computer.getWorld().getServer();
+        MinecraftServer server = computer.getLevel().getServer();
         if( server == null || !server.isCommandBlockEnabled() )
         {
             return new Object[] { false, createOutput( "Command blocks disabled by server" ) };
         }
 
-        Commands commandManager = server.getCommandManager();
+        Commands commandManager = server.getCommands();
         TileCommandComputer.CommandReceiver receiver = computer.getReceiver();
         try
         {
             receiver.clearOutput();
-            int result = commandManager.handleCommand( computer.getSource(), command );
+            int result = commandManager.performCommand( computer.getSource(), command );
             return new Object[] { result > 0, receiver.copyOutput(), result };
         }
         catch( Throwable t )
@@ -75,8 +75,8 @@ public class CommandAPI implements ILuaAPI
         BlockState state = world.getBlockState( pos );
         Map table = BlockData.fill( new HashMap<>(), state );
 
-        TileEntity tile = world.getTileEntity( pos );
-        if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.write( new CompoundNBT() ) ) );
+        TileEntity tile = world.getBlockEntity( pos );
+        if( tile != null ) table.put( "nbt", NBTUtil.toLua( tile.save( new CompoundNBT() ) ) );
 
         return table;
     }
@@ -139,10 +139,10 @@ public class CommandAPI implements ILuaAPI
     @LuaFunction( mainThread = true )
     public final List list( IArguments args ) throws LuaException
     {
-        MinecraftServer server = computer.getWorld().getServer();
+        MinecraftServer server = computer.getLevel().getServer();
 
         if( server == null ) return Collections.emptyList();
-        CommandNode node = server.getCommandManager().getDispatcher().getRoot();
+        CommandNode node = server.getCommands().getDispatcher().getRoot();
         for( int j = 0; j < args.count(); j++ )
         {
             String name = args.getString( j );
@@ -171,7 +171,7 @@ public class CommandAPI implements ILuaAPI
     public final Object[] getBlockPosition()
     {
         // This is probably safe to do on the Lua thread. Probably.
-        BlockPos pos = computer.getPos();
+        BlockPos pos = computer.getBlockPos();
         return new Object[] { pos.getX(), pos.getY(), pos.getZ() };
     }
 
@@ -198,7 +198,7 @@ public class CommandAPI implements ILuaAPI
     public final List> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException
     {
         // Get the details of the block
-        World world = computer.getWorld();
+        World world = computer.getLevel();
         BlockPos min = new BlockPos(
             Math.min( minX, maxX ),
             Math.min( minY, maxY ),
@@ -209,7 +209,7 @@ public class CommandAPI implements ILuaAPI
             Math.max( minY, maxY ),
             Math.max( minZ, maxZ )
         );
-        if( !World.isValid( min ) || !World.isValid( max ) )
+        if( !World.isInWorldBounds( min ) || !World.isInWorldBounds( max ) )
         {
             throw new LuaException( "Co-ordinates out of range" );
         }
@@ -250,9 +250,9 @@ public class CommandAPI implements ILuaAPI
     public final Map getBlockInfo( int x, int y, int z ) throws LuaException
     {
         // Get the details of the block
-        World world = computer.getWorld();
+        World world = computer.getLevel();
         BlockPos position = new BlockPos( x, y, z );
-        if( World.isValid( position ) )
+        if( World.isInWorldBounds( position ) )
         {
             return getBlockInfo( world, position );
         }
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java
index 37e4a58af..e6daec420 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java
@@ -23,6 +23,8 @@ import net.minecraftforge.fml.RegistryObject;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockComputer extends BlockComputerBase
 {
     public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class );
@@ -31,14 +33,14 @@ public class BlockComputer extends BlockComputerBase
     public BlockComputer( Properties settings, ComputerFamily family, RegistryObject> type )
     {
         super( settings, family, type );
-        setDefaultState( getDefaultState()
-            .with( FACING, Direction.NORTH )
-            .with( STATE, ComputerState.OFF )
+        registerDefaultState( defaultBlockState()
+            .setValue( FACING, Direction.NORTH )
+            .setValue( STATE, ComputerState.OFF )
         );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder builder )
+    protected void createBlockStateDefinition( StateContainer.Builder builder )
     {
         builder.add( FACING, STATE );
     }
@@ -47,7 +49,7 @@ public class BlockComputer extends BlockComputerBase
     @Override
     public BlockState getStateForPlacement( BlockItemUseContext placement )
     {
-        return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() );
+        return defaultBlockState().setValue( FACING, placement.getHorizontalDirection().getOpposite() );
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java
index ef1f29f82..75f3e3a08 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java
@@ -34,6 +34,8 @@ import net.minecraftforge.fml.RegistryObject;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.minecraft.block.Block.Properties;
+
 public abstract class BlockComputerBase extends BlockGeneric implements IBundledRedstoneBlock
 {
     private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" );
@@ -48,26 +50,26 @@ public abstract class BlockComputerBase extends Bloc
 
     @Override
     @Deprecated
-    public void onBlockAdded( @Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState oldState, boolean isMoving )
+    public void onPlace( @Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState oldState, boolean isMoving )
     {
-        super.onBlockAdded( state, world, pos, oldState, isMoving );
+        super.onPlace( state, world, pos, oldState, isMoving );
 
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileComputerBase ) ((TileComputerBase) tile).updateInput();
     }
 
     @Override
     @Deprecated
-    public boolean canProvidePower( @Nonnull BlockState state )
+    public boolean isSignalSource( @Nonnull BlockState state )
     {
         return true;
     }
 
     @Override
     @Deprecated
-    public int getStrongPower( @Nonnull BlockState state, IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
+    public int getDirectSignal( @Nonnull BlockState state, IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
     {
-        TileEntity entity = world.getTileEntity( pos );
+        TileEntity entity = world.getBlockEntity( pos );
         if( !(entity instanceof TileComputerBase) ) return 0;
 
         TileComputerBase computerEntity = (TileComputerBase) entity;
@@ -88,9 +90,9 @@ public abstract class BlockComputerBase extends Bloc
 
     @Override
     @Deprecated
-    public int getWeakPower( @Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
+    public int getSignal( @Nonnull BlockState state, @Nonnull IBlockReader world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
     {
-        return getStrongPower( state, world, pos, incomingSide );
+        return getDirectSignal( state, world, pos, incomingSide );
     }
 
     @Override
@@ -102,7 +104,7 @@ public abstract class BlockComputerBase extends Bloc
     @Override
     public int getBundledRedstoneOutput( World world, BlockPos pos, Direction side )
     {
-        TileEntity entity = world.getTileEntity( pos );
+        TileEntity entity = world.getBlockEntity( pos );
         if( !(entity instanceof TileComputerBase) ) return 0;
 
         TileComputerBase computerEntity = (TileComputerBase) entity;
@@ -117,7 +119,7 @@ public abstract class BlockComputerBase extends Bloc
     @Override
     public ItemStack getPickBlock( BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, PlayerEntity player )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileComputerBase )
         {
             ItemStack result = getItem( (TileComputerBase) tile );
@@ -128,48 +130,48 @@ public abstract class BlockComputerBase extends Bloc
     }
 
     @Override
-    public void harvestBlock( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity tile, @Nonnull ItemStack tool )
+    public void playerDestroy( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity tile, @Nonnull ItemStack tool )
     {
         // Don't drop blocks here - see onBlockHarvested.
-        player.addStat( Stats.BLOCK_MINED.get( this ) );
-        player.addExhaustion( 0.005F );
+        player.awardStat( Stats.BLOCK_MINED.get( this ) );
+        player.causeFoodExhaustion( 0.005F );
     }
 
     @Override
-    public void onBlockHarvested( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player )
+    public void playerWillDestroy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player )
     {
         if( !(world instanceof ServerWorld) ) return;
 
         // We drop the item here instead of doing it in the harvest method, as we should
         // drop computers for creative players too.
 
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileComputerBase )
         {
             TileComputerBase computer = (TileComputerBase) tile;
             LootContext.Builder context = new LootContext.Builder( (ServerWorld) world )
-                .withRandom( world.rand )
-                .withParameter( LootParameters.POSITION, pos )
-                .withParameter( LootParameters.TOOL, player.getHeldItemMainhand() )
+                .withRandom( world.random )
+                .withParameter( LootParameters.BLOCK_POS, pos )
+                .withParameter( LootParameters.TOOL, player.getMainHandItem() )
                 .withParameter( LootParameters.THIS_ENTITY, player )
-                .withNullableParameter( LootParameters.BLOCK_ENTITY, tile )
+                .withOptionalParameter( LootParameters.BLOCK_ENTITY, tile )
                 .withDynamicDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) );
             for( ItemStack item : state.getDrops( context ) )
             {
-                spawnAsEntity( world, pos, item );
+                popResource( world, pos, item );
             }
 
-            state.spawnAdditionalDrops( world, pos, player.getHeldItemMainhand() );
+            state.spawnAfterBreak( world, pos, player.getMainHandItem() );
         }
     }
 
     @Override
-    public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
+    public void setPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
     {
-        super.onBlockPlacedBy( world, pos, state, placer, stack );
+        super.setPlacedBy( world, pos, state, placer, stack );
 
-        TileEntity tile = world.getTileEntity( pos );
-        if( !world.isRemote && tile instanceof IComputerTile && stack.getItem() instanceof IComputerItem )
+        TileEntity tile = world.getBlockEntity( pos );
+        if( !world.isClientSide && tile instanceof IComputerTile && stack.getItem() instanceof IComputerItem )
         {
             IComputerTile computer = (IComputerTile) tile;
             IComputerItem item = (IComputerItem) stack.getItem();
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java
index 951dd6091..2dfabd43d 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java
@@ -54,21 +54,21 @@ public class TileCommandComputer extends TileComputer
         }
 
         @Override
-        public boolean shouldReceiveFeedback()
+        public boolean acceptsSuccess()
         {
-            return getWorld().getGameRules().getBoolean( GameRules.SEND_COMMAND_FEEDBACK );
+            return getLevel().getGameRules().getBoolean( GameRules.RULE_SENDCOMMANDFEEDBACK );
         }
 
         @Override
-        public boolean shouldReceiveErrors()
+        public boolean acceptsFailure()
         {
             return true;
         }
 
         @Override
-        public boolean allowLogging()
+        public boolean shouldInformAdmins()
         {
-            return getWorld().getGameRules().getBoolean( GameRules.COMMAND_BLOCK_OUTPUT );
+            return getLevel().getGameRules().getBoolean( GameRules.RULE_COMMANDBLOCKOUTPUT );
         }
     }
 
@@ -96,10 +96,10 @@ public class TileCommandComputer extends TileComputer
         }
 
         return new CommandSource( receiver,
-            new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ), Vec2f.ZERO,
-            (ServerWorld) getWorld(), 2,
+            new Vec3d( worldPosition.getX() + 0.5, worldPosition.getY() + 0.5, worldPosition.getZ() + 0.5 ), Vec2f.ZERO,
+            (ServerWorld) getLevel(), 2,
             name, new StringTextComponent( name ),
-            getWorld().getServer(), null
+            getLevel().getServer(), null
         );
     }
 
@@ -122,12 +122,12 @@ public class TileCommandComputer extends TileComputer
         MinecraftServer server = player.getServer();
         if( server == null || !server.isCommandBlockEnabled() )
         {
-            player.sendStatusMessage( new TranslationTextComponent( "advMode.notEnabled" ), true );
+            player.displayClientMessage( new TranslationTextComponent( "advMode.notEnabled" ), true );
             return false;
         }
-        else if( ComputerCraft.commandRequireCreative ? !player.canUseCommandBlock() : !server.getPlayerList().canSendCommands( player.getGameProfile() ) )
+        else if( ComputerCraft.commandRequireCreative ? !player.canUseGameMasterBlocks() : !server.getPlayerList().isOp( player.getGameProfile() ) )
         {
-            player.sendStatusMessage( new TranslationTextComponent( "advMode.notAllowed" ), true );
+            player.displayClientMessage( new TranslationTextComponent( "advMode.notAllowed" ), true );
             return false;
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java
index 03eea284e..23a4a7d6f 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java
@@ -42,11 +42,11 @@ public class TileComputer extends TileComputerBase
     {
         ComputerFamily family = getFamily();
         ServerComputer computer = new ServerComputer(
-            getWorld(), id, label, instanceID, family,
+            getLevel(), id, label, instanceID, family,
             ComputerCraft.computerTermWidth,
             ComputerCraft.computerTermHeight
         );
-        computer.setPosition( getPos() );
+        computer.setPosition( getBlockPos() );
         return computer;
     }
 
@@ -58,16 +58,16 @@ public class TileComputer extends TileComputerBase
     @Override
     public Direction getDirection()
     {
-        return getBlockState().get( BlockComputer.FACING );
+        return getBlockState().getValue( BlockComputer.FACING );
     }
 
     @Override
     protected void updateBlockState( ComputerState newState )
     {
         BlockState existing = getBlockState();
-        if( existing.get( BlockComputer.STATE ) != newState )
+        if( existing.getValue( BlockComputer.STATE ) != newState )
         {
-            getWorld().setBlockState( getPos(), existing.with( BlockComputer.STATE, newState ), 3 );
+            getLevel().setBlock( getBlockPos(), existing.setValue( BlockComputer.STATE, newState ), 3 );
         }
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java
index 6179b5393..44b41d796 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java
@@ -80,7 +80,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
     {
         if( m_instanceID >= 0 )
         {
-            if( !getWorld().isRemote ) ComputerCraft.serverComputerRegistry.remove( m_instanceID );
+            if( !getLevel().isClientSide ) ComputerCraft.serverComputerRegistry.remove( m_instanceID );
             m_instanceID = -1;
         }
     }
@@ -91,7 +91,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
         unload();
         for( Direction dir : DirectionUtil.FACINGS )
         {
-            RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir );
+            RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir );
         }
     }
 
@@ -102,10 +102,10 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
     }
 
     @Override
-    public void remove()
+    public void setRemoved()
     {
         unload();
-        super.remove();
+        super.setRemoved();
     }
 
     protected boolean canNameWithTag( PlayerEntity player )
@@ -117,13 +117,13 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
     @Override
     public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
     {
-        ItemStack currentItem = player.getHeldItem( hand );
-        if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasDisplayName() )
+        ItemStack currentItem = player.getItemInHand( hand );
+        if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasCustomHoverName() )
         {
             // Label to rename computer
-            if( !getWorld().isRemote )
+            if( !getLevel().isClientSide )
             {
-                setLabel( currentItem.getDisplayName().getString() );
+                setLabel( currentItem.getHoverName().getString() );
                 currentItem.shrink( 1 );
             }
             return ActionResultType.SUCCESS;
@@ -131,7 +131,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
         else if( !player.isCrouching() )
         {
             // Regular right click to activate computer
-            if( !getWorld().isRemote && isUsable( player, false ) )
+            if( !getLevel().isClientSide && isUsable( player, false ) )
             {
                 createServerComputer().turnOn();
                 new ComputerContainerData( createServerComputer() ).open( player, this );
@@ -156,7 +156,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
     @Override
     public void tick()
     {
-        if( !getWorld().isRemote )
+        if( !getLevel().isClientSide )
         {
             ServerComputer computer = createServerComputer();
             if( computer == null ) return;
@@ -189,20 +189,20 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
 
     @Nonnull
     @Override
-    public CompoundNBT write( @Nonnull CompoundNBT nbt )
+    public CompoundNBT save( @Nonnull CompoundNBT nbt )
     {
         // Save ID, label and power state
         if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID );
         if( label != null ) nbt.putString( NBT_LABEL, label );
         nbt.putBoolean( NBT_ON, m_on );
 
-        return super.write( nbt );
+        return super.save( nbt );
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT nbt )
+    public void load( @Nonnull CompoundNBT nbt )
     {
-        super.read( nbt );
+        super.load( nbt );
 
         // Load ID, label and power state
         m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
@@ -232,11 +232,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
         Direction offsetSide = dir.getOpposite();
         ComputerSide localDir = remapToLocalSide( dir );
 
-        computer.setRedstoneInput( localDir, getRedstoneInput( world, offset, dir ) );
-        computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
+        computer.setRedstoneInput( localDir, getRedstoneInput( level, offset, dir ) );
+        computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), offset, offsetSide ) );
         if( !isPeripheralBlockedOnSide( localDir ) )
         {
-            IPeripheral peripheral = Peripherals.getPeripheral( getWorld(), offset, offsetSide, invalidate[dir.ordinal()] );
+            IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), offset, offsetSide, invalidate[dir.ordinal()] );
             computer.setPeripheral( localDir, peripheral );
         }
     }
@@ -252,18 +252,18 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
      */
     protected static int getRedstoneInput( World world, BlockPos pos, Direction side )
     {
-        int power = world.getRedstonePower( pos, side );
+        int power = world.getSignal( pos, side );
         if( power >= 15 ) return power;
 
         BlockState neighbour = world.getBlockState( pos );
         return neighbour.getBlock() == Blocks.REDSTONE_WIRE
-            ? Math.max( power, neighbour.get( RedstoneWireBlock.POWER ) )
+            ? Math.max( power, neighbour.getValue( RedstoneWireBlock.POWER ) )
             : power;
     }
 
     public void updateInput()
     {
-        if( getWorld() == null || getWorld().isRemote ) return;
+        if( getLevel() == null || getLevel().isClientSide ) return;
 
         // Update all sides
         ServerComputer computer = getServerComputer();
@@ -272,20 +272,20 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
         BlockPos pos = computer.getPosition();
         for( Direction dir : DirectionUtil.FACINGS )
         {
-            updateSideInput( computer, dir, pos.offset( dir ) );
+            updateSideInput( computer, dir, pos.relative( dir ) );
         }
     }
 
     private void updateInput( BlockPos neighbour )
     {
-        if( getWorld() == null || getWorld().isRemote ) return;
+        if( getLevel() == null || getLevel().isClientSide ) return;
 
         ServerComputer computer = getServerComputer();
         if( computer == null ) return;
 
         for( Direction dir : DirectionUtil.FACINGS )
         {
-            BlockPos offset = pos.offset( dir );
+            BlockPos offset = worldPosition.relative( dir );
             if( offset.equals( neighbour ) )
             {
                 updateSideInput( computer, dir, offset );
@@ -299,12 +299,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
 
     private void updateInput( Direction dir )
     {
-        if( getWorld() == null || getWorld().isRemote ) return;
+        if( getLevel() == null || getLevel().isClientSide ) return;
 
         ServerComputer computer = getServerComputer();
         if( computer == null ) return;
 
-        updateSideInput( computer, dir, pos.offset( dir ) );
+        updateSideInput( computer, dir, worldPosition.relative( dir ) );
     }
 
     public void updateOutput()
@@ -313,7 +313,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
         updateBlock();
         for( Direction dir : DirectionUtil.FACINGS )
         {
-            RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir );
+            RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir );
         }
     }
 
@@ -334,23 +334,23 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
     @Override
     public final void setComputerID( int id )
     {
-        if( getWorld().isRemote || m_computerID == id ) return;
+        if( getLevel().isClientSide || m_computerID == id ) return;
 
         m_computerID = id;
         ServerComputer computer = getServerComputer();
         if( computer != null ) computer.setID( m_computerID );
-        markDirty();
+        setChanged();
     }
 
     @Override
     public final void setLabel( String label )
     {
-        if( getWorld().isRemote || Objects.equals( this.label, label ) ) return;
+        if( getLevel().isClientSide || Objects.equals( this.label, label ) ) return;
 
         this.label = label;
         ServerComputer computer = getServerComputer();
         if( computer != null ) computer.setLabel( label );
-        markDirty();
+        setChanged();
     }
 
     @Override
@@ -361,7 +361,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
 
     public ServerComputer createServerComputer()
     {
-        if( getWorld().isRemote ) return null;
+        if( getLevel().isClientSide ) return null;
 
         boolean changed = false;
         if( m_instanceID < 0 )
@@ -386,7 +386,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
 
     public ServerComputer getServerComputer()
     {
-        return getWorld().isRemote ? null : ComputerCraft.serverComputerRegistry.get( m_instanceID );
+        return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( m_instanceID );
     }
 
     // Networking stuff
@@ -428,7 +428,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
     {
         return hasCustomName()
             ? new StringTextComponent( label )
-            : new TranslationTextComponent( getBlockState().getBlock().getTranslationKey() );
+            : new TranslationTextComponent( getBlockState().getBlock().getDescriptionId() );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java
index 2b6ccc039..46a382c78 100644
--- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java
+++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerState.java
@@ -24,7 +24,7 @@ public enum ComputerState implements IStringSerializable
 
     @Nonnull
     @Override
-    public String getName()
+    public String getSerializedName()
     {
         return name;
     }
diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java
index 4d1db3f23..a54893384 100644
--- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java
@@ -368,7 +368,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
     {
         if( player == null ) return null;
 
-        Container container = player.openContainer;
+        Container container = player.containerMenu;
         if( !(container instanceof IContainerComputer) ) return null;
 
         IContainerComputer computerContainer = (IContainerComputer) container;
diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java
index a84f1a4fc..492aafab7 100644
--- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java
+++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java
@@ -40,7 +40,7 @@ public class ContainerComputerBase extends Container implements IContainerComput
     protected static IComputer getComputer( PlayerInventory player, ComputerContainerData data )
     {
         int id = data.getInstanceId();
-        if( !player.player.world.isRemote ) return ComputerCraft.serverComputerRegistry.get( id );
+        if( !player.player.level.isClientSide ) return ComputerCraft.serverComputerRegistry.get( id );
 
         ClientComputer computer = ComputerCraft.clientComputerRegistry.get( id );
         if( computer == null ) ComputerCraft.clientComputerRegistry.add( id, computer = new ClientComputer( id ) );
@@ -48,7 +48,7 @@ public class ContainerComputerBase extends Container implements IContainerComput
     }
 
     @Override
-    public boolean canInteractWith( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
         return canUse.test( player );
     }
@@ -74,9 +74,9 @@ public class ContainerComputerBase extends Container implements IContainerComput
     }
 
     @Override
-    public void onContainerClosed( @Nonnull PlayerEntity player )
+    public void removed( @Nonnull PlayerEntity player )
     {
-        super.onContainerClosed( player );
+        super.removed( player );
         input.close();
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java
index 3f4f03de3..26a74bd6b 100644
--- a/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java
+++ b/src/main/java/dan200/computercraft/shared/computer/items/IComputerItem.java
@@ -23,7 +23,7 @@ public interface IComputerItem
 
     default String getLabel( @Nonnull ItemStack stack )
     {
-        return stack.hasDisplayName() ? stack.getDisplayName().getString() : null;
+        return stack.hasCustomHoverName() ? stack.getHoverName().getString() : null;
     }
 
     ComputerFamily getFamily();
diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java
index 1dd01ea2b..caab0cbaf 100644
--- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java
@@ -12,6 +12,8 @@ import net.minecraft.util.text.StringTextComponent;
 
 import javax.annotation.Nonnull;
 
+import net.minecraft.item.Item.Properties;
+
 public class ItemComputer extends ItemComputerBase
 {
     public ItemComputer( BlockComputer block, Properties settings )
@@ -23,7 +25,7 @@ public class ItemComputer extends ItemComputerBase
     {
         ItemStack result = new ItemStack( this );
         if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id );
-        if( label != null ) result.setDisplayName( new StringTextComponent( label ) );
+        if( label != null ) result.setHoverName( new StringTextComponent( label ) );
         return result;
     }
 
@@ -31,7 +33,7 @@ public class ItemComputer extends ItemComputerBase
     public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family )
     {
         ItemStack result = ComputerItemFactory.create( getComputerID( stack ), null, family );
-        if( stack.hasDisplayName() ) result.setDisplayName( stack.getDisplayName() );
+        if( stack.hasCustomHoverName() ) result.setHoverName( stack.getHoverName() );
         return result;
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java
index 501ae9826..e2ed053a5 100644
--- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java
+++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java
@@ -24,6 +24,8 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 
+import net.minecraft.item.Item.Properties;
+
 public abstract class ItemComputerBase extends BlockItem implements IComputerItem, IMedia
 {
     private final ComputerFamily family;
@@ -35,7 +37,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
     }
 
     @Override
-    public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag options )
+    public void appendHoverText( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag options )
     {
         if( options.isAdvanced() || getLabel( stack ) == null )
         {
@@ -43,7 +45,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
             if( id >= 0 )
             {
                 list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id )
-                    .applyTextStyle( TextFormatting.GRAY ) );
+                    .withStyle( TextFormatting.GRAY ) );
             }
         }
     }
@@ -67,11 +69,11 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
     {
         if( label != null )
         {
-            stack.setDisplayName( new StringTextComponent( label ) );
+            stack.setHoverName( new StringTextComponent( label ) );
         }
         else
         {
-            stack.clearCustomName();
+            stack.resetHoverName();
         }
         return true;
     }
diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java
index 830efb4f7..7a5d6e4e3 100644
--- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerConvertRecipe.java
@@ -37,9 +37,9 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe
     {
         if( !super.matches( inventory, world ) ) return false;
 
-        for( int i = 0; i < inventory.getSizeInventory(); i++ )
+        for( int i = 0; i < inventory.getContainerSize(); i++ )
         {
-            if( inventory.getStackInSlot( i ).getItem() instanceof IComputerItem ) return true;
+            if( inventory.getItem( i ).getItem() instanceof IComputerItem ) return true;
         }
 
         return false;
@@ -47,12 +47,12 @@ public abstract class ComputerConvertRecipe extends ShapedRecipe
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory )
+    public ItemStack assemble( @Nonnull CraftingInventory inventory )
     {
         // Find our computer item and convert it.
-        for( int i = 0; i < inventory.getSizeInventory(); i++ )
+        for( int i = 0; i < inventory.getContainerSize(); i++ )
         {
-            ItemStack stack = inventory.getStackInSlot( i );
+            ItemStack stack = inventory.getItem( i );
             if( stack.getItem() instanceof IComputerItem ) return convert( (IComputerItem) stack.getItem(), stack );
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java
index b82869dfa..2f7562c4b 100644
--- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerFamilyRecipe.java
@@ -39,42 +39,42 @@ public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe
 
         @Nonnull
         @Override
-        public T read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json )
+        public T fromJson( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json )
         {
-            String group = JSONUtils.getString( json, "group", "" );
+            String group = JSONUtils.getAsString( json, "group", "" );
             ComputerFamily family = RecipeUtil.getFamily( json, "family" );
 
             RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json );
-            ItemStack result = deserializeItem( JSONUtils.getJsonObject( json, "result" ) );
+            ItemStack result = itemFromJson( JSONUtils.getAsJsonObject( json, "result" ) );
 
             return create( identifier, group, template.width, template.height, template.ingredients, result, family );
         }
 
         @Nonnull
         @Override
-        public T read( @Nonnull ResourceLocation identifier, @Nonnull PacketBuffer buf )
+        public T fromNetwork( @Nonnull ResourceLocation identifier, @Nonnull PacketBuffer buf )
         {
             int width = buf.readVarInt();
             int height = buf.readVarInt();
-            String group = buf.readString( Short.MAX_VALUE );
+            String group = buf.readUtf( Short.MAX_VALUE );
 
             NonNullList ingredients = NonNullList.withSize( width * height, Ingredient.EMPTY );
-            for( int i = 0; i < ingredients.size(); i++ ) ingredients.set( i, Ingredient.read( buf ) );
+            for( int i = 0; i < ingredients.size(); i++ ) ingredients.set( i, Ingredient.fromNetwork( buf ) );
 
-            ItemStack result = buf.readItemStack();
-            ComputerFamily family = buf.readEnumValue( ComputerFamily.class );
+            ItemStack result = buf.readItem();
+            ComputerFamily family = buf.readEnum( ComputerFamily.class );
             return create( identifier, group, width, height, ingredients, result, family );
         }
 
         @Override
-        public void write( @Nonnull PacketBuffer buf, @Nonnull T recipe )
+        public void toNetwork( @Nonnull PacketBuffer buf, @Nonnull T recipe )
         {
             buf.writeVarInt( recipe.getWidth() );
             buf.writeVarInt( recipe.getHeight() );
-            buf.writeString( recipe.getGroup() );
-            for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buf );
-            buf.writeItemStack( recipe.getRecipeOutput() );
-            buf.writeEnumValue( recipe.getFamily() );
+            buf.writeUtf( recipe.getGroup() );
+            for( Ingredient ingredient : recipe.getIngredients() ) ingredient.toNetwork( buf );
+            buf.writeItem( recipe.getResultItem() );
+            buf.writeEnum( recipe.getFamily() );
         }
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java
index cd50542ff..35d7d8c7a 100644
--- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java
@@ -15,6 +15,8 @@ import net.minecraft.util.ResourceLocation;
 
 import javax.annotation.Nonnull;
 
+import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe.Serializer;
+
 public class ComputerUpgradeRecipe extends ComputerFamilyRecipe
 {
     public ComputerUpgradeRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family )
diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java
index 27e4cae7f..8597b7eae 100644
--- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java
+++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java
@@ -16,6 +16,8 @@ import javax.annotation.Nonnull;
 import java.util.Collections;
 import java.util.Set;
 
+import net.minecraft.world.storage.loot.conditions.ILootCondition.IBuilder;
+
 /**
  * A loot condition which checks if the tile entity has a name.
  */
@@ -30,13 +32,13 @@ public final class BlockNamedEntityLootCondition implements ILootCondition
     @Override
     public boolean test( LootContext lootContext )
     {
-        TileEntity tile = lootContext.get( LootParameters.BLOCK_ENTITY );
+        TileEntity tile = lootContext.getParamOrNull( LootParameters.BLOCK_ENTITY );
         return tile instanceof INameable && ((INameable) tile).hasCustomName();
     }
 
     @Nonnull
     @Override
-    public Set> getRequiredParameters()
+    public Set> getReferencedContextParams()
     {
         return Collections.singleton( LootParameters.BLOCK_ENTITY );
     }
diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java
index 1f16abec0..e734bf836 100644
--- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java
+++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java
@@ -16,6 +16,8 @@ import javax.annotation.Nonnull;
 import java.util.Collections;
 import java.util.Set;
 
+import net.minecraft.world.storage.loot.conditions.ILootCondition.IBuilder;
+
 /**
  * A loot condition which checks if the tile entity has has a non-0 ID.
  */
@@ -30,13 +32,13 @@ public final class HasComputerIdLootCondition implements ILootCondition
     @Override
     public boolean test( LootContext lootContext )
     {
-        TileEntity tile = lootContext.get( LootParameters.BLOCK_ENTITY );
+        TileEntity tile = lootContext.getParamOrNull( LootParameters.BLOCK_ENTITY );
         return tile instanceof IComputerTile && ((IComputerTile) tile).getComputerID() >= 0;
     }
 
     @Nonnull
     @Override
-    public Set> getRequiredParameters()
+    public Set> getReferencedContextParams()
     {
         return Collections.singleton( LootParameters.BLOCK_ENTITY );
     }
diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java
index e777cfb26..346634b6e 100644
--- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java
+++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java
@@ -16,6 +16,8 @@ import javax.annotation.Nonnull;
 import java.util.Collections;
 import java.util.Set;
 
+import net.minecraft.world.storage.loot.conditions.ILootCondition.IBuilder;
+
 /**
  * A loot condition which checks if the entity is in creative mode.
  */
@@ -30,13 +32,13 @@ public final class PlayerCreativeLootCondition implements ILootCondition
     @Override
     public boolean test( LootContext lootContext )
     {
-        Entity entity = lootContext.get( LootParameters.THIS_ENTITY );
-        return entity instanceof PlayerEntity && ((PlayerEntity) entity).abilities.isCreativeMode;
+        Entity entity = lootContext.getParamOrNull( LootParameters.THIS_ENTITY );
+        return entity instanceof PlayerEntity && ((PlayerEntity) entity).abilities.instabuild;
     }
 
     @Nonnull
     @Override
-    public Set> getRequiredParameters()
+    public Set> getReferencedContextParams()
     {
         return Collections.singleton( LootParameters.THIS_ENTITY );
     }
diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java
index 0bed3e75c..a3a4810d6 100644
--- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java
+++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java
@@ -32,8 +32,8 @@ import net.minecraft.util.ResourceLocation;
 import javax.annotation.Nonnull;
 import java.util.*;
 
-import static net.minecraft.item.crafting.Ingredient.fromStacks;
-import static net.minecraft.util.NonNullList.from;
+import static net.minecraft.item.crafting.Ingredient.of;
+import static net.minecraft.util.NonNullList.of;
 
 class RecipeResolver implements IRecipeManagerPlugin
 {
@@ -158,18 +158,18 @@ class RecipeResolver implements IRecipeManagerPlugin
             if( left != null && right != null ) return Collections.emptyList();
 
             List recipes = new ArrayList<>();
-            Ingredient ingredient = fromStacks( stack );
+            Ingredient ingredient = of( stack );
             for( UpgradeInfo upgrade : turtleUpgrades )
             {
                 // The turtle is facing towards us, so upgrades on the left are actually crafted on the right.
                 if( left == null )
                 {
-                    recipes.add( horizontal( from( Ingredient.EMPTY, ingredient, upgrade.ingredient ), turtleWith( stack, upgrade.turtle, right ) ) );
+                    recipes.add( horizontal( of( Ingredient.EMPTY, ingredient, upgrade.ingredient ), turtleWith( stack, upgrade.turtle, right ) ) );
                 }
 
                 if( right == null )
                 {
-                    recipes.add( horizontal( from( Ingredient.EMPTY, upgrade.ingredient, ingredient ), turtleWith( stack, left, upgrade.turtle ) ) );
+                    recipes.add( horizontal( of( Ingredient.EMPTY, upgrade.ingredient, ingredient ), turtleWith( stack, left, upgrade.turtle ) ) );
                 }
             }
 
@@ -182,10 +182,10 @@ class RecipeResolver implements IRecipeManagerPlugin
             if( back != null ) return Collections.emptyList();
 
             List recipes = new ArrayList<>();
-            Ingredient ingredient = fromStacks( stack );
+            Ingredient ingredient = of( stack );
             for( UpgradeInfo upgrade : pocketUpgrades )
             {
-                recipes.add( vertical( from( Ingredient.EMPTY, ingredient, upgrade.ingredient ), pocketWith( stack, upgrade.pocket ) ) );
+                recipes.add( vertical( of( Ingredient.EMPTY, ingredient, upgrade.ingredient ), pocketWith( stack, upgrade.pocket ) ) );
             }
 
             return recipes;
@@ -240,7 +240,7 @@ class RecipeResolver implements IRecipeManagerPlugin
             if( left != null )
             {
                 recipes.add( horizontal(
-                    from( Ingredient.EMPTY, fromStacks( turtleWith( stack, null, right ) ), fromStacks( left.getCraftingItem() ) ),
+                    of( Ingredient.EMPTY, of( turtleWith( stack, null, right ) ), of( left.getCraftingItem() ) ),
                     stack
                 ) );
             }
@@ -248,7 +248,7 @@ class RecipeResolver implements IRecipeManagerPlugin
             if( right != null )
             {
                 recipes.add( horizontal(
-                    from( Ingredient.EMPTY, fromStacks( right.getCraftingItem() ), fromStacks( turtleWith( stack, left, null ) ) ),
+                    of( Ingredient.EMPTY, of( right.getCraftingItem() ), of( turtleWith( stack, left, null ) ) ),
                     stack
                 ) );
             }
@@ -263,7 +263,7 @@ class RecipeResolver implements IRecipeManagerPlugin
             if( back != null )
             {
                 recipes.add( vertical(
-                    from( Ingredient.EMPTY, fromStacks( back.getCraftingItem() ), fromStacks( pocketWith( stack, null ) ) ),
+                    of( Ingredient.EMPTY, of( back.getCraftingItem() ), of( pocketWith( stack, null ) ) ),
                     stack
                 ) );
             }
@@ -346,7 +346,7 @@ class RecipeResolver implements IRecipeManagerPlugin
         UpgradeInfo( ItemStack stack, ITurtleUpgrade turtle )
         {
             this.stack = stack;
-            this.ingredient = fromStacks( stack );
+            this.ingredient = of( stack );
             this.upgrade = this.turtle = turtle;
             this.pocket = null;
         }
@@ -354,7 +354,7 @@ class RecipeResolver implements IRecipeManagerPlugin
         UpgradeInfo( ItemStack stack, IPocketUpgrade pocket )
         {
             this.stack = stack;
-            this.ingredient = fromStacks( stack );
+            this.ingredient = of( stack );
             this.turtle = null;
             this.upgrade = this.pocket = pocket;
         }
@@ -370,7 +370,7 @@ class RecipeResolver implements IRecipeManagerPlugin
                 if( turtle != null && TurtleUpgrades.suitableForFamily( family, turtle ) )
                 {
                     recipes.add( horizontal(
-                        from( Ingredient.EMPTY, ingredient, fromStacks( TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ) ) ),
+                        of( Ingredient.EMPTY, ingredient, of( TurtleItemFactory.create( -1, null, -1, family, null, null, 0, null ) ) ),
                         TurtleItemFactory.create( -1, null, -1, family, null, turtle, 0, null )
                     ) );
                 }
@@ -378,7 +378,7 @@ class RecipeResolver implements IRecipeManagerPlugin
                 if( pocket != null )
                 {
                     recipes.add( vertical(
-                        from( Ingredient.EMPTY, ingredient, fromStacks( PocketComputerItemFactory.create( -1, null, -1, family, null ) ) ),
+                        of( Ingredient.EMPTY, ingredient, of( PocketComputerItemFactory.create( -1, null, -1, family, null ) ) ),
                         PocketComputerItemFactory.create( -1, null, -1, family, pocket )
                     ) );
                 }
diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java
index 2394b3e1b..b62396e3d 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java
@@ -31,6 +31,8 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 
+import net.minecraft.item.Item.Properties;
+
 public class ItemDisk extends Item implements IMedia, IColouredItem
 {
     private static final String NBT_ID = "DiskId";
@@ -51,9 +53,9 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
     }
 
     @Override
-    public void fillItemGroup( @Nonnull ItemGroup tabs, @Nonnull NonNullList list )
+    public void fillItemCategory( @Nonnull ItemGroup tabs, @Nonnull NonNullList list )
     {
-        if( !isInGroup( tabs ) ) return;
+        if( !allowdedIn( tabs ) ) return;
         for( int colour = 0; colour < 16; colour++ )
         {
             list.add( createFromIDAndColour( -1, null, Colour.VALUES[colour].getHex() ) );
@@ -61,7 +63,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
     }
 
     @Override
-    public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, ITooltipFlag options )
+    public void appendHoverText( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, ITooltipFlag options )
     {
         if( options.isAdvanced() )
         {
@@ -69,7 +71,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
             if( id >= 0 )
             {
                 list.add( new TranslationTextComponent( "gui.computercraft.tooltip.disk_id", id )
-                    .applyTextStyle( TextFormatting.GRAY ) );
+                    .withStyle( TextFormatting.GRAY ) );
             }
         }
     }
@@ -83,7 +85,7 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
     @Override
     public String getLabel( @Nonnull ItemStack stack )
     {
-        return stack.hasDisplayName() ? stack.getDisplayName().getString() : null;
+        return stack.hasCustomHoverName() ? stack.getHoverName().getString() : null;
     }
 
     @Override
@@ -91,11 +93,11 @@ public class ItemDisk extends Item implements IMedia, IColouredItem
     {
         if( label != null )
         {
-            stack.setDisplayName( new StringTextComponent( label ) );
+            stack.setHoverName( new StringTextComponent( label ) );
         }
         else
         {
-            stack.clearCustomName();
+            stack.resetHoverName();
         }
         return true;
     }
diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java
index c54efc754..52be0cfe4 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java
@@ -23,6 +23,8 @@ import net.minecraft.world.World;
 import javax.annotation.Nonnull;
 import java.util.List;
 
+import net.minecraft.item.Item.Properties;
+
 public class ItemPrintout extends Item
 {
     private static final String NBT_TITLE = "Title";
@@ -50,7 +52,7 @@ public class ItemPrintout extends Item
     }
 
     @Override
-    public void addInformation( @Nonnull ItemStack stack, World world, @Nonnull List list, @Nonnull ITooltipFlag options )
+    public void appendHoverText( @Nonnull ItemStack stack, World world, @Nonnull List list, @Nonnull ITooltipFlag options )
     {
         String title = getTitle( stack );
         if( title != null && !title.isEmpty() ) list.add( new StringTextComponent( title ) );
@@ -58,14 +60,14 @@ public class ItemPrintout extends Item
 
     @Nonnull
     @Override
-    public ActionResult onItemRightClick( World world, @Nonnull PlayerEntity player, @Nonnull Hand hand )
+    public ActionResult use( World world, @Nonnull PlayerEntity player, @Nonnull Hand hand )
     {
-        if( !world.isRemote )
+        if( !world.isClientSide )
         {
             new HeldItemContainerData( hand )
-                .open( player, new ContainerHeldItem.Factory( Registry.ModContainers.PRINTOUT.get(), player.getHeldItem( hand ), hand ) );
+                .open( player, new ContainerHeldItem.Factory( Registry.ModContainers.PRINTOUT.get(), player.getItemInHand( hand ), hand ) );
         }
-        return new ActionResult<>( ActionResultType.SUCCESS, player.getHeldItem( hand ) );
+        return new ActionResult<>( ActionResultType.SUCCESS, player.getItemInHand( hand ) );
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java
index 5e7d63187..49cc07dc9 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java
@@ -29,6 +29,8 @@ import javax.annotation.Nullable;
 import java.io.IOException;
 import java.util.List;
 
+import net.minecraft.item.Item.Properties;
+
 public class ItemTreasureDisk extends Item implements IMedia
 {
     private static final String NBT_TITLE = "Title";
@@ -41,12 +43,12 @@ public class ItemTreasureDisk extends Item implements IMedia
     }
 
     @Override
-    public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList stacks )
+    public void fillItemCategory( @Nonnull ItemGroup group, @Nonnull NonNullList stacks )
     {
     }
 
     @Override
-    public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag tooltipOptions )
+    public void appendHoverText( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag tooltipOptions )
     {
         String label = getTitle( stack );
         if( !label.isEmpty() ) list.add( new StringTextComponent( label ) );
diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java
index 32db93c43..2fc56df0b 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java
@@ -41,7 +41,7 @@ public final class RecordMedia implements IMedia
         Item item = stack.getItem();
         if( !(item instanceof MusicDiscItem) ) return null;
 
-        return new TranslationTextComponent( item.getTranslationKey() + ".desc" ).getString();
+        return new TranslationTextComponent( item.getDescriptionId() + ".desc" ).getString();
     }
 
     @Override
@@ -52,7 +52,7 @@ public final class RecordMedia implements IMedia
 
         try
         {
-            return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "field_185076_b" );
+            return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "sound" );
         }
         catch( UnableToAccessFieldException | UnableToFindFieldException e )
         {
diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java
index 6580f3a3c..c3cda6a7a 100644
--- a/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/media/recipes/DiskRecipe.java
@@ -25,8 +25,8 @@ import javax.annotation.Nonnull;
 
 public class DiskRecipe extends SpecialRecipe
 {
-    private final Ingredient paper = Ingredient.fromItems( Items.PAPER );
-    private final Ingredient redstone = Ingredient.fromTag( Tags.Items.DUSTS_REDSTONE );
+    private final Ingredient paper = Ingredient.of( Items.PAPER );
+    private final Ingredient redstone = Ingredient.of( Tags.Items.DUSTS_REDSTONE );
 
     public DiskRecipe( ResourceLocation id )
     {
@@ -39,9 +39,9 @@ public class DiskRecipe extends SpecialRecipe
         boolean paperFound = false;
         boolean redstoneFound = false;
 
-        for( int i = 0; i < inv.getSizeInventory(); i++ )
+        for( int i = 0; i < inv.getContainerSize(); i++ )
         {
-            ItemStack stack = inv.getStackInSlot( i );
+            ItemStack stack = inv.getItem( i );
 
             if( !stack.isEmpty() )
             {
@@ -67,13 +67,13 @@ public class DiskRecipe extends SpecialRecipe
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inv )
+    public ItemStack assemble( @Nonnull CraftingInventory inv )
     {
         ColourTracker tracker = new ColourTracker();
 
-        for( int i = 0; i < inv.getSizeInventory(); i++ )
+        for( int i = 0; i < inv.getContainerSize(); i++ )
         {
-            ItemStack stack = inv.getStackInSlot( i );
+            ItemStack stack = inv.getItem( i );
 
             if( stack.isEmpty() ) continue;
 
@@ -88,14 +88,14 @@ public class DiskRecipe extends SpecialRecipe
     }
 
     @Override
-    public boolean canFit( int x, int y )
+    public boolean canCraftInDimensions( int x, int y )
     {
         return x >= 2 && y >= 2;
     }
 
     @Nonnull
     @Override
-    public ItemStack getRecipeOutput()
+    public ItemStack getResultItem()
     {
         return ItemDisk.createFromIDAndColour( -1, null, Colour.BLUE.getHex() );
     }
diff --git a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java
index 12fec72e2..b71bbaef3 100644
--- a/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/media/recipes/PrintoutRecipe.java
@@ -20,9 +20,9 @@ import javax.annotation.Nonnull;
 
 public final class PrintoutRecipe extends SpecialRecipe
 {
-    private final Ingredient paper = Ingredient.fromItems( net.minecraft.item.Items.PAPER );
-    private final Ingredient leather = Ingredient.fromItems( net.minecraft.item.Items.LEATHER );
-    private final Ingredient string = Ingredient.fromItems( Items.STRING );
+    private final Ingredient paper = Ingredient.of( net.minecraft.item.Items.PAPER );
+    private final Ingredient leather = Ingredient.of( net.minecraft.item.Items.LEATHER );
+    private final Ingredient string = Ingredient.of( Items.STRING );
 
     private PrintoutRecipe( ResourceLocation id )
     {
@@ -30,14 +30,14 @@ public final class PrintoutRecipe extends SpecialRecipe
     }
 
     @Override
-    public boolean canFit( int x, int y )
+    public boolean canCraftInDimensions( int x, int y )
     {
         return x >= 3 && y >= 3;
     }
 
     @Nonnull
     @Override
-    public ItemStack getRecipeOutput()
+    public ItemStack getResultItem()
     {
         return ItemPrintout.createMultipleFromTitleAndText( null, null, null );
     }
@@ -45,12 +45,12 @@ public final class PrintoutRecipe extends SpecialRecipe
     @Override
     public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world )
     {
-        return !getCraftingResult( inventory ).isEmpty();
+        return !assemble( inventory ).isEmpty();
     }
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory )
+    public ItemStack assemble( @Nonnull CraftingInventory inventory )
     {
         // See if we match the recipe, and extract the input disk ID and dye colour
         int numPages = 0;
@@ -63,7 +63,7 @@ public final class PrintoutRecipe extends SpecialRecipe
         {
             for( int x = 0; x < inventory.getWidth(); x++ )
             {
-                ItemStack stack = inventory.getStackInSlot( x + y * inventory.getWidth() );
+                ItemStack stack = inventory.getItem( x + y * inventory.getWidth() );
                 if( !stack.isEmpty() )
                 {
                     if( stack.getItem() instanceof ItemPrintout && ((ItemPrintout) stack.getItem()).getType() != ItemPrintout.Type.BOOK )
diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java
index 79e49949c..d78dd991b 100644
--- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java
+++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java
@@ -60,7 +60,7 @@ public final class NetworkHandler
 
     public static void sendToPlayer( PlayerEntity player, NetworkMessage packet )
     {
-        network.sendTo( packet, ((ServerPlayerEntity) player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT );
+        network.sendTo( packet, ((ServerPlayerEntity) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT );
     }
 
     public static void sendToAllPlayers( NetworkMessage packet )
diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java
index bad9f3e1d..0e48dad40 100644
--- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java
+++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java
@@ -38,13 +38,13 @@ public class ChatTableClientMessage implements NetworkMessage
         buf.writeBoolean( table.getHeaders() != null );
         if( table.getHeaders() != null )
         {
-            for( ITextComponent header : table.getHeaders() ) buf.writeTextComponent( header );
+            for( ITextComponent header : table.getHeaders() ) buf.writeComponent( header );
         }
 
         buf.writeVarInt( table.getRows().size() );
         for( ITextComponent[] row : table.getRows() )
         {
-            for( ITextComponent column : row ) buf.writeTextComponent( column );
+            for( ITextComponent column : row ) buf.writeComponent( column );
         }
 
         buf.writeVarInt( table.getAdditional() );
@@ -59,7 +59,7 @@ public class ChatTableClientMessage implements NetworkMessage
         if( buf.readBoolean() )
         {
             ITextComponent[] headers = new ITextComponent[columns];
-            for( int i = 0; i < columns; i++ ) headers[i] = buf.readTextComponent();
+            for( int i = 0; i < columns; i++ ) headers[i] = buf.readComponent();
             table = new TableBuilder( id, headers );
         }
         else
@@ -71,7 +71,7 @@ public class ChatTableClientMessage implements NetworkMessage
         for( int i = 0; i < rows; i++ )
         {
             ITextComponent[] row = new ITextComponent[columns];
-            for( int j = 0; j < columns; j++ ) row[j] = buf.readTextComponent();
+            for( int j = 0; j < columns; j++ ) row[j] = buf.readComponent();
             table.row( row );
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java
index 60e517f4a..d2ec44e87 100644
--- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java
+++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java
@@ -36,16 +36,16 @@ public class ComputerDataClientMessage extends ComputerClientMessage
     public void toBytes( @Nonnull PacketBuffer buf )
     {
         super.toBytes( buf );
-        buf.writeEnumValue( state );
-        buf.writeCompoundTag( userData );
+        buf.writeEnum( state );
+        buf.writeNbt( userData );
     }
 
     @Override
     public void fromBytes( @Nonnull PacketBuffer buf )
     {
         super.fromBytes( buf );
-        state = buf.readEnumValue( ComputerState.class );
-        userData = buf.readCompoundTag();
+        state = buf.readEnum( ComputerState.class );
+        userData = buf.readNbt();
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java
index 512bad7f7..ca11a15ca 100644
--- a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java
+++ b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java
@@ -44,9 +44,9 @@ public class MonitorClientMessage implements NetworkMessage
     public void handle( NetworkEvent.Context context )
     {
         ClientPlayerEntity player = Minecraft.getInstance().player;
-        if( player == null || player.world == null ) return;
+        if( player == null || player.level == null ) return;
 
-        TileEntity te = player.world.getTileEntity( pos );
+        TileEntity te = player.level.getBlockEntity( pos );
         if( !(te instanceof TileMonitor) ) return;
 
         ((TileMonitor) te).read( state );
diff --git a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java
index 3f10e09f4..89dbf2b0c 100644
--- a/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java
+++ b/src/main/java/dan200/computercraft/shared/network/client/PlayRecordClientMessage.java
@@ -48,7 +48,7 @@ public class PlayRecordClientMessage implements NetworkMessage
         pos = buf.readBlockPos();
         if( buf.readBoolean() )
         {
-            name = buf.readString( Short.MAX_VALUE );
+            name = buf.readUtf( Short.MAX_VALUE );
             soundEvent = buf.readRegistryIdSafe( SoundEvent.class );
         }
         else
@@ -69,7 +69,7 @@ public class PlayRecordClientMessage implements NetworkMessage
         else
         {
             buf.writeBoolean( true );
-            buf.writeString( name );
+            buf.writeUtf( name );
             buf.writeRegistryId( soundEvent );
         }
     }
@@ -79,7 +79,7 @@ public class PlayRecordClientMessage implements NetworkMessage
     public void handle( NetworkEvent.Context context )
     {
         Minecraft mc = Minecraft.getInstance();
-        mc.worldRenderer.playRecord( soundEvent, pos );
-        if( name != null ) mc.ingameGUI.setRecordPlayingMessage( name );
+        mc.levelRenderer.playStreamingMusic( soundEvent, pos );
+        if( name != null ) mc.gui.setNowPlaying( name );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java
index 88f7a2042..ed67433da 100644
--- a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java
+++ b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java
@@ -23,14 +23,14 @@ public class ComputerContainerData implements ContainerData
     public ComputerContainerData( PacketBuffer buf )
     {
         this.id = buf.readInt();
-        this.family = buf.readEnumValue( ComputerFamily.class );
+        this.family = buf.readEnum( ComputerFamily.class );
     }
 
     @Override
     public void toBytes( PacketBuffer buf )
     {
         buf.writeInt( id );
-        buf.writeEnumValue( family );
+        buf.writeEnum( family );
     }
 
     public int getInstanceId()
diff --git a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java
index 1bef2de56..ba1e8ae68 100644
--- a/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java
+++ b/src/main/java/dan200/computercraft/shared/network/container/HeldItemContainerData.java
@@ -28,13 +28,13 @@ public class HeldItemContainerData implements ContainerData
 
     public HeldItemContainerData( PacketBuffer buffer )
     {
-        hand = buffer.readEnumValue( Hand.class );
+        hand = buffer.readEnum( Hand.class );
     }
 
     @Override
     public void toBytes( PacketBuffer buf )
     {
-        buf.writeEnumValue( hand );
+        buf.writeEnum( hand );
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java
index 688262a21..2590e33b7 100644
--- a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java
+++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java
@@ -29,14 +29,14 @@ public class ComputerActionServerMessage extends ComputerServerMessage
     public void toBytes( @Nonnull PacketBuffer buf )
     {
         super.toBytes( buf );
-        buf.writeEnumValue( action );
+        buf.writeEnum( action );
     }
 
     @Override
     public void fromBytes( @Nonnull PacketBuffer buf )
     {
         super.fromBytes( buf );
-        action = buf.readEnumValue( Action.class );
+        action = buf.readEnum( Action.class );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java
index 792fc4a26..a0ca4c06e 100644
--- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java
+++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java
@@ -40,17 +40,17 @@ public class QueueEventServerMessage extends ComputerServerMessage
     public void toBytes( @Nonnull PacketBuffer buf )
     {
         super.toBytes( buf );
-        buf.writeString( event );
-        buf.writeCompoundTag( args == null ? null : NBTUtil.encodeObjects( args ) );
+        buf.writeUtf( event );
+        buf.writeNbt( args == null ? null : NBTUtil.encodeObjects( args ) );
     }
 
     @Override
     public void fromBytes( @Nonnull PacketBuffer buf )
     {
         super.fromBytes( buf );
-        event = buf.readString( Short.MAX_VALUE );
+        event = buf.readUtf( Short.MAX_VALUE );
 
-        CompoundNBT args = buf.readCompoundTag();
+        CompoundNBT args = buf.readNbt();
         this.args = args == null ? null : NBTUtil.decodeObjects( args );
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java
index 0dbf2d709..350a60119 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/commandblock/CommandBlockPeripheral.java
@@ -64,7 +64,7 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider
     @LuaFunction( mainThread = true )
     public final String getCommand()
     {
-        return commandBlock.getCommandBlockLogic().getCommand();
+        return commandBlock.getCommandBlock().getCommand();
     }
 
     /**
@@ -75,8 +75,8 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider
     @LuaFunction( mainThread = true )
     public final void setCommand( String command )
     {
-        commandBlock.getCommandBlockLogic().setCommand( command );
-        commandBlock.getCommandBlockLogic().updateCommand();
+        commandBlock.getCommandBlock().setCommand( command );
+        commandBlock.getCommandBlock().onUpdated();
     }
 
     /**
@@ -89,8 +89,8 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider
     @LuaFunction( mainThread = true )
     public final Object[] runCommand()
     {
-        commandBlock.getCommandBlockLogic().trigger( commandBlock.getWorld() );
-        int result = commandBlock.getCommandBlockLogic().getSuccessCount();
+        commandBlock.getCommandBlock().performCommand( commandBlock.getLevel() );
+        int result = commandBlock.getCommandBlock().getSuccessCount();
         return result > 0 ? new Object[] { true } : new Object[] { false, "Command failed" };
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java
index cf3e5fa24..fc8cb0162 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java
@@ -27,6 +27,8 @@ import net.minecraft.world.World;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockDiskDrive extends BlockGeneric
 {
     static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
@@ -35,14 +37,14 @@ public class BlockDiskDrive extends BlockGeneric
     public BlockDiskDrive( Properties settings )
     {
         super( settings, Registry.ModTiles.DISK_DRIVE );
-        setDefaultState( getStateContainer().getBaseState()
-            .with( FACING, Direction.NORTH )
-            .with( STATE, DiskDriveState.EMPTY ) );
+        registerDefaultState( getStateDefinition().any()
+            .setValue( FACING, Direction.NORTH )
+            .setValue( STATE, DiskDriveState.EMPTY ) );
     }
 
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder properties )
+    protected void createBlockStateDefinition( StateContainer.Builder properties )
     {
         properties.add( FACING, STATE );
     }
@@ -51,34 +53,34 @@ public class BlockDiskDrive extends BlockGeneric
     @Override
     public BlockState getStateForPlacement( BlockItemUseContext placement )
     {
-        return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() );
+        return defaultBlockState().setValue( FACING, placement.getHorizontalDirection().getOpposite() );
     }
 
     @Override
-    public void harvestBlock( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack )
+    public void playerDestroy( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack )
     {
         if( te instanceof INameable && ((INameable) te).hasCustomName() )
         {
-            player.addStat( Stats.BLOCK_MINED.get( this ) );
-            player.addExhaustion( 0.005F );
+            player.awardStat( Stats.BLOCK_MINED.get( this ) );
+            player.causeFoodExhaustion( 0.005F );
 
             ItemStack result = new ItemStack( this );
-            result.setDisplayName( ((INameable) te).getCustomName() );
-            spawnAsEntity( world, pos, result );
+            result.setHoverName( ((INameable) te).getCustomName() );
+            popResource( world, pos, result );
         }
         else
         {
-            super.harvestBlock( world, player, pos, state, te, stack );
+            super.playerDestroy( world, player, pos, state, te, stack );
         }
     }
 
     @Override
-    public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack )
+    public void setPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack )
     {
-        if( stack.hasDisplayName() )
+        if( stack.hasCustomHoverName() )
         {
-            TileEntity tileentity = world.getTileEntity( pos );
-            if( tileentity instanceof TileDiskDrive ) ((TileDiskDrive) tileentity).customName = stack.getDisplayName();
+            TileEntity tileentity = world.getBlockEntity( pos );
+            if( tileentity instanceof TileDiskDrive ) ((TileDiskDrive) tileentity).customName = stack.getHoverName();
         }
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java
index 5fe4542af..c258a348e 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/ContainerDiskDrive.java
@@ -48,38 +48,38 @@ public class ContainerDiskDrive extends Container
     }
 
     @Override
-    public boolean canInteractWith( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
-        return inventory.isUsableByPlayer( player );
+        return inventory.stillValid( player );
     }
 
     @Nonnull
     @Override
-    public ItemStack transferStackInSlot( @Nonnull PlayerEntity player, int slotIndex )
+    public ItemStack quickMoveStack( @Nonnull PlayerEntity player, int slotIndex )
     {
-        Slot slot = inventorySlots.get( slotIndex );
-        if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY;
+        Slot slot = slots.get( slotIndex );
+        if( slot == null || !slot.hasItem() ) return ItemStack.EMPTY;
 
-        ItemStack existing = slot.getStack().copy();
+        ItemStack existing = slot.getItem().copy();
         ItemStack result = existing.copy();
         if( slotIndex == 0 )
         {
             // Insert into player inventory
-            if( !mergeItemStack( existing, 1, 37, true ) ) return ItemStack.EMPTY;
+            if( !moveItemStackTo( existing, 1, 37, true ) ) return ItemStack.EMPTY;
         }
         else
         {
             // Insert into drive inventory
-            if( !mergeItemStack( existing, 0, 1, false ) ) return ItemStack.EMPTY;
+            if( !moveItemStackTo( existing, 0, 1, false ) ) return ItemStack.EMPTY;
         }
 
         if( existing.isEmpty() )
         {
-            slot.putStack( ItemStack.EMPTY );
+            slot.set( ItemStack.EMPTY );
         }
         else
         {
-            slot.onSlotChanged();
+            slot.setChanged();
         }
 
         if( existing.getCount() == result.getCount() ) return ItemStack.EMPTY;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java
index a82201bb8..c48326310 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/DiskDriveState.java
@@ -24,7 +24,7 @@ public enum DiskDriveState implements IStringSerializable
 
     @Override
     @Nonnull
-    public String getName()
+    public String getSerializedName()
     {
         return name;
     }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
index 1797a02a2..f2136367c 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java
@@ -99,54 +99,54 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
         if( player.isCrouching() )
         {
             // Try to put a disk into the drive
-            ItemStack disk = player.getHeldItem( hand );
+            ItemStack disk = player.getItemInHand( hand );
             if( disk.isEmpty() ) return ActionResultType.PASS;
-            if( !getWorld().isRemote && getStackInSlot( 0 ).isEmpty() && MediaProviders.get( disk ) != null )
+            if( !getLevel().isClientSide && getItem( 0 ).isEmpty() && MediaProviders.get( disk ) != null )
             {
                 setDiskStack( disk );
-                player.setHeldItem( hand, ItemStack.EMPTY );
+                player.setItemInHand( hand, ItemStack.EMPTY );
             }
             return ActionResultType.SUCCESS;
         }
         else
         {
             // Open the GUI
-            if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this );
+            if( !getLevel().isClientSide ) NetworkHooks.openGui( (ServerPlayerEntity) player, this );
             return ActionResultType.SUCCESS;
         }
     }
 
     public Direction getDirection()
     {
-        return getBlockState().get( BlockDiskDrive.FACING );
+        return getBlockState().getValue( BlockDiskDrive.FACING );
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT nbt )
+    public void load( @Nonnull CompoundNBT nbt )
     {
-        super.read( nbt );
+        super.load( nbt );
         customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null;
         if( nbt.contains( NBT_ITEM ) )
         {
             CompoundNBT item = nbt.getCompound( NBT_ITEM );
-            m_diskStack = ItemStack.read( item );
+            m_diskStack = ItemStack.of( item );
             m_diskMount = null;
         }
     }
 
     @Nonnull
     @Override
-    public CompoundNBT write( @Nonnull CompoundNBT nbt )
+    public CompoundNBT save( @Nonnull CompoundNBT nbt )
     {
         if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) );
 
         if( !m_diskStack.isEmpty() )
         {
             CompoundNBT item = new CompoundNBT();
-            m_diskStack.write( item );
+            m_diskStack.save( item );
             nbt.put( NBT_ITEM, item );
         }
-        return super.write( nbt );
+        return super.save( nbt );
     }
 
     @Override
@@ -162,7 +162,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
         // Music
         synchronized( this )
         {
-            if( !world.isRemote && m_recordPlaying != m_recordQueued || m_restartRecord )
+            if( !level.isClientSide && m_recordPlaying != m_recordQueued || m_restartRecord )
             {
                 m_restartRecord = false;
                 if( m_recordQueued )
@@ -191,7 +191,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
     // IInventory implementation
 
     @Override
-    public int getSizeInventory()
+    public int getContainerSize()
     {
         return 1;
     }
@@ -204,14 +204,14 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
 
     @Nonnull
     @Override
-    public ItemStack getStackInSlot( int slot )
+    public ItemStack getItem( int slot )
     {
         return m_diskStack;
     }
 
     @Nonnull
     @Override
-    public ItemStack removeStackFromSlot( int slot )
+    public ItemStack removeItemNoUpdate( int slot )
     {
         ItemStack result = m_diskStack;
         m_diskStack = ItemStack.EMPTY;
@@ -222,30 +222,30 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
 
     @Nonnull
     @Override
-    public ItemStack decrStackSize( int slot, int count )
+    public ItemStack removeItem( int slot, int count )
     {
         if( m_diskStack.isEmpty() ) return ItemStack.EMPTY;
 
         if( m_diskStack.getCount() <= count )
         {
             ItemStack disk = m_diskStack;
-            setInventorySlotContents( slot, ItemStack.EMPTY );
+            setItem( slot, ItemStack.EMPTY );
             return disk;
         }
 
         ItemStack part = m_diskStack.split( count );
-        setInventorySlotContents( slot, m_diskStack.isEmpty() ? ItemStack.EMPTY : m_diskStack );
+        setItem( slot, m_diskStack.isEmpty() ? ItemStack.EMPTY : m_diskStack );
         return part;
     }
 
     @Override
-    public void setInventorySlotContents( int slot, @Nonnull ItemStack stack )
+    public void setItem( int slot, @Nonnull ItemStack stack )
     {
-        if( getWorld().isRemote )
+        if( getLevel().isClientSide )
         {
             m_diskStack = stack;
             m_diskMount = null;
-            markDirty();
+            setChanged();
             return;
         }
 
@@ -276,7 +276,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
             // Swap disk over
             m_diskStack = stack;
             m_diskMount = null;
-            markDirty();
+            setChanged();
 
             // Mount new disk
             if( !m_diskStack.isEmpty() )
@@ -288,33 +288,33 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
     }
 
     @Override
-    public void markDirty()
+    public void setChanged()
     {
-        if( !world.isRemote ) updateBlockState();
-        super.markDirty();
+        if( !level.isClientSide ) updateBlockState();
+        super.setChanged();
     }
 
     @Override
-    public boolean isUsableByPlayer( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
         return isUsable( player, false );
     }
 
     @Override
-    public void clear()
+    public void clearContent()
     {
-        setInventorySlotContents( 0, ItemStack.EMPTY );
+        setItem( 0, ItemStack.EMPTY );
     }
 
     @Nonnull
     ItemStack getDiskStack()
     {
-        return getStackInSlot( 0 );
+        return getItem( 0 );
     }
 
     void setDiskStack( @Nonnull ItemStack stack )
     {
-        setInventorySlotContents( 0, stack );
+        setItem( 0, stack );
     }
 
     private IMedia getDiskMedia()
@@ -391,7 +391,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
             {
                 if( m_diskMount == null )
                 {
-                    m_diskMount = contents.createDataMount( m_diskStack, getWorld() );
+                    m_diskMount = contents.createDataMount( m_diskStack, getLevel() );
                 }
                 if( m_diskMount != null )
                 {
@@ -442,7 +442,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
 
     private void updateBlockState()
     {
-        if( removed ) return;
+        if( remove ) return;
 
         if( !m_diskStack.isEmpty() )
         {
@@ -458,14 +458,14 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
     private void updateBlockState( DiskDriveState state )
     {
         BlockState blockState = getBlockState();
-        if( blockState.get( BlockDiskDrive.STATE ) == state ) return;
+        if( blockState.getValue( BlockDiskDrive.STATE ) == state ) return;
 
-        getWorld().setBlockState( getPos(), blockState.with( BlockDiskDrive.STATE, state ) );
+        getLevel().setBlockAndUpdate( getBlockPos(), blockState.setValue( BlockDiskDrive.STATE, state ) );
     }
 
     private synchronized void ejectContents( boolean destroyed )
     {
-        if( getWorld().isRemote || m_diskStack.isEmpty() ) return;
+        if( getLevel().isClientSide || m_diskStack.isEmpty() ) return;
 
         // Remove the disks from the inventory
         ItemStack disks = m_diskStack;
@@ -477,19 +477,19 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
         if( !destroyed )
         {
             Direction dir = getDirection();
-            xOff = dir.getXOffset();
-            zOff = dir.getZOffset();
+            xOff = dir.getStepX();
+            zOff = dir.getStepZ();
         }
 
-        BlockPos pos = getPos();
+        BlockPos pos = getBlockPos();
         double x = pos.getX() + 0.5 + xOff * 0.5;
         double y = pos.getY() + 0.75;
         double z = pos.getZ() + 0.5 + zOff * 0.5;
-        ItemEntity entityitem = new ItemEntity( getWorld(), x, y, z, disks );
-        entityitem.setMotion( xOff * 0.15, 0, zOff * 0.15 );
+        ItemEntity entityitem = new ItemEntity( getLevel(), x, y, z, disks );
+        entityitem.setDeltaMovement( xOff * 0.15, 0, zOff * 0.15 );
 
-        getWorld().addEntity( entityitem );
-        if( !destroyed ) getWorld().playBroadcastSound( 1000, getPos(), 0 );
+        getLevel().addFreshEntity( entityitem );
+        if( !destroyed ) getLevel().globalLevelEvent( 1000, getBlockPos(), 0 );
     }
 
     // Private methods
@@ -500,17 +500,17 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
         SoundEvent record = contents != null ? contents.getAudio( m_diskStack ) : null;
         if( record != null )
         {
-            RecordUtil.playRecord( record, contents.getAudioTitle( m_diskStack ), getWorld(), getPos() );
+            RecordUtil.playRecord( record, contents.getAudioTitle( m_diskStack ), getLevel(), getBlockPos() );
         }
         else
         {
-            RecordUtil.playRecord( null, null, getWorld(), getPos() );
+            RecordUtil.playRecord( null, null, getLevel(), getBlockPos() );
         }
     }
 
     private void stopRecord()
     {
-        RecordUtil.playRecord( null, null, getWorld(), getPos() );
+        RecordUtil.playRecord( null, null, getLevel(), getBlockPos() );
     }
 
     @Nonnull
@@ -549,7 +549,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
     @Override
     public ITextComponent getName()
     {
-        return customName != null ? customName : new TranslationTextComponent( getBlockState().getBlock().getTranslationKey() );
+        return customName != null ? customName : new TranslationTextComponent( getBlockState().getBlock().getDescriptionId() );
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java
index 6bb25f1b8..7f81033d0 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/GenericPeripheralProvider.java
@@ -35,7 +35,7 @@ public class GenericPeripheralProvider
     @Nullable
     public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer> invalidate )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile == null ) return null;
 
         ArrayList saturated = new ArrayList<>( 0 );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java
index ec07302f9..3947487fd 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/BlockData.java
@@ -5,7 +5,6 @@
  */
 package dan200.computercraft.shared.peripheral.generic.data;
 
-import com.google.common.collect.ImmutableMap;
 import net.minecraft.block.BlockState;
 import net.minecraft.state.IProperty;
 
@@ -21,7 +20,7 @@ public class BlockData
         data.put( "name", DataHelpers.getId( state.getBlock() ) );
 
         Map stateTable = new HashMap<>();
-        for( ImmutableMap.Entry, ? extends Comparable> entry : state.getValues().entrySet() )
+        for( Map.Entry, ? extends Comparable> entry : state.getValues().entrySet() )
         {
             IProperty property = entry.getKey();
             stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java
index 2622d654a..84486335a 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/data/ItemData.java
@@ -52,12 +52,12 @@ public class ItemData
 
         fillBasic( data, stack );
 
-        data.put( "displayName", stack.getDisplayName().getString() );
+        data.put( "displayName", stack.getHoverName().getString() );
         data.put( "maxCount", stack.getMaxStackSize() );
 
-        if( stack.isDamageable() )
+        if( stack.isDamageableItem() )
         {
-            data.put( "damage", stack.getDamage() );
+            data.put( "damage", stack.getDamageValue() );
             data.put( "maxDamage", stack.getMaxDamage() );
         }
 
@@ -106,7 +106,7 @@ public class ItemData
     {
         try
         {
-            return ITextComponent.Serializer.fromJson( x.getString() );
+            return ITextComponent.Serializer.fromJson( x.getAsString() );
         }
         catch( JsonParseException e )
         {
@@ -138,7 +138,7 @@ public class ItemData
              * I'll do that to have the same data than ones displayed in tooltip.
              * @see EnchantmentHelper.getEnchantments(ItemStack stack)
              */
-            addEnchantments( stack.getEnchantmentTagList(), enchants );
+            addEnchantments( stack.getEnchantmentTags(), enchants );
         }
 
         return enchants;
@@ -157,14 +157,14 @@ public class ItemData
 
         enchants.ensureCapacity( enchants.size() + rawEnchants.size() );
 
-        for( Map.Entry entry : EnchantmentHelper.func_226652_a_( rawEnchants ).entrySet() )
+        for( Map.Entry entry : EnchantmentHelper.deserializeEnchantments( rawEnchants ).entrySet() )
         {
             Enchantment enchantment = entry.getKey();
             Integer level = entry.getValue();
             HashMap enchant = new HashMap<>( 3 );
             enchant.put( "name", DataHelpers.getId( enchantment ) );
             enchant.put( "level", level );
-            enchant.put( "displayName", enchantment.getDisplayName( level ).getString() );
+            enchant.put( "displayName", enchantment.getFullname( level ).getString() );
             enchants.add( enchant );
         }
     }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java
index c213e961d..0e57d9abb 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemShapes.java
@@ -14,18 +14,18 @@ import javax.annotation.Nonnull;
 public final class ModemShapes
 {
     private static final VoxelShape[] BOXES = new VoxelShape[] {
-        VoxelShapes.create( 0.125, 0.0, 0.125, 0.875, 0.1875, 0.875 ), // Down
-        VoxelShapes.create( 0.125, 0.8125, 0.125, 0.875, 1.0, 0.875 ), // Up
-        VoxelShapes.create( 0.125, 0.125, 0.0, 0.875, 0.875, 0.1875 ), // North
-        VoxelShapes.create( 0.125, 0.125, 0.8125, 0.875, 0.875, 1.0 ), // South
-        VoxelShapes.create( 0.0, 0.125, 0.125, 0.1875, 0.875, 0.875 ), // West
-        VoxelShapes.create( 0.8125, 0.125, 0.125, 1.0, 0.875, 0.875 ), // East
+        VoxelShapes.box( 0.125, 0.0, 0.125, 0.875, 0.1875, 0.875 ), // Down
+        VoxelShapes.box( 0.125, 0.8125, 0.125, 0.875, 1.0, 0.875 ), // Up
+        VoxelShapes.box( 0.125, 0.125, 0.0, 0.875, 0.875, 0.1875 ), // North
+        VoxelShapes.box( 0.125, 0.125, 0.8125, 0.875, 0.875, 1.0 ), // South
+        VoxelShapes.box( 0.0, 0.125, 0.125, 0.1875, 0.875, 0.875 ), // West
+        VoxelShapes.box( 0.8125, 0.125, 0.125, 1.0, 0.875, 0.875 ), // East
     };
 
     @Nonnull
     public static VoxelShape getBounds( Direction facing )
     {
         int direction = facing.ordinal();
-        return direction < BOXES.length ? BOXES[direction] : VoxelShapes.fullCube();
+        return direction < BOXES.length ? BOXES[direction] : VoxelShapes.block();
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java
index 2660dac95..8c5f6ec03 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java
@@ -40,6 +40,8 @@ import java.util.EnumMap;
 
 import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockCable extends BlockGeneric implements IWaterLoggable
 {
     public static final EnumProperty MODEM = EnumProperty.create( "modem", CableModemVariant.class );
@@ -63,32 +65,32 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable
     {
         super( settings, Registry.ModTiles.CABLE );
 
-        setDefaultState( getStateContainer().getBaseState()
-            .with( MODEM, CableModemVariant.None )
-            .with( CABLE, false )
-            .with( NORTH, false ).with( SOUTH, false )
-            .with( EAST, false ).with( WEST, false )
-            .with( UP, false ).with( DOWN, false )
-            .with( WATERLOGGED, false )
+        registerDefaultState( getStateDefinition().any()
+            .setValue( MODEM, CableModemVariant.None )
+            .setValue( CABLE, false )
+            .setValue( NORTH, false ).setValue( SOUTH, false )
+            .setValue( EAST, false ).setValue( WEST, false )
+            .setValue( UP, false ).setValue( DOWN, false )
+            .setValue( WATERLOGGED, false )
         );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder builder )
+    protected void createBlockStateDefinition( StateContainer.Builder builder )
     {
         builder.add( MODEM, CABLE, NORTH, SOUTH, EAST, WEST, UP, DOWN, WATERLOGGED );
     }
 
     public static boolean canConnectIn( BlockState state, Direction direction )
     {
-        return state.get( BlockCable.CABLE ) && state.get( BlockCable.MODEM ).getFacing() != direction;
+        return state.getValue( BlockCable.CABLE ) && state.getValue( BlockCable.MODEM ).getFacing() != direction;
     }
 
     public static boolean doesConnectVisually( BlockState state, IBlockReader world, BlockPos pos, Direction direction )
     {
-        if( !state.get( CABLE ) ) return false;
-        if( state.get( MODEM ).getFacing() == direction ) return true;
-        return ComputerCraftAPI.getWiredElementAt( world, pos.offset( direction ), direction.getOpposite() ).isPresent();
+        if( !state.getValue( CABLE ) ) return false;
+        if( state.getValue( MODEM ).getFacing() == direction ) return true;
+        return ComputerCraftAPI.getWiredElementAt( world, pos.relative( direction ), direction.getOpposite() ).isPresent();
     }
 
     @Nonnull
@@ -102,40 +104,40 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable
     @Override
     public boolean removedByPlayer( BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid )
     {
-        if( state.get( CABLE ) && state.get( MODEM ).getFacing() != null )
+        if( state.getValue( CABLE ) && state.getValue( MODEM ).getFacing() != null )
         {
-            BlockRayTraceResult hit = world.rayTraceBlocks( new RayTraceContext(
+            BlockRayTraceResult hit = world.clip( new RayTraceContext(
                 WorldUtil.getRayStart( player ), WorldUtil.getRayEnd( player ),
                 RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, player
             ) );
             if( hit.getType() == RayTraceResult.Type.BLOCK )
             {
-                TileEntity tile = world.getTileEntity( pos );
-                if( tile instanceof TileCable && tile.hasWorld() )
+                TileEntity tile = world.getBlockEntity( pos );
+                if( tile instanceof TileCable && tile.hasLevel() )
                 {
                     TileCable cable = (TileCable) tile;
 
                     ItemStack item;
                     BlockState newState;
 
-                    if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
+                    if( WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) ) )
                     {
-                        newState = state.with( MODEM, CableModemVariant.None );
+                        newState = state.setValue( MODEM, CableModemVariant.None );
                         item = new ItemStack( Registry.ModItems.WIRED_MODEM.get() );
                     }
                     else
                     {
-                        newState = state.with( CABLE, false );
+                        newState = state.setValue( CABLE, false );
                         item = new ItemStack( Registry.ModItems.CABLE.get() );
                     }
 
-                    world.setBlockState( pos, correctConnections( world, pos, newState ), 3 );
+                    world.setBlock( pos, correctConnections( world, pos, newState ), 3 );
 
                     cable.modemChanged();
                     cable.connectionsChanged();
-                    if( !world.isRemote && !player.abilities.isCreativeMode )
+                    if( !world.isClientSide && !player.abilities.instabuild )
                     {
-                        Block.spawnAsEntity( world, pos, item );
+                        Block.popResource( world, pos, item );
                     }
 
                     return false;
@@ -150,31 +152,31 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable
     @Override
     public ItemStack getPickBlock( BlockState state, RayTraceResult hit, IBlockReader world, BlockPos pos, PlayerEntity player )
     {
-        Direction modem = state.get( MODEM ).getFacing();
-        boolean cable = state.get( CABLE );
+        Direction modem = state.getValue( MODEM ).getFacing();
+        boolean cable = state.getValue( CABLE );
 
         // If we've only got one, just use that.
         if( !cable ) return new ItemStack( Registry.ModItems.WIRED_MODEM.get() );
         if( modem == null ) return new ItemStack( Registry.ModItems.CABLE.get() );
 
         // We've a modem and cable, so try to work out which one we're interacting with
-        return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getHitVec().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
+        return hit != null && WorldUtil.isVecInside( CableShapes.getModemShape( state ), hit.getLocation().subtract( pos.getX(), pos.getY(), pos.getZ() ) )
             ? new ItemStack( Registry.ModItems.WIRED_MODEM.get() )
             : new ItemStack( Registry.ModItems.CABLE.get() );
 
     }
 
     @Override
-    public void onBlockPlacedBy( World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
+    public void setPlacedBy( World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileCable )
         {
             TileCable cable = (TileCable) tile;
             if( cable.hasCable() ) cable.connectionsChanged();
         }
 
-        super.onBlockPlacedBy( world, pos, state, placer, stack );
+        super.setPlacedBy( world, pos, state, placer, stack );
     }
 
     @Nonnull
@@ -188,66 +190,66 @@ public class BlockCable extends BlockGeneric implements IWaterLoggable
     @Nonnull
     @Override
     @Deprecated
-    public BlockState updatePostPlacement( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
+    public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
     {
         updateWaterloggedPostPlacement( state, world, pos );
         // Should never happen, but handle the case where we've no modem or cable.
-        if( !state.get( CABLE ) && state.get( MODEM ) == CableModemVariant.None )
+        if( !state.getValue( CABLE ) && state.getValue( MODEM ) == CableModemVariant.None )
         {
-            return getFluidState( state ).getBlockState();
+            return getFluidState( state ).createLegacyBlock();
         }
 
-        return state.with( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) );
+        return state.setValue( CONNECTIONS.get( side ), doesConnectVisually( state, world, pos, side ) );
     }
 
     @Override
     @Deprecated
-    public boolean isValidPosition( BlockState state, @Nonnull IWorldReader world, @Nonnull BlockPos pos )
+    public boolean canSurvive( BlockState state, @Nonnull IWorldReader world, @Nonnull BlockPos pos )
     {
-        Direction facing = state.get( MODEM ).getFacing();
+        Direction facing = state.getValue( MODEM ).getFacing();
         if( facing == null ) return true;
 
-        BlockPos offsetPos = pos.offset( facing );
+        BlockPos offsetPos = pos.relative( facing );
         BlockState offsetState = world.getBlockState( offsetPos );
-        return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() );
+        return isFaceSturdy( offsetState, world, offsetPos, facing.getOpposite() );
     }
 
     @Nullable
     @Override
     public BlockState getStateForPlacement( @Nonnull BlockItemUseContext context )
     {
-        BlockState state = getDefaultState()
-            .with( WATERLOGGED, getWaterloggedStateForPlacement( context ) );
+        BlockState state = defaultBlockState()
+            .setValue( WATERLOGGED, getWaterloggedStateForPlacement( context ) );
 
-        if( context.getItem().getItem() instanceof ItemBlockCable.Cable )
+        if( context.getItemInHand().getItem() instanceof ItemBlockCable.Cable )
         {
-            World world = context.getWorld();
-            BlockPos pos = context.getPos();
-            return correctConnections( world, pos, state.with( CABLE, true ) );
+            World world = context.getLevel();
+            BlockPos pos = context.getClickedPos();
+            return correctConnections( world, pos, state.setValue( CABLE, true ) );
         }
         else
         {
-            return state.with( MODEM, CableModemVariant.from( context.getFace().getOpposite() ) );
+            return state.setValue( MODEM, CableModemVariant.from( context.getClickedFace().getOpposite() ) );
         }
     }
 
     public static BlockState correctConnections( World world, BlockPos pos, BlockState state )
     {
-        if( state.get( CABLE ) )
+        if( state.getValue( CABLE ) )
         {
             return state
-                .with( NORTH, doesConnectVisually( state, world, pos, Direction.NORTH ) )
-                .with( SOUTH, doesConnectVisually( state, world, pos, Direction.SOUTH ) )
-                .with( EAST, doesConnectVisually( state, world, pos, Direction.EAST ) )
-                .with( WEST, doesConnectVisually( state, world, pos, Direction.WEST ) )
-                .with( UP, doesConnectVisually( state, world, pos, Direction.UP ) )
-                .with( DOWN, doesConnectVisually( state, world, pos, Direction.DOWN ) );
+                .setValue( NORTH, doesConnectVisually( state, world, pos, Direction.NORTH ) )
+                .setValue( SOUTH, doesConnectVisually( state, world, pos, Direction.SOUTH ) )
+                .setValue( EAST, doesConnectVisually( state, world, pos, Direction.EAST ) )
+                .setValue( WEST, doesConnectVisually( state, world, pos, Direction.WEST ) )
+                .setValue( UP, doesConnectVisually( state, world, pos, Direction.UP ) )
+                .setValue( DOWN, doesConnectVisually( state, world, pos, Direction.DOWN ) );
         }
         else
         {
             return state
-                .with( NORTH, false ).with( SOUTH, false ).with( EAST, false )
-                .with( WEST, false ).with( UP, false ).with( DOWN, false );
+                .setValue( NORTH, false ).setValue( SOUTH, false ).setValue( EAST, false )
+                .setValue( WEST, false ).setValue( UP, false ).setValue( DOWN, false );
         }
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java
index 80cbdc4d3..a56282d4f 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java
@@ -12,6 +12,8 @@ import net.minecraft.block.BlockState;
 import net.minecraft.state.BooleanProperty;
 import net.minecraft.state.StateContainer;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockWiredModemFull extends BlockGeneric
 {
     public static final BooleanProperty MODEM_ON = BooleanProperty.create( "modem" );
@@ -20,14 +22,14 @@ public class BlockWiredModemFull extends BlockGeneric
     public BlockWiredModemFull( Properties settings )
     {
         super( settings, Registry.ModTiles.WIRED_MODEM_FULL );
-        setDefaultState( getStateContainer().getBaseState()
-            .with( MODEM_ON, false )
-            .with( PERIPHERAL_ON, false )
+        registerDefaultState( getStateDefinition().any()
+            .setValue( MODEM_ON, false )
+            .setValue( PERIPHERAL_ON, false )
         );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder builder )
+    protected void createBlockStateDefinition( StateContainer.Builder builder )
     {
         builder.add( MODEM_ON, PERIPHERAL_ON );
     }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java
index 9e5521bb2..2f5482edd 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableModemVariant.java
@@ -53,19 +53,19 @@ public enum CableModemVariant implements IStringSerializable
     @Nonnull
     public static CableModemVariant from( Direction facing )
     {
-        return facing == null ? None : VALUES[1 + facing.getIndex()];
+        return facing == null ? None : VALUES[1 + facing.get3DDataValue()];
     }
 
     @Nonnull
     public static CableModemVariant from( Direction facing, boolean modem, boolean peripheral )
     {
         int state = (modem ? 2 : 0) + (peripheral ? 1 : 0);
-        return facing == null ? None : VALUES[1 + 6 * state + facing.getIndex()];
+        return facing == null ? None : VALUES[1 + 6 * state + facing.get3DDataValue()];
     }
 
     @Nonnull
     @Override
-    public String getName()
+    public String getSerializedName()
     {
         return name;
     }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java
index 01ed76966..e3867522a 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/CableShapes.java
@@ -22,15 +22,15 @@ public final class CableShapes
     private static final double MIN = 0.375;
     private static final double MAX = 1 - MIN;
 
-    private static final VoxelShape SHAPE_CABLE_CORE = VoxelShapes.create( MIN, MIN, MIN, MAX, MAX, MAX );
+    private static final VoxelShape SHAPE_CABLE_CORE = VoxelShapes.box( MIN, MIN, MIN, MAX, MAX, MAX );
     private static final EnumMap SHAPE_CABLE_ARM =
         new EnumMap<>( new ImmutableMap.Builder()
-            .put( Direction.DOWN, VoxelShapes.create( MIN, 0, MIN, MAX, MIN, MAX ) )
-            .put( Direction.UP, VoxelShapes.create( MIN, MAX, MIN, MAX, 1, MAX ) )
-            .put( Direction.NORTH, VoxelShapes.create( MIN, MIN, 0, MAX, MAX, MIN ) )
-            .put( Direction.SOUTH, VoxelShapes.create( MIN, MIN, MAX, MAX, MAX, 1 ) )
-            .put( Direction.WEST, VoxelShapes.create( 0, MIN, MIN, MIN, MAX, MAX ) )
-            .put( Direction.EAST, VoxelShapes.create( MAX, MIN, MIN, 1, MAX, MAX ) )
+            .put( Direction.DOWN, VoxelShapes.box( MIN, 0, MIN, MAX, MIN, MAX ) )
+            .put( Direction.UP, VoxelShapes.box( MIN, MAX, MIN, MAX, 1, MAX ) )
+            .put( Direction.NORTH, VoxelShapes.box( MIN, MIN, 0, MAX, MAX, MIN ) )
+            .put( Direction.SOUTH, VoxelShapes.box( MIN, MIN, MAX, MAX, MAX, 1 ) )
+            .put( Direction.WEST, VoxelShapes.box( 0, MIN, MIN, MIN, MAX, MAX ) )
+            .put( Direction.EAST, VoxelShapes.box( MAX, MIN, MIN, 1, MAX, MAX ) )
             .build()
         );
 
@@ -46,7 +46,7 @@ public final class CableShapes
         int index = 0;
         for( Direction facing : DirectionUtil.FACINGS )
         {
-            if( state.get( CONNECTIONS.get( facing ) ) ) index |= 1 << facing.ordinal();
+            if( state.getValue( CONNECTIONS.get( facing ) ) ) index |= 1 << facing.ordinal();
         }
 
         return index;
@@ -71,20 +71,20 @@ public final class CableShapes
 
     public static VoxelShape getCableShape( BlockState state )
     {
-        if( !state.get( CABLE ) ) return VoxelShapes.empty();
+        if( !state.getValue( CABLE ) ) return VoxelShapes.empty();
         return getCableShape( getCableIndex( state ) );
     }
 
     public static VoxelShape getModemShape( BlockState state )
     {
-        Direction facing = state.get( MODEM ).getFacing();
+        Direction facing = state.getValue( MODEM ).getFacing();
         return facing == null ? VoxelShapes.empty() : ModemShapes.getBounds( facing );
     }
 
     public static VoxelShape getShape( BlockState state )
     {
-        Direction facing = state.get( MODEM ).getFacing();
-        if( !state.get( CABLE ) ) return getModemShape( state );
+        Direction facing = state.getValue( MODEM ).getFacing();
+        if( !state.getValue( CABLE ) ) return getModemShape( state );
 
         int cableIndex = getCableIndex( state );
         int index = cableIndex + ((facing == null ? 0 : facing.ordinal() + 1) << 6);
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java
index cf44fc4eb..ca7ca69a5 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java
@@ -23,6 +23,8 @@ import javax.annotation.Nonnull;
 
 import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*;
 
+import net.minecraft.item.Item.Properties;
+
 public abstract class ItemBlockCable extends BlockItem
 {
     private String translationKey;
@@ -35,13 +37,13 @@ public abstract class ItemBlockCable extends BlockItem
     boolean placeAt( World world, BlockPos pos, BlockState state, PlayerEntity player )
     {
         // TODO: Check entity collision.
-        if( !state.isValidPosition( world, pos ) ) return false;
+        if( !state.canSurvive( world, pos ) ) return false;
 
-        world.setBlockState( pos, state, 3 );
+        world.setBlock( pos, state, 3 );
         SoundType soundType = state.getBlock().getSoundType( state, world, pos, player );
         world.playSound( null, pos, soundType.getPlaceSound(), SoundCategory.BLOCKS, (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F );
 
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( tile instanceof TileCable )
         {
             TileCable cable = (TileCable) tile;
@@ -58,18 +60,18 @@ public abstract class ItemBlockCable extends BlockItem
     }
 
     @Override
-    public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList list )
+    public void fillItemCategory( @Nonnull ItemGroup group, @Nonnull NonNullList list )
     {
-        if( isInGroup( group ) ) list.add( new ItemStack( this ) );
+        if( allowdedIn( group ) ) list.add( new ItemStack( this ) );
     }
 
     @Nonnull
     @Override
-    public String getTranslationKey()
+    public String getDescriptionId()
     {
         if( translationKey == null )
         {
-            translationKey = Util.makeTranslationKey( "block", ForgeRegistries.ITEMS.getKey( this ) );
+            translationKey = Util.makeDescriptionId( "block", ForgeRegistries.ITEMS.getKey( this ) );
         }
         return translationKey;
     }
@@ -83,22 +85,22 @@ public abstract class ItemBlockCable extends BlockItem
 
         @Nonnull
         @Override
-        public ActionResultType tryPlace( BlockItemUseContext context )
+        public ActionResultType place( BlockItemUseContext context )
         {
-            ItemStack stack = context.getItem();
+            ItemStack stack = context.getItemInHand();
             if( stack.isEmpty() ) return ActionResultType.FAIL;
 
-            World world = context.getWorld();
-            BlockPos pos = context.getPos();
+            World world = context.getLevel();
+            BlockPos pos = context.getClickedPos();
             BlockState existingState = world.getBlockState( pos );
 
             // Try to add a modem to a cable
-            if( existingState.getBlock() == Registry.ModBlocks.CABLE.get() && existingState.get( MODEM ) == CableModemVariant.None )
+            if( existingState.getBlock() == Registry.ModBlocks.CABLE.get() && existingState.getValue( MODEM ) == CableModemVariant.None )
             {
-                Direction side = context.getFace().getOpposite();
+                Direction side = context.getClickedFace().getOpposite();
                 BlockState newState = existingState
-                    .with( MODEM, CableModemVariant.from( side ) )
-                    .with( CONNECTIONS.get( side ), existingState.get( CABLE ) );
+                    .setValue( MODEM, CableModemVariant.from( side ) )
+                    .setValue( CONNECTIONS.get( side ), existingState.getValue( CABLE ) );
                 if( placeAt( world, pos, newState, context.getPlayer() ) )
                 {
                     stack.shrink( 1 );
@@ -106,7 +108,7 @@ public abstract class ItemBlockCable extends BlockItem
                 }
             }
 
-            return super.tryPlace( context );
+            return super.place( context );
         }
     }
 
@@ -119,19 +121,19 @@ public abstract class ItemBlockCable extends BlockItem
 
         @Nonnull
         @Override
-        public ActionResultType tryPlace( BlockItemUseContext context )
+        public ActionResultType place( BlockItemUseContext context )
         {
-            ItemStack stack = context.getItem();
+            ItemStack stack = context.getItemInHand();
             if( stack.isEmpty() ) return ActionResultType.FAIL;
 
-            World world = context.getWorld();
-            BlockPos pos = context.getPos();
+            World world = context.getLevel();
+            BlockPos pos = context.getClickedPos();
 
             // Try to add a cable to a modem inside the block we're clicking on.
-            BlockPos insidePos = pos.offset( context.getFace().getOpposite() );
+            BlockPos insidePos = pos.relative( context.getClickedFace().getOpposite() );
             BlockState insideState = world.getBlockState( insidePos );
-            if( insideState.getBlock() == Registry.ModBlocks.CABLE.get() && !insideState.get( BlockCable.CABLE )
-                && placeAtCorrected( world, insidePos, insideState.with( BlockCable.CABLE, true ) ) )
+            if( insideState.getBlock() == Registry.ModBlocks.CABLE.get() && !insideState.getValue( BlockCable.CABLE )
+                && placeAtCorrected( world, insidePos, insideState.setValue( BlockCable.CABLE, true ) ) )
             {
                 stack.shrink( 1 );
                 return ActionResultType.SUCCESS;
@@ -139,14 +141,14 @@ public abstract class ItemBlockCable extends BlockItem
 
             // Try to add a cable to a modem adjacent to this block
             BlockState existingState = world.getBlockState( pos );
-            if( existingState.getBlock() == Registry.ModBlocks.CABLE.get() && !existingState.get( BlockCable.CABLE )
-                && placeAtCorrected( world, pos, existingState.with( BlockCable.CABLE, true ) ) )
+            if( existingState.getBlock() == Registry.ModBlocks.CABLE.get() && !existingState.getValue( BlockCable.CABLE )
+                && placeAtCorrected( world, pos, existingState.setValue( BlockCable.CABLE, true ) ) )
             {
                 stack.shrink( 1 );
                 return ActionResultType.SUCCESS;
             }
 
-            return super.tryPlace( context );
+            return super.place( context );
         }
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java
index 6756f6e3e..7c587f7bb 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java
@@ -53,14 +53,14 @@ public class TileCable extends TileGeneric
         @Override
         public World getWorld()
         {
-            return TileCable.this.getWorld();
+            return TileCable.this.getLevel();
         }
 
         @Nonnull
         @Override
         public Vec3d getPosition()
         {
-            BlockPos pos = getPos();
+            BlockPos pos = getBlockPos();
             return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
         }
 
@@ -105,7 +105,7 @@ public class TileCable extends TileGeneric
         @Override
         public Vec3d getPosition()
         {
-            BlockPos pos = getPos().offset( modemDirection );
+            BlockPos pos = getBlockPos().relative( modemDirection );
             return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
         }
 
@@ -127,7 +127,7 @@ public class TileCable extends TileGeneric
 
     private void onRemove()
     {
-        if( world == null || !world.isRemote )
+        if( level == null || !level.isClientSide )
         {
             m_node.remove();
             m_connectionsFormed = false;
@@ -153,9 +153,9 @@ public class TileCable extends TileGeneric
     }
 
     @Override
-    public void remove()
+    public void setRemoved()
     {
-        super.remove();
+        super.setRemoved();
         onRemove();
     }
 
@@ -175,11 +175,11 @@ public class TileCable extends TileGeneric
     }
 
     @Override
-    public void updateContainingBlockInfo()
+    public void clearCache()
     {
-        super.updateContainingBlockInfo();
+        super.clearCache();
         hasModemDirection = false;
-        if( !world.isRemote ) world.getPendingBlockTicks().scheduleTick( pos, getBlockState().getBlock(), 0 );
+        if( !level.isClientSide ) level.getBlockTicks().scheduleTick( worldPosition, getBlockState().getBlock(), 0 );
     }
 
     private void refreshDirection()
@@ -187,7 +187,7 @@ public class TileCable extends TileGeneric
         if( hasModemDirection ) return;
 
         hasModemDirection = true;
-        modemDirection = getBlockState().get( BlockCable.MODEM ).getFacing();
+        modemDirection = getBlockState().getValue( BlockCable.MODEM ).getFacing();
     }
 
     @Nullable
@@ -208,21 +208,21 @@ public class TileCable extends TileGeneric
     public void onNeighbourChange( @Nonnull BlockPos neighbour )
     {
         Direction dir = getDirection();
-        if( neighbour.equals( getPos().offset( dir ) ) && hasModem() && !getBlockState().isValidPosition( getWorld(), getPos() ) )
+        if( neighbour.equals( getBlockPos().relative( dir ) ) && hasModem() && !getBlockState().canSurvive( getLevel(), getBlockPos() ) )
         {
             if( hasCable() )
             {
                 // Drop the modem and convert to cable
-                Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) );
-                getWorld().setBlockState( getPos(), getBlockState().with( BlockCable.MODEM, CableModemVariant.None ) );
+                Block.popResource( getLevel(), getBlockPos(), new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) );
+                getLevel().setBlockAndUpdate( getBlockPos(), getBlockState().setValue( BlockCable.MODEM, CableModemVariant.None ) );
                 modemChanged();
                 connectionsChanged();
             }
             else
             {
                 // Drop everything and remove block
-                Block.spawnAsEntity( getWorld(), getPos(), new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) );
-                getWorld().removeBlock( getPos(), false );
+                Block.popResource( getLevel(), getBlockPos(), new ItemStack( Registry.ModItems.WIRED_MODEM.get() ) );
+                getLevel().removeBlock( getBlockPos(), false );
                 // This'll call #destroy(), so we don't need to reset the network here.
             }
 
@@ -236,16 +236,16 @@ public class TileCable extends TileGeneric
     public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
     {
         super.onNeighbourTileEntityChange( neighbour );
-        if( !world.isRemote && m_peripheralAccessAllowed )
+        if( !level.isClientSide && m_peripheralAccessAllowed )
         {
             Direction facing = getDirection();
-            if( getPos().offset( facing ).equals( neighbour ) ) refreshPeripheral();
+            if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral();
         }
     }
 
     private void refreshPeripheral()
     {
-        if( world != null && !isRemoved() && m_peripheral.attach( world, getPos(), getDirection() ) )
+        if( level != null && !isRemoved() && m_peripheral.attach( level, getBlockPos(), getDirection() ) )
         {
             updateConnectedPeripherals();
         }
@@ -258,7 +258,7 @@ public class TileCable extends TileGeneric
         if( player.isCrouching() ) return ActionResultType.PASS;
         if( !canAttachPeripheral() ) return ActionResultType.FAIL;
 
-        if( getWorld().isRemote ) return ActionResultType.SUCCESS;
+        if( getLevel().isClientSide ) return ActionResultType.SUCCESS;
 
         String oldName = m_peripheral.getConnectedName();
         togglePeripheralAccess();
@@ -267,12 +267,12 @@ public class TileCable extends TileGeneric
         {
             if( oldName != null )
             {
-                player.sendStatusMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_disconnected",
+                player.displayClientMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_disconnected",
                     CommandCopy.createCopyText( oldName ) ), false );
             }
             if( newName != null )
             {
-                player.sendStatusMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_connected",
+                player.displayClientMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_connected",
                     CommandCopy.createCopyText( newName ) ), false );
             }
         }
@@ -281,39 +281,39 @@ public class TileCable extends TileGeneric
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT nbt )
+    public void load( @Nonnull CompoundNBT nbt )
     {
-        super.read( nbt );
+        super.load( nbt );
         m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED );
         m_peripheral.read( nbt, "" );
     }
 
     @Nonnull
     @Override
-    public CompoundNBT write( CompoundNBT nbt )
+    public CompoundNBT save( CompoundNBT nbt )
     {
         nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed );
         m_peripheral.write( nbt, "" );
-        return super.write( nbt );
+        return super.save( nbt );
     }
 
     private void updateBlockState()
     {
         BlockState state = getBlockState();
-        CableModemVariant oldVariant = state.get( BlockCable.MODEM );
+        CableModemVariant oldVariant = state.getValue( BlockCable.MODEM );
         CableModemVariant newVariant = CableModemVariant
             .from( oldVariant.getFacing(), m_modem.getModemState().isOpen(), m_peripheralAccessAllowed );
 
         if( oldVariant != newVariant )
         {
-            world.setBlockState( getPos(), state.with( BlockCable.MODEM, newVariant ) );
+            level.setBlockAndUpdate( getBlockPos(), state.setValue( BlockCable.MODEM, newVariant ) );
         }
     }
 
     @Override
     public void blockTick()
     {
-        if( getWorld().isRemote ) return;
+        if( getLevel().isClientSide ) return;
 
         Direction oldDirection = modemDirection;
         refreshDirection();
@@ -333,7 +333,7 @@ public class TileCable extends TileGeneric
             connectionsChanged();
             if( m_peripheralAccessAllowed )
             {
-                m_peripheral.attach( world, pos, modemDirection );
+                m_peripheral.attach( level, worldPosition, modemDirection );
                 updateConnectedPeripherals();
             }
         }
@@ -341,14 +341,14 @@ public class TileCable extends TileGeneric
 
     void connectionsChanged()
     {
-        if( getWorld().isRemote ) return;
+        if( getLevel().isClientSide ) return;
 
         BlockState state = getBlockState();
-        World world = getWorld();
-        BlockPos current = getPos();
+        World world = getLevel();
+        BlockPos current = getBlockPos();
         for( Direction facing : DirectionUtil.FACINGS )
         {
-            BlockPos offset = current.offset( facing );
+            BlockPos offset = current.relative( facing );
             if( !world.isAreaLoaded( offset, 0 ) ) continue;
 
             LazyOptional element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() );
@@ -374,7 +374,7 @@ public class TileCable extends TileGeneric
         // Tell anyone who cares that the connection state has changed
         elementCap = CapabilityUtil.invalidate( elementCap );
 
-        if( getWorld().isRemote ) return;
+        if( getLevel().isClientSide ) return;
 
         // If we can no longer attach peripherals, then detach any
         // which may have existed
@@ -383,7 +383,7 @@ public class TileCable extends TileGeneric
             m_peripheralAccessAllowed = false;
             m_peripheral.detach();
             m_node.updatePeripherals( Collections.emptyMap() );
-            markDirty();
+            setChanged();
             updateBlockState();
         }
     }
@@ -392,7 +392,7 @@ public class TileCable extends TileGeneric
     {
         if( !m_peripheralAccessAllowed )
         {
-            m_peripheral.attach( world, getPos(), getDirection() );
+            m_peripheral.attach( level, getBlockPos(), getDirection() );
             if( !m_peripheral.hasPeripheral() ) return;
 
             m_peripheralAccessAllowed = true;
@@ -452,12 +452,12 @@ public class TileCable extends TileGeneric
 
     boolean hasCable()
     {
-        return getBlockState().get( BlockCable.CABLE );
+        return getBlockState().getValue( BlockCable.CABLE );
     }
 
     public boolean hasModem()
     {
-        return getBlockState().get( BlockCable.MODEM ) != CableModemVariant.None;
+        return getBlockState().getValue( BlockCable.MODEM ) != CableModemVariant.None;
     }
 
     private boolean canAttachPeripheral()
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java
index b6e0d7029..98e63377f 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java
@@ -80,14 +80,14 @@ public class TileWiredModemFull extends TileGeneric
         @Override
         public World getWorld()
         {
-            return m_entity.getWorld();
+            return m_entity.getLevel();
         }
 
         @Nonnull
         @Override
         public Vec3d getPosition()
         {
-            BlockPos pos = m_entity.getPos();
+            BlockPos pos = m_entity.getBlockPos();
             return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
         }
     }
@@ -113,14 +113,14 @@ public class TileWiredModemFull extends TileGeneric
         super( type );
         for( int i = 0; i < m_peripherals.length; i++ )
         {
-            Direction facing = Direction.byIndex( i );
+            Direction facing = Direction.from3DDataValue( i );
             m_peripherals[i] = new WiredModemLocalPeripheral( () -> refreshPeripheral( facing ) );
         }
     }
 
     private void doRemove()
     {
-        if( world == null || !world.isRemote )
+        if( level == null || !level.isClientSide )
         {
             m_node.remove();
             m_connectionsFormed = false;
@@ -154,9 +154,9 @@ public class TileWiredModemFull extends TileGeneric
     }
 
     @Override
-    public void remove()
+    public void setRemoved()
     {
-        super.remove();
+        super.setRemoved();
         doRemove();
     }
 
@@ -169,11 +169,11 @@ public class TileWiredModemFull extends TileGeneric
     @Override
     public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
     {
-        if( !world.isRemote && m_peripheralAccessAllowed )
+        if( !level.isClientSide && m_peripheralAccessAllowed )
         {
             for( Direction facing : DirectionUtil.FACINGS )
             {
-                if( getPos().offset( facing ).equals( neighbour ) ) refreshPeripheral( facing );
+                if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral( facing );
             }
         }
     }
@@ -181,7 +181,7 @@ public class TileWiredModemFull extends TileGeneric
     private void refreshPeripheral( @Nonnull Direction facing )
     {
         WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()];
-        if( world != null && !isRemoved() && peripheral.attach( world, getPos(), facing ) )
+        if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), facing ) )
         {
             updateConnectedPeripherals();
         }
@@ -191,7 +191,7 @@ public class TileWiredModemFull extends TileGeneric
     @Override
     public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
     {
-        if( getWorld().isRemote ) return ActionResultType.SUCCESS;
+        if( getLevel().isClientSide ) return ActionResultType.SUCCESS;
 
         // On server, we interacted if a peripheral was found
         Set oldPeriphNames = getConnectedPeripheralNames();
@@ -217,37 +217,37 @@ public class TileWiredModemFull extends TileGeneric
         StringTextComponent base = new StringTextComponent( "" );
         for( int i = 0; i < names.size(); i++ )
         {
-            if( i > 0 ) base.appendText( ", " );
-            base.appendSibling( CommandCopy.createCopyText( names.get( i ) ) );
+            if( i > 0 ) base.append( ", " );
+            base.append( CommandCopy.createCopyText( names.get( i ) ) );
         }
 
-        player.sendStatusMessage( new TranslationTextComponent( kind, base ), false );
+        player.displayClientMessage( new TranslationTextComponent( kind, base ), false );
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT nbt )
+    public void load( @Nonnull CompoundNBT nbt )
     {
-        super.read( nbt );
+        super.load( nbt );
         m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED );
         for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].read( nbt, Integer.toString( i ) );
     }
 
     @Nonnull
     @Override
-    public CompoundNBT write( CompoundNBT nbt )
+    public CompoundNBT save( CompoundNBT nbt )
     {
         nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed );
         for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].write( nbt, Integer.toString( i ) );
-        return super.write( nbt );
+        return super.save( nbt );
     }
 
     private void updateBlockState()
     {
         BlockState state = getBlockState();
         boolean modemOn = m_modemState.isOpen(), peripheralOn = m_peripheralAccessAllowed;
-        if( state.get( MODEM_ON ) == modemOn && state.get( PERIPHERAL_ON ) == peripheralOn ) return;
+        if( state.getValue( MODEM_ON ) == modemOn && state.getValue( PERIPHERAL_ON ) == peripheralOn ) return;
 
-        getWorld().setBlockState( getPos(), state.with( MODEM_ON, modemOn ).with( PERIPHERAL_ON, peripheralOn ) );
+        getLevel().setBlockAndUpdate( getBlockPos(), state.setValue( MODEM_ON, modemOn ).setValue( PERIPHERAL_ON, peripheralOn ) );
     }
 
     @Override
@@ -260,7 +260,7 @@ public class TileWiredModemFull extends TileGeneric
     @Override
     public void blockTick()
     {
-        if( getWorld().isRemote ) return;
+        if( getLevel().isClientSide ) return;
 
         if( m_modemState.pollChanged() ) updateBlockState();
 
@@ -273,7 +273,7 @@ public class TileWiredModemFull extends TileGeneric
             {
                 for( Direction facing : DirectionUtil.FACINGS )
                 {
-                    m_peripherals[facing.ordinal()].attach( world, getPos(), facing );
+                    m_peripherals[facing.ordinal()].attach( level, getBlockPos(), facing );
                 }
                 updateConnectedPeripherals();
             }
@@ -282,13 +282,13 @@ public class TileWiredModemFull extends TileGeneric
 
     private void connectionsChanged()
     {
-        if( getWorld().isRemote ) return;
+        if( getLevel().isClientSide ) return;
 
-        World world = getWorld();
-        BlockPos current = getPos();
+        World world = getLevel();
+        BlockPos current = getBlockPos();
         for( Direction facing : DirectionUtil.FACINGS )
         {
-            BlockPos offset = current.offset( facing );
+            BlockPos offset = current.relative( facing );
             if( !world.isAreaLoaded( offset, 0 ) ) continue;
 
             LazyOptional element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() );
@@ -307,7 +307,7 @@ public class TileWiredModemFull extends TileGeneric
             for( Direction facing : DirectionUtil.FACINGS )
             {
                 WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()];
-                peripheral.attach( world, getPos(), facing );
+                peripheral.attach( level, getBlockPos(), facing );
                 hasAny |= peripheral.hasPeripheral();
             }
 
@@ -401,7 +401,7 @@ public class TileWiredModemFull extends TileGeneric
             @Override
             public Vec3d getPosition()
             {
-                BlockPos pos = getPos().offset( side );
+                BlockPos pos = getBlockPos().relative( side );
                 return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
             }
 
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java
index 190a99930..f93e593b9 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/WiredModemLocalPeripheral.java
@@ -141,7 +141,7 @@ public final class WiredModemLocalPeripheral
     @Nullable
     private IPeripheral getPeripheralFrom( World world, BlockPos pos, Direction direction )
     {
-        BlockPos offset = pos.offset( direction );
+        BlockPos offset = pos.relative( direction );
 
         Block block = world.getBlockState( offset ).getBlock();
         if( block == Registry.ModBlocks.WIRED_MODEM_FULL.get() || block == Registry.ModBlocks.CABLE.get() ) return null;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java
index 8a6fd22d2..7655d15a3 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java
@@ -31,6 +31,8 @@ import javax.annotation.Nullable;
 
 import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable
 {
     public static final DirectionProperty FACING = BlockStateProperties.FACING;
@@ -39,14 +41,14 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable
     public BlockWirelessModem( Properties settings, RegistryObject> type )
     {
         super( settings, type );
-        setDefaultState( getStateContainer().getBaseState()
-            .with( FACING, Direction.NORTH )
-            .with( ON, false )
-            .with( WATERLOGGED, false ) );
+        registerDefaultState( getStateDefinition().any()
+            .setValue( FACING, Direction.NORTH )
+            .setValue( ON, false )
+            .setValue( WATERLOGGED, false ) );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder builder )
+    protected void createBlockStateDefinition( StateContainer.Builder builder )
     {
         builder.add( FACING, ON, WATERLOGGED );
     }
@@ -56,7 +58,7 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable
     @Deprecated
     public VoxelShape getShape( BlockState blockState, @Nonnull IBlockReader blockView, @Nonnull BlockPos blockPos, @Nonnull ISelectionContext context )
     {
-        return ModemShapes.getBounds( blockState.get( FACING ) );
+        return ModemShapes.getBounds( blockState.getValue( FACING ) );
     }
 
     @Nonnull
@@ -70,30 +72,30 @@ public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable
     @Nonnull
     @Override
     @Deprecated
-    public BlockState updatePostPlacement( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
+    public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
     {
         updateWaterloggedPostPlacement( state, world, pos );
-        return side == state.get( FACING ) && !state.isValidPosition( world, pos )
-            ? state.getFluidState().getBlockState()
+        return side == state.getValue( FACING ) && !state.canSurvive( world, pos )
+            ? state.getFluidState().createLegacyBlock()
             : state;
     }
 
     @Override
     @Deprecated
-    public boolean isValidPosition( BlockState state, IWorldReader world, BlockPos pos )
+    public boolean canSurvive( BlockState state, IWorldReader world, BlockPos pos )
     {
-        Direction facing = state.get( FACING );
-        BlockPos offsetPos = pos.offset( facing );
+        Direction facing = state.getValue( FACING );
+        BlockPos offsetPos = pos.relative( facing );
         BlockState offsetState = world.getBlockState( offsetPos );
-        return hasSolidSide( offsetState, world, offsetPos, facing.getOpposite() );
+        return isFaceSturdy( offsetState, world, offsetPos, facing.getOpposite() );
     }
 
     @Nullable
     @Override
     public BlockState getStateForPlacement( BlockItemUseContext placement )
     {
-        return getDefaultState()
-            .with( FACING, placement.getFace().getOpposite() )
-            .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) );
+        return defaultBlockState()
+            .setValue( FACING, placement.getClickedFace().getOpposite() )
+            .setValue( WATERLOGGED, getWaterloggedStateForPlacement( placement ) );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java
index bf187d494..066b0cbf8 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java
@@ -41,14 +41,14 @@ public class TileWirelessModem extends TileGeneric
         @Override
         public World getWorld()
         {
-            return entity.getWorld();
+            return entity.getLevel();
         }
 
         @Nonnull
         @Override
         public Vec3d getPosition()
         {
-            BlockPos pos = entity.getPos().offset( entity.modemDirection );
+            BlockPos pos = entity.getBlockPos().relative( entity.modemDirection );
             return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
         }
 
@@ -99,11 +99,11 @@ public class TileWirelessModem extends TileGeneric
     }
 
     @Override
-    public void updateContainingBlockInfo()
+    public void clearCache()
     {
-        super.updateContainingBlockInfo();
+        super.clearCache();
         hasModemDirection = false;
-        world.getPendingBlockTicks().scheduleTick( getPos(), getBlockState().getBlock(), 0 );
+        level.getBlockTicks().scheduleTick( getBlockPos(), getBlockState().getBlock(), 0 );
     }
 
     @Override
@@ -124,16 +124,16 @@ public class TileWirelessModem extends TileGeneric
         if( hasModemDirection ) return;
 
         hasModemDirection = true;
-        modemDirection = getBlockState().get( BlockWirelessModem.FACING );
+        modemDirection = getBlockState().getValue( BlockWirelessModem.FACING );
     }
 
     private void updateBlockState()
     {
         boolean on = modem.getModemState().isOpen();
         BlockState state = getBlockState();
-        if( state.get( BlockWirelessModem.ON ) != on )
+        if( state.getValue( BlockWirelessModem.ON ) != on )
         {
-            getWorld().setBlockState( getPos(), state.with( BlockWirelessModem.ON, on ) );
+            getLevel().setBlockAndUpdate( getBlockPos(), state.setValue( BlockWirelessModem.ON, on ) );
         }
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java
index 2008a4bec..dc2296e8c 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java
@@ -50,7 +50,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral
                 }
                 if( position.y > 96.0 && maxRange > minRange )
                 {
-                    return minRange + (position.y - 96.0) * ((maxRange - minRange) / ((world.getHeight() - 1) - 96.0));
+                    return minRange + (position.y - 96.0) * ((maxRange - minRange) / ((world.getMaxBuildHeight() - 1) - 96.0));
                 }
                 return minRange;
             }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java
index 0fd216b61..72adfb42e 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java
@@ -70,7 +70,7 @@ public class WirelessNetwork implements IPacketNetwork
         if( receiver.getWorld() == sender.getWorld() )
         {
             double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical
-            double distanceSq = receiver.getPosition().squareDistanceTo( sender.getPosition() );
+            double distanceSq = receiver.getPosition().distanceToSqr( sender.getPosition() );
             if( interdimensional || receiver.isInterdimensional() || distanceSq <= receiveRange * receiveRange )
             {
                 receiver.receiveSameDimension( packet, Math.sqrt( distanceSq ) );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
index caa4146b6..b863f9e89 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
@@ -25,6 +25,8 @@ import net.minecraftforge.fml.RegistryObject;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockMonitor extends BlockGeneric
 {
     public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation",
@@ -38,14 +40,14 @@ public class BlockMonitor extends BlockGeneric
     {
         super( settings, type );
         // TODO: Test underwater - do we need isSolid at all?
-        setDefaultState( getStateContainer().getBaseState()
-            .with( ORIENTATION, Direction.NORTH )
-            .with( FACING, Direction.NORTH )
-            .with( STATE, MonitorEdgeState.NONE ) );
+        registerDefaultState( getStateDefinition().any()
+            .setValue( ORIENTATION, Direction.NORTH )
+            .setValue( FACING, Direction.NORTH )
+            .setValue( STATE, MonitorEdgeState.NONE ) );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder builder )
+    protected void createBlockStateDefinition( StateContainer.Builder builder )
     {
         builder.add( ORIENTATION, FACING, STATE );
     }
@@ -54,7 +56,7 @@ public class BlockMonitor extends BlockGeneric
     @Nullable
     public BlockState getStateForPlacement( BlockItemUseContext context )
     {
-        float pitch = context.getPlayer() == null ? 0 : context.getPlayer().rotationPitch;
+        float pitch = context.getPlayer() == null ? 0 : context.getPlayer().xRot;
         Direction orientation;
         if( pitch > 66.5f )
         {
@@ -71,18 +73,18 @@ public class BlockMonitor extends BlockGeneric
             orientation = Direction.NORTH;
         }
 
-        return getDefaultState()
-            .with( FACING, context.getPlacementHorizontalFacing().getOpposite() )
-            .with( ORIENTATION, orientation );
+        return defaultBlockState()
+            .setValue( FACING, context.getHorizontalDirection().getOpposite() )
+            .setValue( ORIENTATION, orientation );
     }
 
     @Override
-    public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, @Nonnull ItemStack itemStack )
+    public void setPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState blockState, @Nullable LivingEntity livingEntity, @Nonnull ItemStack itemStack )
     {
-        super.onBlockPlacedBy( world, pos, blockState, livingEntity, itemStack );
+        super.setPlacedBy( world, pos, blockState, livingEntity, itemStack );
 
-        TileEntity entity = world.getTileEntity( pos );
-        if( entity instanceof TileMonitor && !world.isRemote )
+        TileEntity entity = world.getBlockEntity( pos );
+        if( entity instanceof TileMonitor && !world.isClientSide )
         {
             TileMonitor monitor = (TileMonitor) entity;
             monitor.contractNeighbours();
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java
index 935e1a12e..5cda81809 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ClientMonitor.java
@@ -64,15 +64,15 @@ public final class ClientMonitor extends ClientTerminal
 
                 deleteBuffers();
 
-                tboBuffer = GlStateManager.genBuffers();
-                GlStateManager.bindBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer );
+                tboBuffer = GlStateManager._glGenBuffers();
+                GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, tboBuffer );
                 GL15.glBufferData( GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW );
-                tboTexture = GlStateManager.genTexture();
+                tboTexture = GlStateManager._genTexture();
                 GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, tboTexture );
                 GL31.glTexBuffer( GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, tboBuffer );
                 GL11.glBindTexture( GL31.GL_TEXTURE_BUFFER, 0 );
 
-                GlStateManager.bindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
+                GlStateManager._glBindBuffer( GL31.GL_TEXTURE_BUFFER, 0 );
 
                 addMonitor();
                 return true;
@@ -82,7 +82,7 @@ public final class ClientMonitor extends ClientTerminal
                 if( buffer != null ) return false;
 
                 deleteBuffers();
-                buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.getVertexFormat() );
+                buffer = new VertexBuffer( FixedWidthFontRenderer.TYPE.format() );
                 addMonitor();
                 return true;
 
@@ -110,7 +110,7 @@ public final class ClientMonitor extends ClientTerminal
 
         if( tboTexture != 0 )
         {
-            GlStateManager.deleteTexture( tboTexture );
+            GlStateManager._deleteTexture( tboTexture );
             tboTexture = 0;
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java
index 30203974c..9fc07e130 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorEdgeState.java
@@ -60,12 +60,12 @@ public enum MonitorEdgeState implements IStringSerializable
     @Override
     public String toString()
     {
-        return getName();
+        return getSerializedName();
     }
 
     @Nonnull
     @Override
-    public String getName()
+    public String getSerializedName()
     {
         return name;
     }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java
index f05a46c55..13f4a71f2 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java
@@ -49,7 +49,7 @@ public final class MonitorWatcher
         Chunk chunk = (Chunk) event.getWorld().getChunk( chunkPos.x, chunkPos.z, ChunkStatus.FULL, false );
         if( chunk == null ) return;
 
-        for( TileEntity te : chunk.getTileEntityMap().values() )
+        for( TileEntity te : chunk.getBlockEntities().values() )
         {
             // Find all origin monitors who are not already on the queue.
             if( !(te instanceof TileMonitor) ) continue;
@@ -61,7 +61,7 @@ public final class MonitorWatcher
             // We use the cached terminal state if available - this is guaranteed to
             TerminalState state = monitor.cached;
             if( state == null ) state = monitor.cached = serverMonitor.write();
-            NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getPos(), state ) );
+            NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getBlockPos(), state ) );
         }
     }
 
@@ -80,12 +80,12 @@ public final class MonitorWatcher
             ServerMonitor monitor = getMonitor( tile );
             if( monitor == null ) continue;
 
-            BlockPos pos = tile.getPos();
-            World world = tile.getWorld();
+            BlockPos pos = tile.getBlockPos();
+            World world = tile.getLevel();
             if( !(world instanceof ServerWorld) ) continue;
 
             Chunk chunk = world.getChunkAt( pos );
-            if( !((ServerWorld) world).getChunkProvider().chunkManager.getTrackingPlayers( chunk.getPos(), false ).findAny().isPresent() )
+            if( !((ServerWorld) world).getChunkSource().chunkMap.getPlayers( chunk.getPos(), false ).findAny().isPresent() )
             {
                 continue;
             }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java
index 49ce409a5..7456c7ba0 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java
@@ -86,13 +86,13 @@ public class TileMonitor extends TileGeneric
         // TODO: Call this before using the block
         if( m_destroyed ) return;
         m_destroyed = true;
-        if( !getWorld().isRemote ) contractNeighbours();
+        if( !getLevel().isClientSide ) contractNeighbours();
     }
 
     @Override
-    public void remove()
+    public void setRemoved()
     {
-        super.remove();
+        super.setRemoved();
         if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy();
     }
 
@@ -107,14 +107,14 @@ public class TileMonitor extends TileGeneric
     @Override
     public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
     {
-        if( !player.isCrouching() && getFront() == hit.getFace() )
+        if( !player.isCrouching() && getFront() == hit.getDirection() )
         {
-            if( !getWorld().isRemote )
+            if( !getLevel().isClientSide )
             {
                 monitorTouched(
-                    (float) (hit.getHitVec().x - hit.getPos().getX()),
-                    (float) (hit.getHitVec().y - hit.getPos().getY()),
-                    (float) (hit.getHitVec().z - hit.getPos().getZ())
+                    (float) (hit.getLocation().x - hit.getBlockPos().getX()),
+                    (float) (hit.getLocation().y - hit.getBlockPos().getY()),
+                    (float) (hit.getLocation().z - hit.getBlockPos().getZ())
                 );
             }
             return ActionResultType.SUCCESS;
@@ -125,19 +125,19 @@ public class TileMonitor extends TileGeneric
 
     @Nonnull
     @Override
-    public CompoundNBT write( CompoundNBT tag )
+    public CompoundNBT save( CompoundNBT tag )
     {
         tag.putInt( NBT_X, m_xIndex );
         tag.putInt( NBT_Y, m_yIndex );
         tag.putInt( NBT_WIDTH, m_width );
         tag.putInt( NBT_HEIGHT, m_height );
-        return super.write( tag );
+        return super.save( tag );
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT tag )
+    public void load( @Nonnull CompoundNBT tag )
     {
-        super.read( tag );
+        super.load( tag );
         m_xIndex = tag.getInt( NBT_X );
         m_yIndex = tag.getInt( NBT_Y );
         m_width = tag.getInt( NBT_WIDTH );
@@ -233,8 +233,8 @@ public class TileMonitor extends TileGeneric
         {
             // Otherwise fetch the origin and attempt to get its monitor
             // Note this may load chunks, but we don't really have a choice here.
-            BlockPos pos = getPos();
-            TileEntity te = world.getTileEntity( pos.offset( getRight(), -m_xIndex ).offset( getDown(), -m_yIndex ) );
+            BlockPos pos = getBlockPos();
+            TileEntity te = level.getBlockEntity( pos.relative( getRight(), -m_xIndex ).relative( getDown(), -m_yIndex ) );
             if( !(te instanceof TileMonitor) ) return null;
 
             return m_serverMonitor = ((TileMonitor) te).createServerMonitor();
@@ -245,8 +245,8 @@ public class TileMonitor extends TileGeneric
     {
         if( m_clientMonitor != null ) return m_clientMonitor;
 
-        BlockPos pos = getPos();
-        TileEntity te = world.getTileEntity( pos.offset( getRight(), -m_xIndex ).offset( getDown(), -m_yIndex ) );
+        BlockPos pos = getBlockPos();
+        TileEntity te = level.getBlockEntity( pos.relative( getRight(), -m_xIndex ).relative( getDown(), -m_yIndex ) );
         if( !(te instanceof TileMonitor) ) return null;
 
         return m_clientMonitor = ((TileMonitor) te).m_clientMonitor;
@@ -305,7 +305,7 @@ public class TileMonitor extends TileGeneric
     {
         if( m_xIndex != 0 || m_yIndex != 0 )
         {
-            ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getPos() );
+            ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getBlockPos() );
             return;
         }
 
@@ -317,8 +317,8 @@ public class TileMonitor extends TileGeneric
 
     private void updateBlockState()
     {
-        getWorld().setBlockState( getPos(), getBlockState()
-            .with( BlockMonitor.STATE, MonitorEdgeState.fromConnections(
+        getLevel().setBlock( getBlockPos(), getBlockState()
+            .setValue( BlockMonitor.STATE, MonitorEdgeState.fromConnections(
                 m_yIndex < m_height - 1, m_yIndex > 0,
                 m_xIndex > 0, m_xIndex < m_width - 1 ) ), 2 );
     }
@@ -329,13 +329,13 @@ public class TileMonitor extends TileGeneric
         // Ensure we're actually a monitor block. This _should_ always be the case, but sometimes there's
         // fun problems with the block being missing on the client.
         BlockState state = getBlockState();
-        return state.has( BlockMonitor.FACING ) ? state.get( BlockMonitor.FACING ) : Direction.NORTH;
+        return state.hasProperty( BlockMonitor.FACING ) ? state.getValue( BlockMonitor.FACING ) : Direction.NORTH;
     }
 
     public Direction getOrientation()
     {
         BlockState state = getBlockState();
-        return state.has( BlockMonitor.ORIENTATION ) ? state.get( BlockMonitor.ORIENTATION ) : Direction.NORTH;
+        return state.hasProperty( BlockMonitor.ORIENTATION ) ? state.getValue( BlockMonitor.ORIENTATION ) : Direction.NORTH;
     }
 
     public Direction getFront()
@@ -346,7 +346,7 @@ public class TileMonitor extends TileGeneric
 
     public Direction getRight()
     {
-        return getDirection().rotateYCCW();
+        return getDirection().getCounterClockWise();
     }
 
     public Direction getDown()
@@ -378,13 +378,13 @@ public class TileMonitor extends TileGeneric
 
     private TileMonitor getSimilarMonitorAt( BlockPos pos )
     {
-        if( pos.equals( getPos() ) ) return this;
+        if( pos.equals( getBlockPos() ) ) return this;
 
         int y = pos.getY();
-        World world = getWorld();
+        World world = getLevel();
         if( world == null || !world.isAreaLoaded( pos, 0 ) ) return null;
 
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         if( !(tile instanceof TileMonitor) ) return null;
 
         TileMonitor monitor = (TileMonitor) tile;
@@ -395,12 +395,12 @@ public class TileMonitor extends TileGeneric
 
     private TileMonitor getNeighbour( int x, int y )
     {
-        BlockPos pos = getPos();
+        BlockPos pos = getBlockPos();
         Direction right = getRight();
         Direction down = getDown();
         int xOffset = -m_xIndex + x;
         int yOffset = -m_yIndex + y;
-        return getSimilarMonitorAt( pos.offset( right, xOffset ).offset( down, yOffset ) );
+        return getSimilarMonitorAt( pos.relative( right, xOffset ).relative( down, yOffset ) );
     }
 
     private TileMonitor getOrigin()
@@ -677,8 +677,8 @@ public class TileMonitor extends TileGeneric
         TileMonitor end = getNeighbour( m_width - 1, m_height - 1 );
         if( start != null && end != null )
         {
-            BlockPos startPos = start.getPos();
-            BlockPos endPos = end.getPos();
+            BlockPos startPos = start.getBlockPos();
+            BlockPos endPos = end.getBlockPos();
             int minX = Math.min( startPos.getX(), endPos.getX() );
             int minY = Math.min( startPos.getY(), endPos.getY() );
             int minZ = Math.min( startPos.getZ(), endPos.getZ() );
@@ -689,13 +689,13 @@ public class TileMonitor extends TileGeneric
         }
         else
         {
-            BlockPos pos = getPos();
+            BlockPos pos = getBlockPos();
             return new AxisAlignedBB( pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1 );
         }
     }
 
     @Override
-    public double getMaxRenderDistanceSquared()
+    public double getViewDistance()
     {
         return ComputerCraft.monitorDistanceSq;
     }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java
index bdc5bed57..9dde86617 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java
@@ -27,6 +27,8 @@ import net.minecraft.world.World;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockPrinter extends BlockGeneric
 {
     private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
@@ -36,14 +38,14 @@ public class BlockPrinter extends BlockGeneric
     public BlockPrinter( Properties settings )
     {
         super( settings, Registry.ModTiles.PRINTER );
-        setDefaultState( getStateContainer().getBaseState()
-            .with( FACING, Direction.NORTH )
-            .with( TOP, false )
-            .with( BOTTOM, false ) );
+        registerDefaultState( getStateDefinition().any()
+            .setValue( FACING, Direction.NORTH )
+            .setValue( TOP, false )
+            .setValue( BOTTOM, false ) );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder properties )
+    protected void createBlockStateDefinition( StateContainer.Builder properties )
     {
         properties.add( FACING, TOP, BOTTOM );
     }
@@ -52,34 +54,34 @@ public class BlockPrinter extends BlockGeneric
     @Override
     public BlockState getStateForPlacement( BlockItemUseContext placement )
     {
-        return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() );
+        return defaultBlockState().setValue( FACING, placement.getHorizontalDirection().getOpposite() );
     }
 
     @Override
-    public void harvestBlock( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack )
+    public void playerDestroy( @Nonnull World world, @Nonnull PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable TileEntity te, @Nonnull ItemStack stack )
     {
         if( te instanceof INameable && ((INameable) te).hasCustomName() )
         {
-            player.addStat( Stats.BLOCK_MINED.get( this ) );
-            player.addExhaustion( 0.005F );
+            player.awardStat( Stats.BLOCK_MINED.get( this ) );
+            player.causeFoodExhaustion( 0.005F );
 
             ItemStack result = new ItemStack( this );
-            result.setDisplayName( ((INameable) te).getCustomName() );
-            spawnAsEntity( world, pos, result );
+            result.setHoverName( ((INameable) te).getCustomName() );
+            popResource( world, pos, result );
         }
         else
         {
-            super.harvestBlock( world, player, pos, state, te, stack );
+            super.playerDestroy( world, player, pos, state, te, stack );
         }
     }
 
     @Override
-    public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack )
+    public void setPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, ItemStack stack )
     {
-        if( stack.hasDisplayName() )
+        if( stack.hasCustomHoverName() )
         {
-            TileEntity tileentity = world.getTileEntity( pos );
-            if( tileentity instanceof TilePrinter ) ((TilePrinter) tileentity).customName = stack.getDisplayName();
+            TileEntity tileentity = world.getBlockEntity( pos );
+            if( tileentity instanceof TilePrinter ) ((TilePrinter) tileentity).customName = stack.getHoverName();
         }
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java
index deb5f09d5..50bda22f4 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/ContainerPrinter.java
@@ -30,7 +30,7 @@ public class ContainerPrinter extends Container
         this.properties = properties;
         this.inventory = inventory;
 
-        trackIntArray( properties );
+        addDataSlots( properties );
 
         // Ink slot
         addSlot( new Slot( inventory, 0, 13, 35 ) );
@@ -73,44 +73,44 @@ public class ContainerPrinter extends Container
     }
 
     @Override
-    public boolean canInteractWith( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
-        return inventory.isUsableByPlayer( player );
+        return inventory.stillValid( player );
     }
 
     @Nonnull
     @Override
-    public ItemStack transferStackInSlot( @Nonnull PlayerEntity player, int index )
+    public ItemStack quickMoveStack( @Nonnull PlayerEntity player, int index )
     {
-        Slot slot = inventorySlots.get( index );
-        if( slot == null || !slot.getHasStack() ) return ItemStack.EMPTY;
-        ItemStack stack = slot.getStack();
+        Slot slot = slots.get( index );
+        if( slot == null || !slot.hasItem() ) return ItemStack.EMPTY;
+        ItemStack stack = slot.getItem();
         ItemStack result = stack.copy();
         if( index < 13 )
         {
             // Transfer from printer to inventory
-            if( !mergeItemStack( stack, 13, 49, true ) ) return ItemStack.EMPTY;
+            if( !moveItemStackTo( stack, 13, 49, true ) ) return ItemStack.EMPTY;
         }
         else
         {
             // Transfer from inventory to printer
             if( TilePrinter.isInk( stack ) )
             {
-                if( !mergeItemStack( stack, 0, 1, false ) ) return ItemStack.EMPTY;
+                if( !moveItemStackTo( stack, 0, 1, false ) ) return ItemStack.EMPTY;
             }
             else //if is paper
             {
-                if( !mergeItemStack( stack, 1, 13, false ) ) return ItemStack.EMPTY;
+                if( !moveItemStackTo( stack, 1, 13, false ) ) return ItemStack.EMPTY;
             }
         }
 
         if( stack.isEmpty() )
         {
-            slot.putStack( ItemStack.EMPTY );
+            slot.set( ItemStack.EMPTY );
         }
         else
         {
-            slot.onSlotChanged();
+            slot.setChanged();
         }
 
         if( stack.getCount() == result.getCount() ) return ItemStack.EMPTY;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
index 8e63d3ae5..17ad232da 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
@@ -86,14 +86,14 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
     {
         if( player.isCrouching() ) return ActionResultType.PASS;
 
-        if( !getWorld().isRemote ) NetworkHooks.openGui( (ServerPlayerEntity) player, this );
+        if( !getLevel().isClientSide ) NetworkHooks.openGui( (ServerPlayerEntity) player, this );
         return ActionResultType.SUCCESS;
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT nbt )
+    public void load( @Nonnull CompoundNBT nbt )
     {
-        super.read( nbt );
+        super.load( nbt );
 
         customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null;
 
@@ -111,7 +111,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
 
     @Nonnull
     @Override
-    public CompoundNBT write( @Nonnull CompoundNBT nbt )
+    public CompoundNBT save( @Nonnull CompoundNBT nbt )
     {
         if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) );
 
@@ -126,7 +126,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
         // Write inventory
         ItemStackHelper.saveAllItems( nbt, m_inventory );
 
-        return super.write( nbt );
+        return super.save( nbt );
     }
 
     boolean isPrinting()
@@ -136,7 +136,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
 
     // IInventory implementation
     @Override
-    public int getSizeInventory()
+    public int getContainerSize()
     {
         return m_inventory.size();
     }
@@ -153,32 +153,32 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
 
     @Nonnull
     @Override
-    public ItemStack getStackInSlot( int slot )
+    public ItemStack getItem( int slot )
     {
         return m_inventory.get( slot );
     }
 
     @Nonnull
     @Override
-    public ItemStack removeStackFromSlot( int slot )
+    public ItemStack removeItemNoUpdate( int slot )
     {
         ItemStack result = m_inventory.get( slot );
         m_inventory.set( slot, ItemStack.EMPTY );
-        markDirty();
+        setChanged();
         updateBlockState();
         return result;
     }
 
     @Nonnull
     @Override
-    public ItemStack decrStackSize( int slot, int count )
+    public ItemStack removeItem( int slot, int count )
     {
         ItemStack stack = m_inventory.get( slot );
         if( stack.isEmpty() ) return ItemStack.EMPTY;
 
         if( stack.getCount() <= count )
         {
-            setInventorySlotContents( slot, ItemStack.EMPTY );
+            setItem( slot, ItemStack.EMPTY );
             return stack;
         }
 
@@ -188,28 +188,28 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
             m_inventory.set( slot, ItemStack.EMPTY );
             updateBlockState();
         }
-        markDirty();
+        setChanged();
         return part;
     }
 
     @Override
-    public void setInventorySlotContents( int slot, @Nonnull ItemStack stack )
+    public void setItem( int slot, @Nonnull ItemStack stack )
     {
         m_inventory.set( slot, stack );
-        markDirty();
+        setChanged();
         updateBlockState();
     }
 
     @Override
-    public void clear()
+    public void clearContent()
     {
         for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY );
-        markDirty();
+        setChanged();
         updateBlockState();
     }
 
     @Override
-    public boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack )
+    public boolean canPlaceItem( int slot, @Nonnull ItemStack stack )
     {
         if( slot == 0 )
         {
@@ -226,7 +226,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
     }
 
     @Override
-    public boolean isUsableByPlayer( @Nonnull PlayerEntity playerEntity )
+    public boolean stillValid( @Nonnull PlayerEntity playerEntity )
     {
         return isUsable( playerEntity, false );
     }
@@ -361,7 +361,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
                 updateBlockState();
             }
 
-            markDirty();
+            setChanged();
             m_printing = true;
             return true;
         }
@@ -384,7 +384,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
         {
             if( m_inventory.get( slot ).isEmpty() )
             {
-                setInventorySlotContents( slot, stack );
+                setItem( slot, stack );
                 m_printing = false;
                 return true;
             }
@@ -400,10 +400,10 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
             if( !stack.isEmpty() )
             {
                 // Remove the stack from the inventory
-                setInventorySlotContents( i, ItemStack.EMPTY );
+                setItem( i, ItemStack.EMPTY );
 
                 // Spawn the item in the world
-                WorldUtil.dropItemStack( stack, getWorld(), new Vec3d( getPos() ).add( 0.5, 0.75, 0.5 ) );
+                WorldUtil.dropItemStack( stack, getLevel(), new Vec3d( getBlockPos() ).add( 0.5, 0.75, 0.5 ) );
             }
         }
     }
@@ -435,12 +435,12 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
 
     private void updateBlockState( boolean top, boolean bottom )
     {
-        if( removed ) return;
+        if( remove ) return;
 
         BlockState state = getBlockState();
-        if( state.get( BlockPrinter.TOP ) == top & state.get( BlockPrinter.BOTTOM ) == bottom ) return;
+        if( state.getValue( BlockPrinter.TOP ) == top & state.getValue( BlockPrinter.BOTTOM ) == bottom ) return;
 
-        getWorld().setBlockState( getPos(), state.with( BlockPrinter.TOP, top ).with( BlockPrinter.BOTTOM, bottom ) );
+        getLevel().setBlockAndUpdate( getBlockPos(), state.setValue( BlockPrinter.TOP, top ).setValue( BlockPrinter.BOTTOM, bottom ) );
     }
 
     @Nonnull
@@ -474,7 +474,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
     @Override
     public ITextComponent getName()
     {
-        return customName != null ? customName : new TranslationTextComponent( getBlockState().getBlock().getTranslationKey() );
+        return customName != null ? customName : new TranslationTextComponent( getBlockState().getBlock().getDescriptionId() );
     }
 
     @Override
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java
index 8e8cfdd08..1aa81c6a6 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java
@@ -17,6 +17,8 @@ import net.minecraft.util.Direction;
 
 import javax.annotation.Nullable;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockSpeaker extends BlockGeneric
 {
     private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
@@ -24,12 +26,12 @@ public class BlockSpeaker extends BlockGeneric
     public BlockSpeaker( Properties settings )
     {
         super( settings, Registry.ModTiles.SPEAKER );
-        setDefaultState( getStateContainer().getBaseState()
-            .with( FACING, Direction.NORTH ) );
+        registerDefaultState( getStateDefinition().any()
+            .setValue( FACING, Direction.NORTH ) );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder properties )
+    protected void createBlockStateDefinition( StateContainer.Builder properties )
     {
         properties.add( FACING );
     }
@@ -38,6 +40,6 @@ public class BlockSpeaker extends BlockGeneric
     @Override
     public BlockState getStateForPlacement( BlockItemUseContext placement )
     {
-        return getDefaultState().with( FACING, placement.getPlacementHorizontalFacing().getOpposite() );
+        return defaultBlockState().setValue( FACING, placement.getHorizontalDirection().getOpposite() );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
index 59316a669..9ebf8c10a 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
@@ -117,7 +117,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
         NoteBlockInstrument instrument = null;
         for( NoteBlockInstrument testInstrument : NoteBlockInstrument.values() )
         {
-            if( testInstrument.getName().equalsIgnoreCase( name ) )
+            if( testInstrument.getSerializedName().equalsIgnoreCase( name ) )
             {
                 instrument = testInstrument;
                 break;
@@ -128,7 +128,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
         if( instrument == null ) throw new LuaException( "Invalid instrument, \"" + name + "\"!" );
 
         // If the resource location for note block notes changes, this method call will need to be updated
-        boolean success = playSound( context, instrument.getSound().getRegistryName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true );
+        boolean success = playSound( context, instrument.getSoundEvent().getRegistryName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true );
         if( success ) m_notesThisTick.incrementAndGet();
         return success;
     }
@@ -151,7 +151,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
             if( server == null ) return null;
 
             float adjVolume = Math.min( volume, 3.0f );
-            server.getPlayerList().sendToAllNearExcept(
+            server.getPlayerList().broadcast(
                 null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.dimension.getType(),
                 new SPlaySoundPacket( name, SoundCategory.RECORDS, pos, adjVolume, pitch )
             );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java
index e0d792284..e06edc73e 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java
@@ -73,13 +73,13 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity
         @Override
         public World getWorld()
         {
-            return speaker.getWorld();
+            return speaker.getLevel();
         }
 
         @Override
         public Vec3d getPosition()
         {
-            BlockPos pos = speaker.getPos();
+            BlockPos pos = speaker.getBlockPos();
             return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
index 2dd3ed61d..575f487d9 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java
@@ -70,10 +70,10 @@ public class PocketAPI implements ILuaAPI
 
         // Attempt to find the upgrade, starting in the main segment, and then looking in the opposite
         // one. We start from the position the item is currently in and loop round to the start.
-        IPocketUpgrade newUpgrade = findUpgrade( inventory.mainInventory, inventory.currentItem, previousUpgrade );
+        IPocketUpgrade newUpgrade = findUpgrade( inventory.items, inventory.selected, previousUpgrade );
         if( newUpgrade == null )
         {
-            newUpgrade = findUpgrade( inventory.offHandInventory, 0, previousUpgrade );
+            newUpgrade = findUpgrade( inventory.offhand, 0, previousUpgrade );
         }
         if( newUpgrade == null ) return new Object[] { false, "Cannot find a valid upgrade" };
 
@@ -83,10 +83,10 @@ public class PocketAPI implements ILuaAPI
             ItemStack stack = previousUpgrade.getCraftingItem();
             if( !stack.isEmpty() )
             {
-                stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem );
+                stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.selected );
                 if( !stack.isEmpty() )
                 {
-                    WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() );
+                    WorldUtil.dropItemStack( stack, player.getCommandSenderWorld(), player.position() );
                 }
             }
         }
@@ -120,10 +120,10 @@ public class PocketAPI implements ILuaAPI
         ItemStack stack = previousUpgrade.getCraftingItem();
         if( !stack.isEmpty() )
         {
-            stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.currentItem );
+            stack = InventoryUtil.storeItems( stack, new PlayerMainInvWrapper( inventory ), inventory.selected );
             if( stack.isEmpty() )
             {
-                WorldUtil.dropItemStack( stack, player.getEntityWorld(), player.getPositionVec() );
+                WorldUtil.dropItemStack( stack, player.getCommandSenderWorld(), player.position() );
             }
         }
 
diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java
index f9dcb00e5..c098c0cd9 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java
@@ -54,12 +54,12 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
         if( entity instanceof PlayerEntity )
         {
             PlayerInventory inventory = ((PlayerEntity) entity).inventory;
-            return inventory.mainInventory.contains( m_stack ) || inventory.offHandInventory.contains( m_stack ) ? entity : null;
+            return inventory.items.contains( m_stack ) || inventory.offhand.contains( m_stack ) ? entity : null;
         }
         else if( entity instanceof LivingEntity )
         {
             LivingEntity living = (LivingEntity) entity;
-            return living.getHeldItemMainhand() == m_stack || living.getHeldItemOffhand() == m_stack ? entity : null;
+            return living.getMainHandItem() == m_stack || living.getOffhandItem() == m_stack ? entity : null;
         }
         else
         {
@@ -116,7 +116,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
     @Override
     public void updateUpgradeNBTData()
     {
-        if( m_entity instanceof PlayerEntity ) ((PlayerEntity) m_entity).inventory.markDirty();
+        if( m_entity instanceof PlayerEntity ) ((PlayerEntity) m_entity).inventory.setChanged();
     }
 
     @Override
@@ -162,8 +162,8 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
     {
         if( entity != null )
         {
-            setWorld( entity.getEntityWorld() );
-            setPosition( entity.getPosition() );
+            setWorld( entity.getCommandSenderWorld() );
+            setPosition( entity.getCommandSenderBlockPosition() );
         }
 
         // If a new entity has picked it up then rebroadcast the terminal to them
diff --git a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java
index a762936d1..e49aa6b97 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/inventory/ContainerPocketComputer.java
@@ -26,7 +26,7 @@ public final class ContainerPocketComputer extends ContainerComputerBase
     private ContainerPocketComputer( int id, ServerComputer computer, ItemPocketComputer item, Hand hand )
     {
         super( Registry.ModContainers.POCKET_COMPUTER.get(), id, p -> {
-            ItemStack stack = p.getHeldItem( hand );
+            ItemStack stack = p.getItemInHand( hand );
             return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer;
         }, computer, item.getFamily() );
     }
@@ -46,7 +46,7 @@ public final class ContainerPocketComputer extends ContainerComputerBase
         public Factory( ServerComputer computer, ItemStack stack, ItemPocketComputer item, Hand hand )
         {
             this.computer = computer;
-            this.name = stack.getDisplayName();
+            this.name = stack.getHoverName();
             this.item = item;
             this.hand = hand;
         }
diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
index e969d7cd7..12c3228ee 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
@@ -45,6 +45,8 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 
+import net.minecraft.item.Item.Properties;
+
 public class ItemPocketComputer extends Item implements IComputerItem, IMedia, IColouredItem
 {
     private static final String NBT_UPGRADE = "Upgrade";
@@ -60,24 +62,24 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
     {
         super( settings );
         this.family = family;
-        addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "state" ), COMPUTER_STATE );
-        addPropertyOverride( new ResourceLocation( ComputerCraft.MOD_ID, "coloured" ), COMPUTER_COLOURED );
+        addProperty( new ResourceLocation( ComputerCraft.MOD_ID, "state" ), COMPUTER_STATE );
+        addProperty( new ResourceLocation( ComputerCraft.MOD_ID, "coloured" ), COMPUTER_COLOURED );
     }
 
     public ItemStack create( int id, String label, int colour, IPocketUpgrade upgrade )
     {
         ItemStack result = new ItemStack( this );
         if( id >= 0 ) result.getOrCreateTag().putInt( NBT_ID, id );
-        if( label != null ) result.setDisplayName( new StringTextComponent( label ) );
+        if( label != null ) result.setHoverName( new StringTextComponent( label ) );
         if( upgrade != null ) result.getOrCreateTag().putString( NBT_UPGRADE, upgrade.getUpgradeID().toString() );
         if( colour != -1 ) result.getOrCreateTag().putInt( NBT_COLOUR, colour );
         return result;
     }
 
     @Override
-    public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList stacks )
+    public void fillItemCategory( @Nonnull ItemGroup group, @Nonnull NonNullList stacks )
     {
-        if( !isInGroup( group ) ) return;
+        if( !allowdedIn( group ) ) return;
         stacks.add( create( -1, null, -1, null ) );
         for( IPocketUpgrade upgrade : PocketUpgrades.getVanillaUpgrades() )
         {
@@ -88,7 +90,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
     @Override
     public void inventoryTick( @Nonnull ItemStack stack, World world, @Nonnull Entity entity, int slotNum, boolean selected )
     {
-        if( !world.isRemote )
+        if( !world.isClientSide )
         {
             // Server side
             IInventory inventory = entity instanceof PlayerEntity ? ((PlayerEntity) entity).inventory : null;
@@ -107,7 +109,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
                 if( id != getComputerID( stack ) )
                 {
                     setComputerID( stack, id );
-                    if( inventory != null ) inventory.markDirty();
+                    if( inventory != null ) inventory.setChanged();
                 }
 
                 // Sync label
@@ -115,7 +117,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
                 if( !Objects.equal( label, getLabel( stack ) ) )
                 {
                     setLabel( stack, label );
-                    if( inventory != null ) inventory.markDirty();
+                    if( inventory != null ) inventory.setChanged();
                 }
 
                 // Update pocket upgrade
@@ -134,10 +136,10 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
 
     @Nonnull
     @Override
-    public ActionResult onItemRightClick( World world, PlayerEntity player, @Nonnull Hand hand )
+    public ActionResult use( World world, PlayerEntity player, @Nonnull Hand hand )
     {
-        ItemStack stack = player.getHeldItem( hand );
-        if( !world.isRemote )
+        ItemStack stack = player.getItemInHand( hand );
+        if( !world.isClientSide )
         {
             PocketServerComputer computer = createServerComputer( world, player.inventory, player, stack );
 
@@ -164,9 +166,9 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
 
     @Nonnull
     @Override
-    public ITextComponent getDisplayName( @Nonnull ItemStack stack )
+    public ITextComponent getName( @Nonnull ItemStack stack )
     {
-        String baseString = getTranslationKey( stack );
+        String baseString = getDescriptionId( stack );
         IPocketUpgrade upgrade = getUpgrade( stack );
         if( upgrade != null )
         {
@@ -176,13 +178,13 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
         }
         else
         {
-            return super.getDisplayName( stack );
+            return super.getName( stack );
         }
     }
 
 
     @Override
-    public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, ITooltipFlag flag )
+    public void appendHoverText( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, ITooltipFlag flag )
     {
         if( flag.isAdvanced() || getLabel( stack ) == null )
         {
@@ -190,7 +192,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
             if( id >= 0 )
             {
                 list.add( new TranslationTextComponent( "gui.computercraft.tooltip.computer_id", id )
-                    .applyTextStyle( TextFormatting.GRAY ) );
+                    .withStyle( TextFormatting.GRAY ) );
             }
         }
     }
@@ -213,7 +215,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
 
     public PocketServerComputer createServerComputer( final World world, IInventory inventory, Entity entity, @Nonnull ItemStack stack )
     {
-        if( world.isRemote ) return null;
+        if( world.isClientSide ) return null;
 
         PocketServerComputer computer;
         int instanceID = getInstanceID( stack );
@@ -249,7 +251,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
             computer.updateValues( entity, stack, getUpgrade( stack ) );
             computer.addAPI( new PocketAPI( computer ) );
             ComputerCraft.serverComputerRegistry.add( instanceID, computer );
-            if( inventory != null ) inventory.markDirty();
+            if( inventory != null ) inventory.setChanged();
         }
         computer.setWorld( world );
         return computer;
@@ -319,11 +321,11 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
     {
         if( label != null )
         {
-            stack.setDisplayName( new StringTextComponent( label ) );
+            stack.setHoverName( new StringTextComponent( label ) );
         }
         else
         {
-            stack.clearCustomName();
+            stack.resetHoverName();
         }
         return true;
     }
@@ -409,7 +411,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
 
     public static CompoundNBT getUpgradeInfo( @Nonnull ItemStack stack )
     {
-        return stack.getOrCreateChildTag( NBT_UPGRADE_INFO );
+        return stack.getOrCreateTagElement( NBT_UPGRADE_INFO );
     }
 
     private static final IItemPropertyGetter COMPUTER_STATE = ( stack, world, player ) -> getState( stack ).ordinal();
diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java
index ea84a3042..47c8bdaf3 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModem.java
@@ -47,7 +47,7 @@ public class PocketModem extends AbstractPocketUpgrade
 
         PocketModemPeripheral modem = (PocketModemPeripheral) peripheral;
 
-        if( entity != null ) modem.setLocation( entity.getEntityWorld(), entity.getEyePosition( 1 ) );
+        if( entity != null ) modem.setLocation( entity.getCommandSenderWorld(), entity.getEyePosition( 1 ) );
 
         ModemState state = modem.getModemState();
         if( state.pollChanged() ) access.setLight( state.isOpen() ? 0xBA0000 : -1 );
diff --git a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java
index 4bba1b47c..e0cb29e99 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketSpeaker.java
@@ -39,7 +39,7 @@ public class PocketSpeaker extends AbstractPocketUpgrade
         Entity entity = access.getEntity();
         if( entity != null )
         {
-            speaker.setLocation( entity.getEntityWorld(), entity.getEyePosition( 1 ) );
+            speaker.setLocation( entity.getCommandSenderWorld(), entity.getEyePosition( 1 ) );
         }
 
         speaker.update();
diff --git a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java
index 17bad137e..0a331a567 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/recipes/PocketComputerUpgradeRecipe.java
@@ -28,14 +28,14 @@ public final class PocketComputerUpgradeRecipe extends SpecialRecipe
     }
 
     @Override
-    public boolean canFit( int x, int y )
+    public boolean canCraftInDimensions( int x, int y )
     {
         return x >= 2 && y >= 2;
     }
 
     @Nonnull
     @Override
-    public ItemStack getRecipeOutput()
+    public ItemStack getResultItem()
     {
         return PocketComputerItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null );
     }
@@ -43,12 +43,12 @@ public final class PocketComputerUpgradeRecipe extends SpecialRecipe
     @Override
     public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world )
     {
-        return !getCraftingResult( inventory ).isEmpty();
+        return !assemble( inventory ).isEmpty();
     }
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory )
+    public ItemStack assemble( @Nonnull CraftingInventory inventory )
     {
         // Scan the grid for a pocket computer
         ItemStack computer = ItemStack.EMPTY;
@@ -59,7 +59,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialRecipe
         {
             for( int x = 0; x < inventory.getWidth(); x++ )
             {
-                ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() );
+                ItemStack item = inventory.getItem( x + y * inventory.getWidth() );
                 if( !item.isEmpty() && item.getItem() instanceof ItemPocketComputer )
                 {
                     computer = item;
@@ -81,7 +81,7 @@ public final class PocketComputerUpgradeRecipe extends SpecialRecipe
         {
             for( int x = 0; x < inventory.getWidth(); x++ )
             {
-                ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() );
+                ItemStack item = inventory.getItem( x + y * inventory.getWidth() );
                 if( x == computerX && y == computerY ) continue;
 
                 if( x == computerX && y == computerY - 1 )
diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java
index 4c5727bfd..38eb89930 100644
--- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java
+++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java
@@ -68,19 +68,19 @@ public final class ComputerCraftProxyCommon
 
     public static void registerLoot()
     {
-        LootConditionManager.registerCondition( ConstantLootConditionSerializer.of(
+        LootConditionManager.register( ConstantLootConditionSerializer.of(
             new ResourceLocation( ComputerCraft.MOD_ID, "block_named" ),
             BlockNamedEntityLootCondition.class,
             BlockNamedEntityLootCondition.INSTANCE
         ) );
 
-        LootConditionManager.registerCondition( ConstantLootConditionSerializer.of(
+        LootConditionManager.register( ConstantLootConditionSerializer.of(
             new ResourceLocation( ComputerCraft.MOD_ID, "player_creative" ),
             PlayerCreativeLootCondition.class,
             PlayerCreativeLootCondition.INSTANCE
         ) );
 
-        LootConditionManager.registerCondition( ConstantLootConditionSerializer.of(
+        LootConditionManager.register( ConstantLootConditionSerializer.of(
             new ResourceLocation( ComputerCraft.MOD_ID, "has_id" ),
             HasComputerIdLootCondition.class,
             HasComputerIdLootCondition.INSTANCE
@@ -176,16 +176,16 @@ public final class ComputerCraftProxyCommon
         public static final ResourceLocation LOOT_TREASURE_DISK = new ResourceLocation( ComputerCraft.MOD_ID, "treasure_disk" );
 
         private static final Set TABLES = new HashSet<>( Arrays.asList(
-            LootTables.CHESTS_SIMPLE_DUNGEON,
-            LootTables.CHESTS_ABANDONED_MINESHAFT,
-            LootTables.CHESTS_STRONGHOLD_CORRIDOR,
-            LootTables.CHESTS_STRONGHOLD_CROSSING,
-            LootTables.CHESTS_STRONGHOLD_LIBRARY,
-            LootTables.CHESTS_DESERT_PYRAMID,
-            LootTables.CHESTS_JUNGLE_TEMPLE,
-            LootTables.CHESTS_IGLOO_CHEST,
-            LootTables.CHESTS_WOODLAND_MANSION,
-            LootTables.CHESTS_VILLAGE_VILLAGE_CARTOGRAPHER
+            LootTables.SIMPLE_DUNGEON,
+            LootTables.ABANDONED_MINESHAFT,
+            LootTables.STRONGHOLD_CORRIDOR,
+            LootTables.STRONGHOLD_CROSSING,
+            LootTables.STRONGHOLD_LIBRARY,
+            LootTables.DESERT_PYRAMID,
+            LootTables.JUNGLE_TEMPLE,
+            LootTables.IGLOO_CHEST,
+            LootTables.WOODLAND_MANSION,
+            LootTables.VILLAGE_CARTOGRAPHER
         ) );
 
         @SubscribeEvent
@@ -194,9 +194,9 @@ public final class ComputerCraftProxyCommon
             ResourceLocation name = event.getName();
             if( !name.getNamespace().equals( "minecraft" ) || !TABLES.contains( name ) ) return;
 
-            event.getTable().addPool( LootPool.builder()
-                .addEntry( TableLootEntry.builder( LOOT_TREASURE_DISK ) )
-                .rolls( ConstantRange.of( 1 ) )
+            event.getTable().addPool( LootPool.lootPool()
+                .add( TableLootEntry.lootTableReference( LOOT_TREASURE_DISK ) )
+                .setRolls( ConstantRange.exactly( 1 ) )
                 .name( "computercraft_treasure" )
                 .build() );
         }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java
index b09bdc4f9..e1d35ce49 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java
@@ -308,7 +308,7 @@ public class TurtleAPI implements ILuaAPI
     public final int getItemCount( Optional slot ) throws LuaException
     {
         int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() );
-        return turtle.getInventory().getStackInSlot( actualSlot ).getCount();
+        return turtle.getInventory().getItem( actualSlot ).getCount();
     }
 
     /**
@@ -324,7 +324,7 @@ public class TurtleAPI implements ILuaAPI
     public final int getItemSpace( Optional slot ) throws LuaException
     {
         int actualSlot = checkSlot( slot ).orElse( turtle.getSelectedSlot() );
-        ItemStack stack = turtle.getInventory().getStackInSlot( actualSlot );
+        ItemStack stack = turtle.getInventory().getItem( actualSlot );
         return stack.isEmpty() ? 64 : Math.min( stack.getMaxStackSize(), 64 ) - stack.getCount();
     }
 
@@ -600,7 +600,7 @@ public class TurtleAPI implements ILuaAPI
 
     private Object[] getItemDetail( int slot, boolean detailed )
     {
-        ItemStack stack = turtle.getInventory().getStackInSlot( slot );
+        ItemStack stack = turtle.getInventory().getItem( slot );
         if( stack.isEmpty() ) return new Object[] { null };
 
         Map table = detailed
diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java
index 7efc6ceb8..81a42d134 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java
@@ -44,11 +44,13 @@ import javax.annotation.Nullable;
 import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
 import static net.minecraft.state.properties.BlockStateProperties.WATERLOGGED;
 
+import net.minecraft.block.Block.Properties;
+
 public class BlockTurtle extends BlockComputerBase implements IWaterLoggable
 {
     public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
 
-    private static final VoxelShape DEFAULT_SHAPE = VoxelShapes.create(
+    private static final VoxelShape DEFAULT_SHAPE = VoxelShapes.box(
         0.125, 0.125, 0.125,
         0.875, 0.875, 0.875
     );
@@ -56,14 +58,14 @@ public class BlockTurtle extends BlockComputerBase implements IWater
     public BlockTurtle( Properties settings, ComputerFamily family, RegistryObject> type )
     {
         super( settings, family, type );
-        setDefaultState( getStateContainer().getBaseState()
-            .with( FACING, Direction.NORTH )
-            .with( WATERLOGGED, false )
+        registerDefaultState( getStateDefinition().any()
+            .setValue( FACING, Direction.NORTH )
+            .setValue( WATERLOGGED, false )
         );
     }
 
     @Override
-    protected void fillStateContainer( StateContainer.Builder builder )
+    protected void createBlockStateDefinition( StateContainer.Builder builder )
     {
         builder.add( FACING, WATERLOGGED );
     }
@@ -71,7 +73,7 @@ public class BlockTurtle extends BlockComputerBase implements IWater
     @Nonnull
     @Override
     @Deprecated
-    public BlockRenderType getRenderType( @Nonnull BlockState state )
+    public BlockRenderType getRenderShape( @Nonnull BlockState state )
     {
         return BlockRenderType.ENTITYBLOCK_ANIMATED;
     }
@@ -81,18 +83,18 @@ public class BlockTurtle extends BlockComputerBase implements IWater
     @Deprecated
     public VoxelShape getShape( @Nonnull BlockState state, IBlockReader world, @Nonnull BlockPos pos, @Nonnull ISelectionContext context )
     {
-        TileEntity tile = world.getTileEntity( pos );
+        TileEntity tile = world.getBlockEntity( pos );
         Vec3d offset = tile instanceof TileTurtle ? ((TileTurtle) tile).getRenderOffset( 1.0f ) : Vec3d.ZERO;
-        return offset.equals( Vec3d.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.withOffset( offset.x, offset.y, offset.z );
+        return offset.equals( Vec3d.ZERO ) ? DEFAULT_SHAPE : DEFAULT_SHAPE.move( offset.x, offset.y, offset.z );
     }
 
     @Nullable
     @Override
     public BlockState getStateForPlacement( BlockItemUseContext placement )
     {
-        return getDefaultState()
-            .with( FACING, placement.getPlacementHorizontalFacing() )
-            .with( WATERLOGGED, getWaterloggedStateForPlacement( placement ) );
+        return defaultBlockState()
+            .setValue( FACING, placement.getHorizontalDirection() )
+            .setValue( WATERLOGGED, getWaterloggedStateForPlacement( placement ) );
     }
 
     @Nonnull
@@ -106,19 +108,19 @@ public class BlockTurtle extends BlockComputerBase implements IWater
     @Nonnull
     @Override
     @Deprecated
-    public BlockState updatePostPlacement( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
+    public BlockState updateShape( @Nonnull BlockState state, @Nonnull Direction side, @Nonnull BlockState otherState, @Nonnull IWorld world, @Nonnull BlockPos pos, @Nonnull BlockPos otherPos )
     {
         updateWaterloggedPostPlacement( state, world, pos );
         return state;
     }
 
     @Override
-    public void onBlockPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack )
+    public void setPlacedBy( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable LivingEntity player, @Nonnull ItemStack stack )
     {
-        super.onBlockPlacedBy( world, pos, state, player, stack );
+        super.setPlacedBy( world, pos, state, player, stack );
 
-        TileEntity tile = world.getTileEntity( pos );
-        if( !world.isRemote && tile instanceof TileTurtle )
+        TileEntity tile = world.getBlockEntity( pos );
+        if( !world.isClientSide && tile instanceof TileTurtle )
         {
             TileTurtle turtle = (TileTurtle) tile;
 
diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java
index cd5d5973a..46b5fef4c 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java
@@ -86,10 +86,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     protected ServerComputer createComputer( int instanceID, int id )
     {
         ServerComputer computer = new ServerComputer(
-            getWorld(), id, label, instanceID, getFamily(),
+            getLevel(), id, label, instanceID, getFamily(),
             ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight
         );
-        computer.setPosition( getPos() );
+        computer.setPosition( getBlockPos() );
         computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) );
         m_brain.setupComputer( computer );
         return computer;
@@ -109,15 +109,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
             super.destroy();
 
             // Drop contents
-            if( !getWorld().isRemote )
+            if( !getLevel().isClientSide )
             {
-                int size = getSizeInventory();
+                int size = getContainerSize();
                 for( int i = 0; i < size; i++ )
                 {
-                    ItemStack stack = getStackInSlot( i );
+                    ItemStack stack = getItem( i );
                     if( !stack.isEmpty() )
                     {
-                        WorldUtil.dropItemStack( stack, getWorld(), getPos() );
+                        WorldUtil.dropItemStack( stack, getLevel(), getBlockPos() );
                     }
                 }
             }
@@ -127,7 +127,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
             // Just turn off any redstone we had on
             for( Direction dir : DirectionUtil.FACINGS )
             {
-                RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir );
+                RedstoneUtil.propagateRedstoneOutput( getLevel(), getBlockPos(), dir );
             }
         }
     }
@@ -154,13 +154,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTraceResult hit )
     {
         // Apply dye
-        ItemStack currentItem = player.getHeldItem( hand );
+        ItemStack currentItem = player.getItemInHand( hand );
         if( !currentItem.isEmpty() )
         {
             if( currentItem.getItem() instanceof DyeItem )
             {
                 // Dye to change turtle colour
-                if( !getWorld().isRemote )
+                if( !getLevel().isClientSide )
                 {
                     DyeColor dye = ((DyeItem) currentItem.getItem()).getDyeColor();
                     if( m_brain.getDyeColour() != dye )
@@ -177,15 +177,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
             else if( currentItem.getItem() == Items.WATER_BUCKET && m_brain.getColour() != -1 )
             {
                 // Water to remove turtle colour
-                if( !getWorld().isRemote )
+                if( !getLevel().isClientSide )
                 {
                     if( m_brain.getColour() != -1 )
                     {
                         m_brain.setColour( -1 );
                         if( !player.isCreative() )
                         {
-                            player.setHeldItem( hand, new ItemStack( Items.BUCKET ) );
-                            player.inventory.markDirty();
+                            player.setItemInHand( hand, new ItemStack( Items.BUCKET ) );
+                            player.inventory.setChanged();
                         }
                     }
                 }
@@ -214,15 +214,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     {
         super.tick();
         m_brain.update();
-        if( !getWorld().isRemote && m_inventoryChanged )
+        if( !getLevel().isClientSide && m_inventoryChanged )
         {
             ServerComputer computer = getServerComputer();
             if( computer != null ) computer.queueEvent( "turtle_inventory" );
 
             m_inventoryChanged = false;
-            for( int n = 0; n < getSizeInventory(); n++ )
+            for( int n = 0; n < getContainerSize(); n++ )
             {
-                m_previousInventory.set( n, getStackInSlot( n ).copy() );
+                m_previousInventory.set( n, getItem( n ).copy() );
             }
         }
     }
@@ -256,9 +256,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     }
 
     @Override
-    public void read( @Nonnull CompoundNBT nbt )
+    public void load( @Nonnull CompoundNBT nbt )
     {
-        super.read( nbt );
+        super.load( nbt );
 
         // Read inventory
         ListNBT nbttaglist = nbt.getList( "Items", Constants.NBT.TAG_COMPOUND );
@@ -268,9 +268,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
         {
             CompoundNBT tag = nbttaglist.getCompound( i );
             int slot = tag.getByte( "Slot" ) & 0xff;
-            if( slot < getSizeInventory() )
+            if( slot < getContainerSize() )
             {
-                m_inventory.set( slot, ItemStack.read( tag ) );
+                m_inventory.set( slot, ItemStack.of( tag ) );
                 m_previousInventory.set( slot, m_inventory.get( slot ).copy() );
             }
         }
@@ -281,7 +281,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
 
     @Nonnull
     @Override
-    public CompoundNBT write( @Nonnull CompoundNBT nbt )
+    public CompoundNBT save( @Nonnull CompoundNBT nbt )
     {
         // Write inventory
         ListNBT nbttaglist = new ListNBT();
@@ -291,7 +291,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
             {
                 CompoundNBT tag = new CompoundNBT();
                 tag.putByte( "Slot", (byte) i );
-                m_inventory.get( i ).write( tag );
+                m_inventory.get( i ).save( tag );
                 nbttaglist.add( tag );
             }
         }
@@ -300,7 +300,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
         // Write brain
         nbt = m_brain.writeToNBT( nbt );
 
-        return super.write( nbt );
+        return super.save( nbt );
     }
 
     @Override
@@ -314,13 +314,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     @Override
     public Direction getDirection()
     {
-        return getBlockState().get( BlockTurtle.FACING );
+        return getBlockState().getValue( BlockTurtle.FACING );
     }
 
     public void setDirection( Direction dir )
     {
         if( dir.getAxis() == Direction.Axis.Y ) dir = Direction.NORTH;
-        world.setBlockState( pos, getBlockState().with( BlockTurtle.FACING, dir ) );
+        level.setBlockAndUpdate( worldPosition, getBlockState().setValue( BlockTurtle.FACING, dir ) );
         updateOutput();
         updateInput();
         onTileEntityChange();
@@ -373,13 +373,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     void setOwningPlayer( GameProfile player )
     {
         m_brain.setOwningPlayer( player );
-        markDirty();
+        setChanged();
     }
 
     // IInventory
 
     @Override
-    public int getSizeInventory()
+    public int getContainerSize()
     {
         return INVENTORY_SIZE;
     }
@@ -396,32 +396,32 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
 
     @Nonnull
     @Override
-    public ItemStack getStackInSlot( int slot )
+    public ItemStack getItem( int slot )
     {
         return slot >= 0 && slot < INVENTORY_SIZE ? m_inventory.get( slot ) : ItemStack.EMPTY;
     }
 
     @Nonnull
     @Override
-    public ItemStack removeStackFromSlot( int slot )
+    public ItemStack removeItemNoUpdate( int slot )
     {
-        ItemStack result = getStackInSlot( slot );
-        setInventorySlotContents( slot, ItemStack.EMPTY );
+        ItemStack result = getItem( slot );
+        setItem( slot, ItemStack.EMPTY );
         return result;
     }
 
     @Nonnull
     @Override
-    public ItemStack decrStackSize( int slot, int count )
+    public ItemStack removeItem( int slot, int count )
     {
         if( count == 0 ) return ItemStack.EMPTY;
 
-        ItemStack stack = getStackInSlot( slot );
+        ItemStack stack = getItem( slot );
         if( stack.isEmpty() ) return ItemStack.EMPTY;
 
         if( stack.getCount() <= count )
         {
-            setInventorySlotContents( slot, ItemStack.EMPTY );
+            setItem( slot, ItemStack.EMPTY );
             return stack;
         }
 
@@ -431,7 +431,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     }
 
     @Override
-    public void setInventorySlotContents( int i, @Nonnull ItemStack stack )
+    public void setItem( int i, @Nonnull ItemStack stack )
     {
         if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, m_inventory.get( i ) ) )
         {
@@ -441,7 +441,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     }
 
     @Override
-    public void clear()
+    public void clearContent()
     {
         boolean changed = false;
         for( int i = 0; i < INVENTORY_SIZE; i++ )
@@ -457,14 +457,14 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     }
 
     @Override
-    public void markDirty()
+    public void setChanged()
     {
-        super.markDirty();
+        super.setChanged();
         if( !m_inventoryChanged )
         {
-            for( int n = 0; n < getSizeInventory(); n++ )
+            for( int n = 0; n < getContainerSize(); n++ )
             {
-                if( !ItemStack.areItemStacksEqual( getStackInSlot( n ), m_previousInventory.get( n ) ) )
+                if( !ItemStack.matches( getItem( n ), m_previousInventory.get( n ) ) )
                 {
                     m_inventoryChanged = true;
                     break;
@@ -474,20 +474,20 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
     }
 
     @Override
-    public boolean isUsableByPlayer( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
         return isUsable( player, false );
     }
 
     private void onInventoryDefinitelyChanged()
     {
-        super.markDirty();
+        super.setChanged();
         m_inventoryChanged = true;
     }
 
     public void onTileEntityChange()
     {
-        super.markDirty();
+        super.setChanged();
     }
 
     // Networking stuff
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java
index e09af75cb..9ba2d1456 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java
@@ -124,7 +124,7 @@ public class TurtleBrain implements ITurtleAccess
     public void update()
     {
         World world = getWorld();
-        if( !world.isRemote )
+        if( !world.isClientSide )
         {
             // Advance movement
             updateCommands();
@@ -273,20 +273,20 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public World getWorld()
     {
-        return m_owner.getWorld();
+        return m_owner.getLevel();
     }
 
     @Nonnull
     @Override
     public BlockPos getPosition()
     {
-        return m_owner.getPos();
+        return m_owner.getBlockPos();
     }
 
     @Override
     public boolean teleportTo( @Nonnull World world, @Nonnull BlockPos pos )
     {
-        if( world.isRemote || getWorld().isRemote )
+        if( world.isClientSide || getWorld().isClientSide )
         {
             throw new UnsupportedOperationException( "Cannot teleport on the client" );
         }
@@ -294,7 +294,7 @@ public class TurtleBrain implements ITurtleAccess
         // Cache info about the old turtle (so we don't access this after we delete ourselves)
         World oldWorld = getWorld();
         TileTurtle oldOwner = m_owner;
-        BlockPos oldPos = m_owner.getPos();
+        BlockPos oldPos = m_owner.getBlockPos();
         BlockState oldBlock = m_owner.getBlockState();
 
         if( oldWorld == world && oldPos.equals( pos ) )
@@ -307,31 +307,31 @@ public class TurtleBrain implements ITurtleAccess
         if( !world.isAreaLoaded( pos, 0 ) ) return false;
 
         // Ensure we're inside the world border
-        if( !world.getWorldBorder().contains( pos ) ) return false;
+        if( !world.getWorldBorder().isWithinBounds( pos ) ) return false;
 
         IFluidState existingFluid = world.getBlockState( pos ).getFluidState();
         BlockState newState = oldBlock
             // We only mark this as waterlogged when travelling into a source block. This prevents us from spreading
             // fluid by creating a new source when moving into a block, causing the next block to be almost full and
             // then moving into that.
-            .with( WATERLOGGED, existingFluid.isTagged( FluidTags.WATER ) && existingFluid.isSource() );
+            .setValue( WATERLOGGED, existingFluid.is( FluidTags.WATER ) && existingFluid.isSource() );
 
         oldOwner.notifyMoveStart();
 
         try
         {
             // Create a new turtle
-            if( world.setBlockState( pos, newState, 0 ) )
+            if( world.setBlock( pos, newState, 0 ) )
             {
                 Block block = world.getBlockState( pos ).getBlock();
                 if( block == oldBlock.getBlock() )
                 {
-                    TileEntity newTile = world.getTileEntity( pos );
+                    TileEntity newTile = world.getBlockEntity( pos );
                     if( newTile instanceof TileTurtle )
                     {
                         // Copy the old turtle state into the new turtle
                         TileTurtle newTurtle = (TileTurtle) newTile;
-                        newTurtle.setWorldAndPos( world, pos );
+                        newTurtle.setLevelAndPosition( world, pos );
                         newTurtle.transferStateFrom( oldOwner );
                         newTurtle.createServerComputer().setWorld( world );
                         newTurtle.createServerComputer().setPosition( pos );
@@ -365,7 +365,7 @@ public class TurtleBrain implements ITurtleAccess
     public Vec3d getVisualPosition( float f )
     {
         Vec3d offset = getRenderOffset( f );
-        BlockPos pos = m_owner.getPos();
+        BlockPos pos = m_owner.getBlockPos();
         return new Vec3d(
             pos.getX() + 0.5 + offset.x,
             pos.getY() + 0.5 + offset.y,
@@ -376,7 +376,7 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public float getVisualYaw( float f )
     {
-        float yaw = getDirection().getHorizontalAngle();
+        float yaw = getDirection().toYRot();
         switch( m_animation )
         {
             case TURN_LEFT:
@@ -423,9 +423,9 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public void setSelectedSlot( int slot )
     {
-        if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot set the slot on the client" );
+        if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot set the slot on the client" );
 
-        if( slot >= 0 && slot < m_owner.getSizeInventory() )
+        if( slot >= 0 && slot < m_owner.getContainerSize() )
         {
             m_selectedSlot = slot;
             m_owner.onTileEntityChange();
@@ -481,7 +481,7 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public boolean consumeFuel( int fuel )
     {
-        if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot consume fuel on the client" );
+        if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot consume fuel on the client" );
 
         if( !isFuelNeeded() ) return true;
 
@@ -497,7 +497,7 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public void addFuel( int fuel )
     {
-        if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot add fuel on the client" );
+        if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot add fuel on the client" );
 
         int addition = Math.max( fuel, 0 );
         setFuelLevel( getFuelLevel() + addition );
@@ -513,7 +513,7 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public MethodResult executeCommand( @Nonnull ITurtleCommand command )
     {
-        if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot run commands on the client" );
+        if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot run commands on the client" );
 
         // Issue command
         int commandID = issueCommand( command );
@@ -523,7 +523,7 @@ public class TurtleBrain implements ITurtleAccess
     @Override
     public void playAnimation( @Nonnull TurtleAnimation animation )
     {
-        if( getWorld().isRemote ) throw new UnsupportedOperationException( "Cannot play animations on the client" );
+        if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot play animations on the client" );
 
         m_animation = animation;
         if( m_animation == TurtleAnimation.SHORT_WAIT )
@@ -636,7 +636,7 @@ public class TurtleBrain implements ITurtleAccess
         if( upgrade != null ) m_upgrades.put( side, upgrade );
 
         // Notify clients and create peripherals
-        if( m_owner.getWorld() != null )
+        if( m_owner.getLevel() != null )
         {
             updatePeripherals( m_owner.createServerComputer() );
             m_owner.updateBlock();
@@ -694,9 +694,9 @@ public class TurtleBrain implements ITurtleAccess
 
                 double distance = -1.0 + getAnimationFraction( f );
                 return new Vec3d(
-                    distance * dir.getXOffset(),
-                    distance * dir.getYOffset(),
-                    distance * dir.getZOffset()
+                    distance * dir.getStepX(),
+                    distance * dir.getStepY(),
+                    distance * dir.getStepZ()
                 );
             }
             default:
@@ -848,41 +848,41 @@ public class TurtleBrain implements ITurtleAccess
 
                     float pushFrac = 1.0f - (float) (m_animationProgress + 1) / ANIM_DURATION;
                     float push = Math.max( pushFrac + 0.0125f, 0.0f );
-                    if( moveDir.getXOffset() < 0 )
+                    if( moveDir.getStepX() < 0 )
                     {
-                        minX += moveDir.getXOffset() * push;
+                        minX += moveDir.getStepX() * push;
                     }
                     else
                     {
-                        maxX -= moveDir.getXOffset() * push;
+                        maxX -= moveDir.getStepX() * push;
                     }
 
-                    if( moveDir.getYOffset() < 0 )
+                    if( moveDir.getStepY() < 0 )
                     {
-                        minY += moveDir.getYOffset() * push;
+                        minY += moveDir.getStepY() * push;
                     }
                     else
                     {
-                        maxY -= moveDir.getYOffset() * push;
+                        maxY -= moveDir.getStepY() * push;
                     }
 
-                    if( moveDir.getZOffset() < 0 )
+                    if( moveDir.getStepZ() < 0 )
                     {
-                        minZ += moveDir.getZOffset() * push;
+                        minZ += moveDir.getStepZ() * push;
                     }
                     else
                     {
-                        maxZ -= moveDir.getZOffset() * push;
+                        maxZ -= moveDir.getStepZ() * push;
                     }
 
                     AxisAlignedBB aabb = new AxisAlignedBB( minX, minY, minZ, maxX, maxY, maxZ );
-                    List list = world.getEntitiesWithinAABB( Entity.class, aabb, EntityPredicates.NOT_SPECTATING );
+                    List list = world.getEntitiesOfClass( Entity.class, aabb, EntityPredicates.NO_SPECTATORS );
                     if( !list.isEmpty() )
                     {
                         double pushStep = 1.0f / ANIM_DURATION;
-                        double pushStepX = moveDir.getXOffset() * pushStep;
-                        double pushStepY = moveDir.getYOffset() * pushStep;
-                        double pushStepZ = moveDir.getZOffset() * pushStep;
+                        double pushStepX = moveDir.getStepX() * pushStep;
+                        double pushStepY = moveDir.getStepY() * pushStep;
+                        double pushStepZ = moveDir.getStepZ() * pushStep;
                         for( Entity entity : list )
                         {
                             entity.move( MoverType.PISTON, new Vec3d( pushStepX, pushStepY, pushStepZ ) );
@@ -892,7 +892,7 @@ public class TurtleBrain implements ITurtleAccess
             }
 
             // Advance valentines day easter egg
-            if( world.isRemote && m_animation == TurtleAnimation.MOVE_FORWARD && m_animationProgress == 4 )
+            if( world.isClientSide && m_animation == TurtleAnimation.MOVE_FORWARD && m_animationProgress == 4 )
             {
                 // Spawn love pfx if valentines day
                 Holiday currentHoliday = HolidayUtil.getCurrentHoliday();
@@ -901,14 +901,14 @@ public class TurtleBrain implements ITurtleAccess
                     Vec3d position = getVisualPosition( 1.0f );
                     if( position != null )
                     {
-                        double x = position.x + world.rand.nextGaussian() * 0.1;
-                        double y = position.y + 0.5 + world.rand.nextGaussian() * 0.1;
-                        double z = position.z + world.rand.nextGaussian() * 0.1;
+                        double x = position.x + world.random.nextGaussian() * 0.1;
+                        double y = position.y + 0.5 + world.random.nextGaussian() * 0.1;
+                        double z = position.z + world.random.nextGaussian() * 0.1;
                         world.addParticle(
                             ParticleTypes.HEART, x, y, z,
-                            world.rand.nextGaussian() * 0.02,
-                            world.rand.nextGaussian() * 0.02,
-                            world.rand.nextGaussian() * 0.02
+                            world.random.nextGaussian() * 0.02,
+                            world.random.nextGaussian() * 0.02,
+                            world.random.nextGaussian() * 0.02
                         );
                     }
                 }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java
index 01633a247..9c018ce25 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java
@@ -38,15 +38,15 @@ public class TurtleCompareCommand implements ITurtleCommand
         Direction direction = m_direction.toWorldDir( turtle );
 
         // Get currently selected stack
-        ItemStack selectedStack = turtle.getInventory().getStackInSlot( turtle.getSelectedSlot() );
+        ItemStack selectedStack = turtle.getInventory().getItem( turtle.getSelectedSlot() );
 
         // Get stack representing thing in front
         World world = turtle.getWorld();
         BlockPos oldPosition = turtle.getPosition();
-        BlockPos newPosition = oldPosition.offset( direction );
+        BlockPos newPosition = oldPosition.relative( direction );
 
         ItemStack lookAtStack = ItemStack.EMPTY;
-        if( !world.isAirBlock( newPosition ) )
+        if( !world.isEmptyBlock( newPosition ) )
         {
             BlockState lookAtState = world.getBlockState( newPosition );
             Block lookAtBlock = lookAtState.getBlock();
@@ -69,7 +69,7 @@ public class TurtleCompareCommand implements ITurtleCommand
                 // (try 5 times to try and beat random number generators)
                 for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ )
                 {
-                    List drops = Block.getDrops( lookAtState, (ServerWorld) world, newPosition, world.getTileEntity( newPosition ) );
+                    List drops = Block.getDrops( lookAtState, (ServerWorld) world, newPosition, world.getBlockEntity( newPosition ) );
                     if( !drops.isEmpty() )
                     {
                         for( ItemStack drop : drops )
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java
index b57e471b9..74cc04b1e 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java
@@ -26,8 +26,8 @@ public class TurtleCompareToCommand implements ITurtleCommand
     @Override
     public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
     {
-        ItemStack selectedStack = turtle.getInventory().getStackInSlot( turtle.getSelectedSlot() );
-        ItemStack stack = turtle.getInventory().getStackInSlot( m_slot );
+        ItemStack selectedStack = turtle.getInventory().getItem( turtle.getSelectedSlot() );
+        ItemStack stack = turtle.getInventory().getItem( m_slot );
         if( InventoryUtil.areItemsStackable( selectedStack, stack ) )
         {
             return TurtleCommandResult.success();
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java
index 3b1c88917..df3c79dc7 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java
@@ -34,9 +34,9 @@ public class TurtleDetectCommand implements ITurtleCommand
         // Check if thing in front is air or not
         World world = turtle.getWorld();
         BlockPos oldPosition = turtle.getPosition();
-        BlockPos newPosition = oldPosition.offset( direction );
+        BlockPos newPosition = oldPosition.relative( direction );
 
-        return !WorldUtil.isLiquidBlock( world, newPosition ) && !world.isAirBlock( newPosition )
+        return !WorldUtil.isLiquidBlock( world, newPosition ) && !world.isEmptyBlock( newPosition )
             ? TurtleCommandResult.success()
             : TurtleCommandResult.failure();
     }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java
index 747062d4c..21d5f2a4d 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java
@@ -56,7 +56,7 @@ public class TurtleDropCommand implements ITurtleCommand
         // Get inventory for thing in front
         World world = turtle.getWorld();
         BlockPos oldPosition = turtle.getPosition();
-        BlockPos newPosition = oldPosition.offset( direction );
+        BlockPos newPosition = oldPosition.relative( direction );
         Direction side = direction.getOpposite();
 
         IItemHandler inventory = InventoryUtil.getInventory( world, newPosition, side );
@@ -95,7 +95,7 @@ public class TurtleDropCommand implements ITurtleCommand
         {
             // Drop the item into the world
             WorldUtil.dropItemStack( stack, world, oldPosition, direction );
-            world.playBroadcastSound( 1000, newPosition, 0 );
+            world.globalLevelEvent( 1000, newPosition, 0 );
             turtle.playAnimation( TurtleAnimation.WAIT );
             return TurtleCommandResult.success();
         }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java
index bcb596b98..16dbc3511 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java
@@ -39,7 +39,7 @@ public class TurtleInspectCommand implements ITurtleCommand
         // Check if thing in front is air or not
         World world = turtle.getWorld();
         BlockPos oldPosition = turtle.getPosition();
-        BlockPos newPosition = oldPosition.offset( direction );
+        BlockPos newPosition = oldPosition.relative( direction );
 
         BlockState state = world.getBlockState( newPosition );
         if( state.getBlock().isAir( state, world, newPosition ) )
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java
index b7e8c879b..4f4c37585 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java
@@ -45,7 +45,7 @@ public class TurtleMoveCommand implements ITurtleCommand
         // Check if we can move
         World oldWorld = turtle.getWorld();
         BlockPos oldPosition = turtle.getPosition();
-        BlockPos newPosition = oldPosition.offset( direction );
+        BlockPos newPosition = oldPosition.relative( direction );
 
         TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction );
         TurtleCommandResult canEnterResult = canEnter( turtlePlayer, oldWorld, newPosition );
@@ -56,7 +56,7 @@ public class TurtleMoveCommand implements ITurtleCommand
 
         // Check existing block is air or replaceable
         BlockState state = oldWorld.getBlockState( newPosition );
-        if( !oldWorld.isAirBlock( newPosition ) &&
+        if( !oldWorld.isEmptyBlock( newPosition ) &&
             !WorldUtil.isLiquidBlock( oldWorld, newPosition ) &&
             !state.getMaterial().isReplaceable() )
         {
@@ -64,13 +64,13 @@ public class TurtleMoveCommand implements ITurtleCommand
         }
 
         // Check there isn't anything in the way
-        VoxelShape collision = state.getCollisionShape( oldWorld, oldPosition ).withOffset(
+        VoxelShape collision = state.getCollisionShape( oldWorld, oldPosition ).move(
             newPosition.getX(),
             newPosition.getY(),
             newPosition.getZ()
         );
 
-        if( !oldWorld.checkNoEntityCollision( null, collision ) )
+        if( !oldWorld.isUnobstructed( null, collision ) )
         {
             if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.UP || m_direction == MoveDirection.DOWN )
             {
@@ -78,15 +78,15 @@ public class TurtleMoveCommand implements ITurtleCommand
             }
 
             // Check there is space for all the pushable entities to be pushed
-            List list = oldWorld.getEntitiesWithinAABB( Entity.class, getBox( collision ), x -> x != null && x.isAlive() && x.preventEntitySpawning );
+            List list = oldWorld.getEntitiesOfClass( Entity.class, getBox( collision ), x -> x != null && x.isAlive() && x.blocksBuilding );
             for( Entity entity : list )
             {
-                AxisAlignedBB pushedBB = entity.getBoundingBox().offset(
-                    direction.getXOffset(),
-                    direction.getYOffset(),
-                    direction.getZOffset()
+                AxisAlignedBB pushedBB = entity.getBoundingBox().move(
+                    direction.getStepX(),
+                    direction.getStepY(),
+                    direction.getStepZ()
                 );
-                if( !oldWorld.checkNoEntityCollision( null, VoxelShapes.create( pushedBB ) ) )
+                if( !oldWorld.isUnobstructed( null, VoxelShapes.create( pushedBB ) ) )
                 {
                     return TurtleCommandResult.failure( "Movement obstructed" );
                 }
@@ -137,7 +137,7 @@ public class TurtleMoveCommand implements ITurtleCommand
         {
             return TurtleCommandResult.failure( position.getY() < 0 ? "Too low to move" : "Too high to move" );
         }
-        if( !World.isValid( position ) ) return TurtleCommandResult.failure( "Cannot leave the world" );
+        if( !World.isInWorldBounds( position ) ) return TurtleCommandResult.failure( "Cannot leave the world" );
 
         // Check spawn protection
         if( ComputerCraft.turtlesObeyBlockProtection && !TurtlePermissions.isBlockEnterable( world, position, turtlePlayer ) )
@@ -146,7 +146,7 @@ public class TurtleMoveCommand implements ITurtleCommand
         }
 
         if( !world.isAreaLoaded( position, 0 ) ) return TurtleCommandResult.failure( "Cannot leave loaded world" );
-        if( !world.getWorldBorder().contains( position ) )
+        if( !world.getWorldBorder().isWithinBounds( position ) )
         {
             return TurtleCommandResult.failure( "Cannot pass the world border" );
         }
@@ -156,7 +156,7 @@ public class TurtleMoveCommand implements ITurtleCommand
 
     private static AxisAlignedBB getBox( VoxelShape shape )
     {
-        return shape.isEmpty() ? EMPTY_BOX : shape.getBoundingBox();
+        return shape.isEmpty() ? EMPTY_BOX : shape.bounds();
     }
 
     private static final AxisAlignedBB EMPTY_BOX = new AxisAlignedBB( 0, 0, 0, 0, 0, 0 );
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
index a7b739f5a..cbdc4991f 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java
@@ -56,7 +56,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
     public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
     {
         // Get thing to place
-        ItemStack stack = turtle.getInventory().getStackInSlot( turtle.getSelectedSlot() );
+        ItemStack stack = turtle.getInventory().getItem( turtle.getSelectedSlot() );
         if( stack.isEmpty() )
         {
             return TurtleCommandResult.failure( "No items to place" );
@@ -64,10 +64,10 @@ public class TurtlePlaceCommand implements ITurtleCommand
 
         // Remember old block
         Direction direction = m_direction.toWorldDir( turtle );
-        BlockPos coordinates = turtle.getPosition().offset( direction );
+        BlockPos coordinates = turtle.getPosition().relative( direction );
 
         // Create a fake player, and orient it appropriately
-        BlockPos playerPosition = turtle.getPosition().offset( direction );
+        BlockPos playerPosition = turtle.getPosition().relative( direction );
         TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction );
 
         TurtleBlockEvent.Place place = new TurtleBlockEvent.Place( turtle, turtlePlayer, turtle.getWorld(), coordinates, stack );
@@ -82,8 +82,8 @@ public class TurtlePlaceCommand implements ITurtleCommand
         if( remainder != stack )
         {
             // Put the remaining items back
-            turtle.getInventory().setInventorySlotContents( turtle.getSelectedSlot(), remainder );
-            turtle.getInventory().markDirty();
+            turtle.getInventory().setItem( turtle.getSelectedSlot(), remainder );
+            turtle.getInventory().setChanged();
 
             // Animate and return success
             turtle.playAnimation( TurtleAnimation.WAIT );
@@ -109,7 +109,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
     public static ItemStack deploy( @Nonnull ItemStack stack, ITurtleAccess turtle, Direction direction, Object[] extraArguments, String[] outErrorMessage )
     {
         // Create a fake player, and orient it appropriately
-        BlockPos playerPosition = turtle.getPosition().offset( direction );
+        BlockPos playerPosition = turtle.getPosition().relative( direction );
         TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction );
 
         return deploy( stack, turtle, turtlePlayer, direction, extraArguments, outErrorMessage );
@@ -126,7 +126,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
 
         // Deploy on the block immediately in front
         BlockPos position = turtle.getPosition();
-        BlockPos newPosition = position.offset( direction );
+        BlockPos newPosition = position.relative( direction );
         remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition, direction.getOpposite(), extraArguments, true, outErrorMessage );
         if( remainder != stack )
         {
@@ -134,7 +134,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
         }
 
         // Deploy on the block one block away
-        remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.offset( direction ), direction.getOpposite(), extraArguments, false, outErrorMessage );
+        remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.relative( direction ), direction.getOpposite(), extraArguments, false, outErrorMessage );
         if( remainder != stack )
         {
             return remainder;
@@ -143,7 +143,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
         if( direction.getAxis() != Direction.Axis.Y )
         {
             // Deploy down on the block in front
-            remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.down(), Direction.UP, extraArguments, false, outErrorMessage );
+            remainder = deployOnBlock( stack, turtle, turtlePlayer, newPosition.below(), Direction.UP, extraArguments, false, outErrorMessage );
             if( remainder != stack )
             {
                 return remainder;
@@ -177,31 +177,31 @@ public class TurtlePlaceCommand implements ITurtleCommand
         // Stop intersection with the turtle itself
         if( turtle.getPosition().equals( position ) )
         {
-            posX += 0.48 * direction.getXOffset();
-            posY += 0.48 * direction.getYOffset();
-            posZ += 0.48 * direction.getZOffset();
+            posX += 0.48 * direction.getStepX();
+            posY += 0.48 * direction.getStepY();
+            posZ += 0.48 * direction.getStepZ();
         }
 
         if( direction.getAxis() != Direction.Axis.Y )
         {
-            turtlePlayer.rotationYaw = direction.getHorizontalAngle();
-            turtlePlayer.rotationPitch = 0.0f;
+            turtlePlayer.yRot = direction.toYRot();
+            turtlePlayer.xRot = 0.0f;
         }
         else
         {
-            turtlePlayer.rotationYaw = turtle.getDirection().getHorizontalAngle();
-            turtlePlayer.rotationPitch = DirectionUtil.toPitchAngle( direction );
+            turtlePlayer.yRot = turtle.getDirection().toYRot();
+            turtlePlayer.xRot = DirectionUtil.toPitchAngle( direction );
         }
 
-        turtlePlayer.setRawPosition( posX, posY, posZ );
-        turtlePlayer.prevPosX = posX;
-        turtlePlayer.prevPosY = posY;
-        turtlePlayer.prevPosZ = posZ;
-        turtlePlayer.prevRotationPitch = turtlePlayer.rotationPitch;
-        turtlePlayer.prevRotationYaw = turtlePlayer.rotationYaw;
+        turtlePlayer.setPosRaw( posX, posY, posZ );
+        turtlePlayer.xo = posX;
+        turtlePlayer.yo = posY;
+        turtlePlayer.zo = posZ;
+        turtlePlayer.xRotO = turtlePlayer.xRot;
+        turtlePlayer.yRotO = turtlePlayer.yRot;
 
-        turtlePlayer.rotationYawHead = turtlePlayer.rotationYaw;
-        turtlePlayer.prevRotationYawHead = turtlePlayer.rotationYawHead;
+        turtlePlayer.yHeadRot = turtlePlayer.yRot;
+        turtlePlayer.yHeadRotO = turtlePlayer.yHeadRot;
     }
 
     @Nonnull
@@ -210,8 +210,8 @@ public class TurtlePlaceCommand implements ITurtleCommand
         // See if there is an entity present
         final World world = turtle.getWorld();
         final BlockPos position = turtle.getPosition();
-        Vec3d turtlePos = turtlePlayer.getPositionVec();
-        Vec3d rayDir = turtlePlayer.getLook( 1.0f );
+        Vec3d turtlePos = turtlePlayer.position();
+        Vec3d rayDir = turtlePlayer.getViewVector( 1.0f );
         Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 );
         if( hit == null )
         {
@@ -235,7 +235,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
         ActionResultType cancelResult = ForgeHooks.onInteractEntityAt( turtlePlayer, hitEntity, hitPos, Hand.MAIN_HAND );
         if( cancelResult == null )
         {
-            cancelResult = hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, Hand.MAIN_HAND );
+            cancelResult = hitEntity.interactAt( turtlePlayer, hitPos, Hand.MAIN_HAND );
         }
 
         if( cancelResult == ActionResultType.SUCCESS )
@@ -252,13 +252,13 @@ public class TurtlePlaceCommand implements ITurtleCommand
             }
             else if( cancelResult == null )
             {
-                if( hitEntity.processInitialInteract( turtlePlayer, Hand.MAIN_HAND ) )
+                if( hitEntity.interact( turtlePlayer, Hand.MAIN_HAND ) )
                 {
                     placed = true;
                 }
                 else if( hitEntity instanceof LivingEntity )
                 {
-                    placed = stackCopy.interactWithEntity( turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND );
+                    placed = stackCopy.interactEnemy( turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND );
                     if( placed ) turtlePlayer.loadInventory( stackCopy );
                 }
             }
@@ -273,7 +273,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
 
         // Put everything we collected into the turtles inventory, then return
         ItemStack remainder = turtlePlayer.unloadInventory( turtle );
-        if( !placed && ItemStack.areItemStacksEqual( stack, remainder ) )
+        if( !placed && ItemStack.matches( stack, remainder ) )
         {
             return stack;
         }
@@ -290,15 +290,15 @@ public class TurtlePlaceCommand implements ITurtleCommand
     private static boolean canDeployOnBlock( @Nonnull BlockItemUseContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, Direction side, boolean allowReplaceable, String[] outErrorMessage )
     {
         World world = turtle.getWorld();
-        if( !World.isValid( position ) || world.isAirBlock( position ) ||
-            (context.getItem().getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) )
+        if( !World.isInWorldBounds( position ) || world.isEmptyBlock( position ) ||
+            (context.getItemInHand().getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) )
         {
             return false;
         }
 
         BlockState state = world.getBlockState( position );
 
-        boolean replaceable = state.isReplaceable( context );
+        boolean replaceable = state.canBeReplaced( context );
         if( !allowReplaceable && replaceable ) return false;
 
         if( ComputerCraft.turtlesObeyBlockProtection )
@@ -306,7 +306,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
             // Check spawn protection
             boolean editable = replaceable
                 ? TurtlePermissions.isBlockEditable( world, position, player )
-                : TurtlePermissions.isBlockEditable( world, position.offset( side ), player );
+                : TurtlePermissions.isBlockEditable( world, position.relative( side ), player );
             if( !editable )
             {
                 if( outErrorMessage != null ) outErrorMessage[0] = "Cannot place in protected area";
@@ -322,16 +322,16 @@ public class TurtlePlaceCommand implements ITurtleCommand
     {
         // Re-orient the fake player
         Direction playerDir = side.getOpposite();
-        BlockPos playerPosition = position.offset( side );
+        BlockPos playerPosition = position.relative( side );
         orientPlayer( turtle, turtlePlayer, playerPosition, playerDir );
 
         ItemStack stackCopy = stack.copy();
         turtlePlayer.loadInventory( stackCopy );
 
         // Calculate where the turtle would hit the block
-        float hitX = 0.5f + side.getXOffset() * 0.5f;
-        float hitY = 0.5f + side.getYOffset() * 0.5f;
-        float hitZ = 0.5f + side.getZOffset() * 0.5f;
+        float hitX = 0.5f + side.getStepX() * 0.5f;
+        float hitY = 0.5f + side.getStepY() * 0.5f;
+        float hitZ = 0.5f + side.getStepZ() * 0.5f;
         if( Math.abs( hitY - 0.5f ) < 0.01f )
         {
             hitY = 0.45f;
@@ -350,7 +350,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
 
         // Do the deploying (put everything in the players inventory)
         boolean placed = false;
-        TileEntity existingTile = turtle.getWorld().getTileEntity( position );
+        TileEntity existingTile = turtle.getWorld().getBlockEntity( position );
 
         // See PlayerInteractionManager.processRightClickBlock
         // TODO: ^ Check we're still consistent.
@@ -363,7 +363,7 @@ public class TurtlePlaceCommand implements ITurtleCommand
                 turtlePlayer.loadInventory( stackCopy );
             }
             else if( event.getUseItem() != Event.Result.DENY &&
-                stackCopy.onItemUse( context ) == ActionResultType.SUCCESS )
+                stackCopy.useOn( context ) == ActionResultType.SUCCESS )
             {
                 placed = true;
                 turtlePlayer.loadInventory( stackCopy );
@@ -379,11 +379,11 @@ public class TurtlePlaceCommand implements ITurtleCommand
             }
             else if( actionResult == null )
             {
-                ActionResult result = stackCopy.useItemRightClick( turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND );
-                if( result.getType() == ActionResultType.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) )
+                ActionResult result = stackCopy.use( turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND );
+                if( result.getResult() == ActionResultType.SUCCESS && !ItemStack.matches( stack, result.getObject() ) )
                 {
                     placed = true;
-                    turtlePlayer.loadInventory( result.getResult() );
+                    turtlePlayer.loadInventory( result.getObject() );
                 }
             }
         }
@@ -394,10 +394,10 @@ public class TurtlePlaceCommand implements ITurtleCommand
             if( extraArguments != null && extraArguments.length >= 1 && extraArguments[0] instanceof String )
             {
                 World world = turtle.getWorld();
-                TileEntity tile = world.getTileEntity( position );
+                TileEntity tile = world.getBlockEntity( position );
                 if( tile == null || tile == existingTile )
                 {
-                    tile = world.getTileEntity( position.offset( side ) );
+                    tile = world.getBlockEntity( position.relative( side ) );
                 }
                 if( tile instanceof SignTileEntity )
                 {
@@ -405,33 +405,33 @@ public class TurtlePlaceCommand implements ITurtleCommand
                     String s = (String) extraArguments[0];
                     String[] split = s.split( "\n" );
                     int firstLine = split.length <= 2 ? 1 : 0;
-                    for( int i = 0; i < signTile.signText.length; i++ )
+                    for( int i = 0; i < signTile.messages.length; i++ )
                     {
                         if( i >= firstLine && i < firstLine + split.length )
                         {
                             if( split[i - firstLine].length() > 15 )
                             {
-                                signTile.signText[i] = new StringTextComponent( split[i - firstLine].substring( 0, 15 ) );
+                                signTile.messages[i] = new StringTextComponent( split[i - firstLine].substring( 0, 15 ) );
                             }
                             else
                             {
-                                signTile.signText[i] = new StringTextComponent( split[i - firstLine] );
+                                signTile.messages[i] = new StringTextComponent( split[i - firstLine] );
                             }
                         }
                         else
                         {
-                            signTile.signText[i] = new StringTextComponent( "" );
+                            signTile.messages[i] = new StringTextComponent( "" );
                         }
                     }
-                    signTile.markDirty();
-                    world.notifyBlockUpdate( tile.getPos(), tile.getBlockState(), tile.getBlockState(), 3 );
+                    signTile.setChanged();
+                    world.sendBlockUpdated( tile.getBlockPos(), tile.getBlockState(), tile.getBlockState(), 3 );
                 }
             }
         }
 
         // Put everything we collected into the turtles inventory, then return
         ItemStack remainder = turtlePlayer.unloadInventory( turtle );
-        if( !placed && ItemStack.areItemStacksEqual( stack, remainder ) )
+        if( !placed && ItemStack.matches( stack, remainder ) )
         {
             return stack;
         }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java
index 270b25183..5da920cf8 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java
@@ -61,7 +61,7 @@ public final class TurtlePlayer extends FakePlayer
             // Constructing a player overrides the "active player" variable in advancements. As fake players cannot
             // get advancements, this prevents a normal player who has placed a turtle from getting advancements.
             // We try to locate the "actual" player and restore them.
-            ServerPlayerEntity actualPlayer = world.getServer().getPlayerList().getPlayerByUUID( profile.getId() );
+            ServerPlayerEntity actualPlayer = world.getServer().getPlayerList().getPlayer( profile.getId() );
             if( actualPlayer != null ) player.getAdvancements().setPlayer( actualPlayer );
         }
 
@@ -75,19 +75,19 @@ public final class TurtlePlayer extends FakePlayer
 
     private void setState( ITurtleAccess turtle )
     {
-        if( openContainer != container )
+        if( containerMenu != inventoryMenu )
         {
-            ComputerCraft.log.warn( "Turtle has open container ({})", openContainer );
-            closeContainer();
+            ComputerCraft.log.warn( "Turtle has open container ({})", containerMenu );
+            doCloseContainer();
         }
 
         BlockPos position = turtle.getPosition();
-        setRawPosition( position.getX() + 0.5, position.getY() + 0.5, position.getZ() + 0.5 );
+        setPosRaw( position.getX() + 0.5, position.getY() + 0.5, position.getZ() + 0.5 );
 
-        rotationYaw = turtle.getDirection().getHorizontalAngle();
-        rotationPitch = 0.0f;
+        yRot = turtle.getDirection().toYRot();
+        xRot = 0.0f;
 
-        inventory.clear();
+        inventory.clearContent();
     }
 
     public static TurtlePlayer get( ITurtleAccess access )
@@ -97,7 +97,7 @@ public final class TurtlePlayer extends FakePlayer
         TurtleBrain brain = (TurtleBrain) access;
         TurtlePlayer player = brain.m_cachedPlayer;
         if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() )
-            || player.getEntityWorld() != access.getWorld() )
+            || player.getCommandSenderWorld() != access.getWorld() )
         {
             player = brain.m_cachedPlayer = create( brain );
         }
@@ -112,22 +112,22 @@ public final class TurtlePlayer extends FakePlayer
     public void loadInventory( @Nonnull ItemStack currentStack )
     {
         // Load up the fake inventory
-        inventory.currentItem = 0;
-        inventory.setInventorySlotContents( 0, currentStack );
+        inventory.selected = 0;
+        inventory.setItem( 0, currentStack );
     }
 
     public ItemStack unloadInventory( ITurtleAccess turtle )
     {
         // Get the item we placed with
-        ItemStack results = inventory.getStackInSlot( 0 );
-        inventory.setInventorySlotContents( 0, ItemStack.EMPTY );
+        ItemStack results = inventory.getItem( 0 );
+        inventory.setItem( 0, ItemStack.EMPTY );
 
         // Store (or drop) anything else we found
         BlockPos dropPosition = turtle.getPosition();
         Direction dropDirection = turtle.getDirection().getOpposite();
-        for( int i = 0; i < inventory.getSizeInventory(); i++ )
+        for( int i = 0; i < inventory.getContainerSize(); i++ )
         {
-            ItemStack stack = inventory.getStackInSlot( i );
+            ItemStack stack = inventory.getItem( i );
             if( !stack.isEmpty() )
             {
                 ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() );
@@ -135,10 +135,10 @@ public final class TurtlePlayer extends FakePlayer
                 {
                     WorldUtil.dropItemStack( remainder, turtle.getWorld(), dropPosition, dropDirection );
                 }
-                inventory.setInventorySlotContents( i, ItemStack.EMPTY );
+                inventory.setItem( i, ItemStack.EMPTY );
             }
         }
-        inventory.markDirty();
+        inventory.setChanged();
         return results;
     }
 
@@ -150,9 +150,9 @@ public final class TurtlePlayer extends FakePlayer
     }
 
     @Override
-    public Vec3d getPositionVector()
+    public Vec3d getCommandSenderWorldPosition()
     {
-        return getPositionVec();
+        return position();
     }
 
     @Override
@@ -170,18 +170,18 @@ public final class TurtlePlayer extends FakePlayer
     //region Code which depends on the connection
     @Nonnull
     @Override
-    public OptionalInt openContainer( @Nullable INamedContainerProvider prover )
+    public OptionalInt openMenu( @Nullable INamedContainerProvider prover )
     {
         return OptionalInt.empty();
     }
 
     @Override
-    public void sendEnterCombat()
+    public void onEnterCombat()
     {
     }
 
     @Override
-    public void sendEndCombat()
+    public void onLeaveCombat()
     {
     }
 
@@ -197,7 +197,7 @@ public final class TurtlePlayer extends FakePlayer
     }
 
     @Override
-    public void openSignEditor( @Nonnull SignTileEntity signTile )
+    public void openTextEdit( @Nonnull SignTileEntity signTile )
     {
     }
 
@@ -207,32 +207,32 @@ public final class TurtlePlayer extends FakePlayer
     }
 
     @Override
-    public void openBook( @Nonnull ItemStack stack, @Nonnull Hand hand )
+    public void openItemGui( @Nonnull ItemStack stack, @Nonnull Hand hand )
     {
     }
 
     @Override
-    public void closeScreen()
+    public void closeContainer()
     {
     }
 
     @Override
-    public void updateHeldItem()
+    public void broadcastCarriedItem()
     {
     }
 
     @Override
-    protected void onNewPotionEffect( @Nonnull EffectInstance id )
+    protected void onEffectAdded( @Nonnull EffectInstance id )
     {
     }
 
     @Override
-    protected void onChangedPotionEffect( @Nonnull EffectInstance id, boolean apply )
+    protected void onEffectUpdated( @Nonnull EffectInstance id, boolean apply )
     {
     }
 
     @Override
-    protected void onFinishedPotionEffect( @Nonnull EffectInstance effect )
+    protected void onEffectRemoved( @Nonnull EffectInstance effect )
     {
     }
     //endregion
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java
index 58a789979..fdee852cb 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java
@@ -29,7 +29,7 @@ public class TurtleRefuelCommand implements ITurtleCommand
     public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle )
     {
         int slot = turtle.getSelectedSlot();
-        ItemStack stack = turtle.getInventory().getStackInSlot( slot );
+        ItemStack stack = turtle.getInventory().getItem( slot );
         if( stack.isEmpty() ) return TurtleCommandResult.failure( "No items to combust" );
 
         TurtleRefuelEvent event = new TurtleRefuelEvent( turtle, stack );
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java
index 8ca4b8b26..776394792 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java
@@ -52,7 +52,7 @@ public class TurtleSuckCommand implements ITurtleCommand
         // Get inventory for thing in front
         World world = turtle.getWorld();
         BlockPos turtlePosition = turtle.getPosition();
-        BlockPos blockPosition = turtlePosition.offset( direction );
+        BlockPos blockPosition = turtlePosition.relative( direction );
         Direction side = direction.getOpposite();
 
         IItemHandler inventory = InventoryUtil.getInventory( world, blockPosition, side );
@@ -97,7 +97,7 @@ public class TurtleSuckCommand implements ITurtleCommand
                 blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(),
                 blockPosition.getX() + 1.0, blockPosition.getY() + 1.0, blockPosition.getZ() + 1.0
             );
-            List list = world.getEntitiesWithinAABB( ItemEntity.class, aabb, EntityPredicates.IS_ALIVE );
+            List list = world.getEntitiesOfClass( ItemEntity.class, aabb, EntityPredicates.ENTITY_STILL_ALIVE );
             if( list.isEmpty() ) return TurtleCommandResult.failure( "No items to take" );
 
             for( ItemEntity entity : list )
@@ -141,7 +141,7 @@ public class TurtleSuckCommand implements ITurtleCommand
                     }
 
                     // Play fx
-                    world.playBroadcastSound( 1000, turtlePosition, 0 ); // BLOCK_DISPENSER_DISPENSE
+                    world.globalLevelEvent( 1000, turtlePosition, 0 ); // BLOCK_DISPENSER_DISPENSE
                     turtle.playAnimation( TurtleAnimation.WAIT );
                     return TurtleCommandResult.success();
                 }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java
index 05fc7978c..63a3375b2 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java
@@ -38,13 +38,13 @@ public class TurtleTurnCommand implements ITurtleCommand
         {
             case LEFT:
             {
-                turtle.setDirection( turtle.getDirection().rotateYCCW() );
+                turtle.setDirection( turtle.getDirection().getCounterClockWise() );
                 turtle.playAnimation( TurtleAnimation.TURN_LEFT );
                 return TurtleCommandResult.success();
             }
             case RIGHT:
             {
-                turtle.setDirection( turtle.getDirection().rotateY() );
+                turtle.setDirection( turtle.getDirection().getClockWise() );
                 turtle.playAnimation( TurtleAnimation.TURN_RIGHT );
                 return TurtleCommandResult.success();
             }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java
index c02a6e933..c11357614 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java
@@ -40,7 +40,7 @@ public class ContainerTurtle extends ContainerComputerBase
         super( Registry.ModContainers.TURTLE.get(), id, canUse, computer, family );
         this.properties = properties;
 
-        trackIntArray( properties );
+        addDataSlots( properties );
 
         // Turtle inventory
         for( int y = 0; y < 4; y++ )
@@ -70,7 +70,7 @@ public class ContainerTurtle extends ContainerComputerBase
     public ContainerTurtle( int id, PlayerInventory player, TurtleBrain turtle )
     {
         this(
-            id, p -> turtle.getOwner().isUsableByPlayer( p ), turtle.getOwner().createServerComputer(), turtle.getFamily(),
+            id, p -> turtle.getOwner().stillValid( p ), turtle.getOwner().createServerComputer(), turtle.getFamily(),
             player, turtle.getInventory(), (SingleIntArray) turtle::getSelectedSlot
         );
     }
@@ -91,24 +91,24 @@ public class ContainerTurtle extends ContainerComputerBase
     @Nonnull
     private ItemStack tryItemMerge( PlayerEntity player, int slotNum, int firstSlot, int lastSlot, boolean reverse )
     {
-        Slot slot = inventorySlots.get( slotNum );
+        Slot slot = slots.get( slotNum );
         ItemStack originalStack = ItemStack.EMPTY;
-        if( slot != null && slot.getHasStack() )
+        if( slot != null && slot.hasItem() )
         {
-            ItemStack clickedStack = slot.getStack();
+            ItemStack clickedStack = slot.getItem();
             originalStack = clickedStack.copy();
-            if( !mergeItemStack( clickedStack, firstSlot, lastSlot, reverse ) )
+            if( !moveItemStackTo( clickedStack, firstSlot, lastSlot, reverse ) )
             {
                 return ItemStack.EMPTY;
             }
 
             if( clickedStack.isEmpty() )
             {
-                slot.putStack( ItemStack.EMPTY );
+                slot.set( ItemStack.EMPTY );
             }
             else
             {
-                slot.onSlotChanged();
+                slot.setChanged();
             }
 
             if( clickedStack.getCount() != originalStack.getCount() )
@@ -125,7 +125,7 @@ public class ContainerTurtle extends ContainerComputerBase
 
     @Nonnull
     @Override
-    public ItemStack transferStackInSlot( @Nonnull PlayerEntity player, int slotNum )
+    public ItemStack quickMoveStack( @Nonnull PlayerEntity player, int slotNum )
     {
         if( slotNum >= 0 && slotNum < 16 )
         {
diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java
index f849357e5..331f8e28f 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java
@@ -27,6 +27,8 @@ import javax.annotation.Nullable;
 
 import static dan200.computercraft.shared.turtle.core.TurtleBrain.*;
 
+import net.minecraft.item.Item.Properties;
+
 public class ItemTurtle extends ItemComputerBase implements ITurtleItem
 {
     public ItemTurtle( BlockTurtle block, Properties settings )
@@ -38,7 +40,7 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem
     {
         // Build the stack
         ItemStack stack = new ItemStack( this );
-        if( label != null ) stack.setDisplayName( new StringTextComponent( label ) );
+        if( label != null ) stack.setHoverName( new StringTextComponent( label ) );
         if( id >= 0 ) stack.getOrCreateTag().putInt( NBT_ID, id );
         IColouredItem.setColourBasic( stack, colour );
         if( fuelLevel > 0 ) stack.getOrCreateTag().putInt( NBT_FUEL, fuelLevel );
@@ -58,9 +60,9 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem
     }
 
     @Override
-    public void fillItemGroup( @Nonnull ItemGroup group, @Nonnull NonNullList list )
+    public void fillItemCategory( @Nonnull ItemGroup group, @Nonnull NonNullList list )
     {
-        if( !isInGroup( group ) ) return;
+        if( !allowdedIn( group ) ) return;
 
         ComputerFamily family = getFamily();
 
@@ -73,9 +75,9 @@ public class ItemTurtle extends ItemComputerBase implements ITurtleItem
 
     @Nonnull
     @Override
-    public ITextComponent getDisplayName( @Nonnull ItemStack stack )
+    public ITextComponent getName( @Nonnull ItemStack stack )
     {
-        String baseString = getTranslationKey( stack );
+        String baseString = getDescriptionId( stack );
         ITurtleUpgrade left = getUpgrade( stack, TurtleSide.LEFT );
         ITurtleUpgrade right = getUpgrade( stack, TurtleSide.RIGHT );
         if( left != null && right != null )
diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java
index 05e598bac..af2dbe8bc 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java
@@ -17,6 +17,8 @@ import net.minecraft.util.ResourceLocation;
 
 import javax.annotation.Nonnull;
 
+import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe.Serializer;
+
 public final class TurtleRecipe extends ComputerFamilyRecipe
 {
     private TurtleRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family )
diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java
index 6240ad6a8..5c76773b2 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java
@@ -29,14 +29,14 @@ public final class TurtleUpgradeRecipe extends SpecialRecipe
     }
 
     @Override
-    public boolean canFit( int x, int y )
+    public boolean canCraftInDimensions( int x, int y )
     {
         return x >= 3 && y >= 1;
     }
 
     @Nonnull
     @Override
-    public ItemStack getRecipeOutput()
+    public ItemStack getResultItem()
     {
         return TurtleItemFactory.create( -1, null, -1, ComputerFamily.NORMAL, null, null, 0, null );
     }
@@ -44,12 +44,12 @@ public final class TurtleUpgradeRecipe extends SpecialRecipe
     @Override
     public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world )
     {
-        return !getCraftingResult( inventory ).isEmpty();
+        return !assemble( inventory ).isEmpty();
     }
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory )
+    public ItemStack assemble( @Nonnull CraftingInventory inventory )
     {
         // Scan the grid for a row containing a turtle and 1 or 2 items
         ItemStack leftItem = ItemStack.EMPTY;
@@ -64,7 +64,7 @@ public final class TurtleUpgradeRecipe extends SpecialRecipe
                 boolean finishedRow = false;
                 for( int x = 0; x < inventory.getWidth(); x++ )
                 {
-                    ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() );
+                    ItemStack item = inventory.getItem( x + y * inventory.getWidth() );
                     if( !item.isEmpty() )
                     {
                         if( finishedRow )
@@ -122,7 +122,7 @@ public final class TurtleUpgradeRecipe extends SpecialRecipe
                 // Turtle is already found, just check this row is empty
                 for( int x = 0; x < inventory.getWidth(); x++ )
                 {
-                    ItemStack item = inventory.getStackInSlot( x + y * inventory.getWidth() );
+                    ItemStack item = inventory.getItem( x + y * inventory.getWidth() );
                     if( !item.isEmpty() )
                     {
                         return ItemStack.EMPTY;
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java
index 903d6677c..044416527 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleHoe.java
@@ -45,12 +45,12 @@ public class TurtleHoe extends TurtleTool
         if( !super.canBreakBlock( state, world, pos, player ) ) return false;
 
         Material material = state.getMaterial();
-        return material == Material.PLANTS ||
+        return material == Material.PLANT ||
             material == Material.CACTUS ||
-            material == Material.GOURD ||
+            material == Material.VEGETABLE ||
             material == Material.LEAVES ||
-            material == Material.OCEAN_PLANT ||
-            material == Material.TALL_PLANTS;
+            material == Material.WATER_PLANT ||
+            material == Material.REPLACEABLE_PLANT;
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java
index 42b063470..bba1393c9 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java
@@ -56,7 +56,7 @@ public class TurtleInventoryCrafting extends CraftingInventory
                 if( x < m_xStart || x >= m_xStart + 3 ||
                     y < m_yStart || y >= m_yStart + 3 )
                 {
-                    if( !m_turtle.getInventory().getStackInSlot( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() )
+                    if( !m_turtle.getInventory().getItem( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() )
                     {
                         return null;
                     }
@@ -65,13 +65,13 @@ public class TurtleInventoryCrafting extends CraftingInventory
         }
 
         // Check the actual crafting
-        return m_turtle.getWorld().getRecipeManager().getRecipe( IRecipeType.CRAFTING, this, m_turtle.getWorld() ).orElse( null );
+        return m_turtle.getWorld().getRecipeManager().getRecipeFor( IRecipeType.CRAFTING, this, m_turtle.getWorld() ).orElse( null );
     }
 
     @Nullable
     public List doCrafting( World world, int maxCount )
     {
-        if( world.isRemote || !(world instanceof ServerWorld) ) return null;
+        if( world.isClientSide || !(world instanceof ServerWorld) ) return null;
 
         // Find out what we can craft
         IRecipe recipe = tryCrafting( 0, 0 );
@@ -88,11 +88,11 @@ public class TurtleInventoryCrafting extends CraftingInventory
         ArrayList results = new ArrayList<>();
         for( int i = 0; i < maxCount && recipe.matches( this, world ); i++ )
         {
-            ItemStack result = recipe.getCraftingResult( this );
+            ItemStack result = recipe.assemble( this );
             if( result.isEmpty() ) break;
             results.add( result );
 
-            result.onCrafting( world, player, result.getCount() );
+            result.onCraftedBy( world, player, result.getCount() );
             BasicEventHooks.firePlayerCraftingEvent( player, result, this );
 
             ForgeHooks.setCraftingPlayer( player );
@@ -101,13 +101,13 @@ public class TurtleInventoryCrafting extends CraftingInventory
 
             for( int slot = 0; slot < remainders.size(); slot++ )
             {
-                ItemStack existing = getStackInSlot( slot );
+                ItemStack existing = getItem( slot );
                 ItemStack remainder = remainders.get( slot );
 
                 if( !existing.isEmpty() )
                 {
-                    decrStackSize( slot, 1 );
-                    existing = getStackInSlot( slot );
+                    removeItem( slot, 1 );
+                    existing = getItem( slot );
                 }
 
                 if( remainder.isEmpty() ) continue;
@@ -116,12 +116,12 @@ public class TurtleInventoryCrafting extends CraftingInventory
                 // afterwards).
                 if( existing.isEmpty() )
                 {
-                    setInventorySlotContents( slot, remainder );
+                    setItem( slot, remainder );
                 }
-                else if( ItemStack.areItemsEqual( existing, remainder ) && ItemStack.areItemStackTagsEqual( existing, remainder ) )
+                else if( ItemStack.isSame( existing, remainder ) && ItemStack.tagMatches( existing, remainder ) )
                 {
                     remainder.grow( existing.getCount() );
-                    setInventorySlotContents( slot, remainder );
+                    setItem( slot, remainder );
                 }
                 else
                 {
@@ -157,74 +157,74 @@ public class TurtleInventoryCrafting extends CraftingInventory
     // IInventory implementation
 
     @Override
-    public int getSizeInventory()
+    public int getContainerSize()
     {
         return getWidth() * getHeight();
     }
 
     @Nonnull
     @Override
-    public ItemStack getStackInSlot( int i )
+    public ItemStack getItem( int i )
     {
         i = modifyIndex( i );
-        return m_turtle.getInventory().getStackInSlot( i );
+        return m_turtle.getInventory().getItem( i );
     }
 
     @Nonnull
     @Override
-    public ItemStack removeStackFromSlot( int i )
+    public ItemStack removeItemNoUpdate( int i )
     {
         i = modifyIndex( i );
-        return m_turtle.getInventory().removeStackFromSlot( i );
+        return m_turtle.getInventory().removeItemNoUpdate( i );
     }
 
     @Nonnull
     @Override
-    public ItemStack decrStackSize( int i, int size )
+    public ItemStack removeItem( int i, int size )
     {
         i = modifyIndex( i );
-        return m_turtle.getInventory().decrStackSize( i, size );
+        return m_turtle.getInventory().removeItem( i, size );
     }
 
     @Override
-    public void setInventorySlotContents( int i, @Nonnull ItemStack stack )
+    public void setItem( int i, @Nonnull ItemStack stack )
     {
         i = modifyIndex( i );
-        m_turtle.getInventory().setInventorySlotContents( i, stack );
+        m_turtle.getInventory().setItem( i, stack );
     }
 
     @Override
-    public int getInventoryStackLimit()
+    public int getMaxStackSize()
     {
-        return m_turtle.getInventory().getInventoryStackLimit();
+        return m_turtle.getInventory().getMaxStackSize();
     }
 
     @Override
-    public void markDirty()
+    public void setChanged()
     {
-        m_turtle.getInventory().markDirty();
+        m_turtle.getInventory().setChanged();
     }
 
     @Override
-    public boolean isUsableByPlayer( @Nonnull PlayerEntity player )
+    public boolean stillValid( @Nonnull PlayerEntity player )
     {
         return true;
     }
 
     @Override
-    public boolean isItemValidForSlot( int i, @Nonnull ItemStack stack )
+    public boolean canPlaceItem( int i, @Nonnull ItemStack stack )
     {
         i = modifyIndex( i );
-        return m_turtle.getInventory().isItemValidForSlot( i, stack );
+        return m_turtle.getInventory().canPlaceItem( i, stack );
     }
 
     @Override
-    public void clear()
+    public void clearContent()
     {
-        for( int i = 0; i < getSizeInventory(); i++ )
+        for( int i = 0; i < getContainerSize(); i++ )
         {
             int j = modifyIndex( i );
-            m_turtle.getInventory().setInventorySlotContents( j, ItemStack.EMPTY );
+            m_turtle.getInventory().setItem( j, ItemStack.EMPTY );
         }
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java
index 4e5f97785..4fe11b97b 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java
@@ -144,7 +144,7 @@ public class TurtleModem extends AbstractTurtleUpgrade
     public void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side )
     {
         // Advance the modem
-        if( !turtle.getWorld().isRemote )
+        if( !turtle.getWorld().isClientSide )
         {
             IPeripheral peripheral = turtle.getPeripheral( side );
             if( peripheral instanceof Peripheral )
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java
index cbec04c14..3981ad12d 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleShovel.java
@@ -45,16 +45,16 @@ public class TurtleShovel extends TurtleTool
         if( !super.canBreakBlock( state, world, pos, player ) ) return false;
 
         Material material = state.getMaterial();
-        return material == Material.EARTH ||
+        return material == Material.DIRT ||
             material == Material.SAND ||
-            material == Material.SNOW ||
+            material == Material.TOP_SNOW ||
             material == Material.CLAY ||
-            material == Material.SNOW_BLOCK ||
-            material == Material.PLANTS ||
+            material == Material.SNOW ||
+            material == Material.PLANT ||
             material == Material.CACTUS ||
-            material == Material.GOURD ||
+            material == Material.VEGETABLE ||
             material == Material.LEAVES ||
-            material == Material.TALL_PLANTS;
+            material == Material.REPLACEABLE_PLANT;
     }
 
     @Nonnull
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java
index 425208eb9..e1cb4f552 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSword.java
@@ -37,9 +37,9 @@ public class TurtleSword extends TurtleTool
         if( !super.canBreakBlock( state, world, pos, player ) ) return false;
 
         Material material = state.getMaterial();
-        return material == Material.PLANTS ||
+        return material == Material.PLANT ||
             material == Material.LEAVES ||
-            material == Material.TALL_PLANTS ||
+            material == Material.REPLACEABLE_PLANT ||
             material == Material.WOOL ||
             material == Material.WEB;
     }
diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
index 96c619a3d..3f6a02ebe 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java
@@ -78,7 +78,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
 
         // Check we've not got anything vaguely interesting on the item. We allow other mods to add their
         // own NBT, with the understanding such details will be lost to the mist of time.
-        if( stack.isDamaged() || stack.isEnchanted() || stack.hasDisplayName() ) return false;
+        if( stack.isDamaged() || stack.isEnchanted() || stack.hasCustomHoverName() ) return false;
         if( tag.contains( "AttributeModifiers", Constants.NBT.TAG_LIST ) &&
             !tag.getList( "AttributeModifiers", Constants.NBT.TAG_COMPOUND ).isEmpty() )
         {
@@ -123,7 +123,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
         Block block = state.getBlock();
         return !state.isAir( world, pos )
             && block != Blocks.BEDROCK
-            && state.getPlayerRelativeBlockHardness( player, world, pos ) > 0
+            && state.getDestroyProgress( player, world, pos ) > 0
             && block.canEntityDestroy( state, world, pos, player );
     }
 
@@ -137,14 +137,14 @@ public class TurtleTool extends AbstractTurtleUpgrade
         // Create a fake player, and orient it appropriately
         World world = turtle.getWorld();
         BlockPos position = turtle.getPosition();
-        TileEntity turtleTile = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getTileEntity( position );
+        TileEntity turtleTile = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( position );
         if( turtleTile == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." );
 
         final TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction );
 
         // See if there is an entity present
-        Vec3d turtlePos = turtlePlayer.getPositionVec();
-        Vec3d rayDir = turtlePlayer.getLook( 1.0f );
+        Vec3d turtlePos = turtlePlayer.position();
+        Vec3d rayDir = turtlePlayer.getViewVector( 1.0f );
         Pair hit = WorldUtil.rayTraceEntities( world, turtlePos, rayDir, 1.5 );
         if( hit != null )
         {
@@ -155,7 +155,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
             Entity hitEntity = hit.getKey();
 
             // Fire several events to ensure we have permissions.
-            if( MinecraftForge.EVENT_BUS.post( new AttackEntityEvent( turtlePlayer, hitEntity ) ) || !hitEntity.canBeAttackedWithItem() )
+            if( MinecraftForge.EVENT_BUS.post( new AttackEntityEvent( turtlePlayer, hitEntity ) ) || !hitEntity.isAttackable() )
             {
                 return TurtleCommandResult.failure( "Nothing to attack here" );
             }
@@ -171,26 +171,26 @@ public class TurtleTool extends AbstractTurtleUpgrade
 
             // Attack the entity
             boolean attacked = false;
-            if( !hitEntity.hitByEntity( turtlePlayer ) )
+            if( !hitEntity.skipAttackInteraction( turtlePlayer ) )
             {
                 float damage = (float) turtlePlayer.getAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getValue();
                 damage *= getDamageMultiplier();
                 if( damage > 0.0f )
                 {
-                    DamageSource source = DamageSource.causePlayerDamage( turtlePlayer );
+                    DamageSource source = DamageSource.playerAttack( turtlePlayer );
                     if( hitEntity instanceof ArmorStandEntity )
                     {
                         // Special case for armor stands: attack twice to guarantee destroy
-                        hitEntity.attackEntityFrom( source, damage );
+                        hitEntity.hurt( source, damage );
                         if( hitEntity.isAlive() )
                         {
-                            hitEntity.attackEntityFrom( source, damage );
+                            hitEntity.hurt( source, damage );
                         }
                         attacked = true;
                     }
                     else
                     {
-                        if( hitEntity.attackEntityFrom( source, damage ) )
+                        if( hitEntity.hurt( source, damage ) )
                         {
                             attacked = true;
                         }
@@ -217,11 +217,11 @@ public class TurtleTool extends AbstractTurtleUpgrade
         // Get ready to dig
         World world = turtle.getWorld();
         BlockPos turtlePosition = turtle.getPosition();
-        TileEntity turtleTile = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getTileEntity( turtlePosition );
+        TileEntity turtleTile = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( turtlePosition );
         if( turtleTile == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." );
 
-        BlockPos blockPosition = turtlePosition.offset( direction );
-        if( world.isAirBlock( blockPosition ) || WorldUtil.isLiquidBlock( world, blockPosition ) )
+        BlockPos blockPosition = turtlePosition.relative( direction );
+        if( world.isEmptyBlock( blockPosition ) || WorldUtil.isLiquidBlock( world, blockPosition ) )
         {
             return TurtleCommandResult.failure( "Nothing to dig here" );
         }
@@ -262,21 +262,21 @@ public class TurtleTool extends AbstractTurtleUpgrade
         // Consume the items the block drops
         DropConsumer.set( world, blockPosition, turtleDropConsumer( turtleTile, turtle ) );
 
-        TileEntity tile = world.getTileEntity( blockPosition );
+        TileEntity tile = world.getBlockEntity( blockPosition );
 
         // Much of this logic comes from PlayerInteractionManager#tryHarvestBlock, so it's a good idea
         // to consult there before making any changes.
 
         // Play the destruction sound and particles
-        world.playEvent( 2001, blockPosition, Block.getStateId( state ) );
+        world.levelEvent( 2001, blockPosition, Block.getId( state ) );
 
         // Destroy the block
         boolean canHarvest = state.canHarvestBlock( world, blockPosition, turtlePlayer );
         boolean canBreak = state.removedByPlayer( world, blockPosition, turtlePlayer, canHarvest, fluidState );
-        if( canBreak ) state.getBlock().onPlayerDestroy( world, blockPosition, state );
+        if( canBreak ) state.getBlock().destroy( world, blockPosition, state );
         if( canHarvest && canBreak )
         {
-            state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() );
+            state.getBlock().playerDestroy( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getMainHandItem() );
         }
 
         stopConsuming( turtleTile, turtle );
diff --git a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java
index 955d52bac..d446d5782 100644
--- a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java
+++ b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java
@@ -24,7 +24,7 @@ public class CreativeTabMain extends ItemGroup
     @Nonnull
     @Override
     @OnlyIn( Dist.CLIENT )
-    public ItemStack createIcon()
+    public ItemStack makeIcon()
     {
         return new ItemStack( Registry.ModBlocks.COMPUTER_NORMAL.get() );
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java
index d23ebfcfb..849cbfc81 100644
--- a/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java
+++ b/src/main/java/dan200/computercraft/shared/util/DefaultInventory.java
@@ -14,23 +14,23 @@ import javax.annotation.Nonnull;
 public interface DefaultInventory extends IInventory
 {
     @Override
-    default int getInventoryStackLimit()
+    default int getMaxStackSize()
     {
         return 64;
     }
 
     @Override
-    default void openInventory( @Nonnull PlayerEntity player )
+    default void startOpen( @Nonnull PlayerEntity player )
     {
     }
 
     @Override
-    default void closeInventory( @Nonnull PlayerEntity player )
+    default void stopOpen( @Nonnull PlayerEntity player )
     {
     }
 
     @Override
-    default boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack )
+    default boolean canPlaceItem( int slot, @Nonnull ItemStack stack )
     {
         return true;
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java
index 92f13dea9..82588557b 100644
--- a/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java
+++ b/src/main/java/dan200/computercraft/shared/util/DefaultSidedInventory.java
@@ -15,13 +15,13 @@ import javax.annotation.Nullable;
 public interface DefaultSidedInventory extends DefaultInventory, ISidedInventory
 {
     @Override
-    default boolean canInsertItem( int slot, @Nonnull ItemStack stack, @Nullable Direction side )
+    default boolean canPlaceItemThroughFace( int slot, @Nonnull ItemStack stack, @Nullable Direction side )
     {
-        return isItemValidForSlot( slot, stack );
+        return canPlaceItem( slot, stack );
     }
 
     @Override
-    default boolean canExtractItem( int slot, @Nonnull ItemStack stack, @Nonnull Direction side )
+    default boolean canTakeItemThroughFace( int slot, @Nonnull ItemStack stack, @Nonnull Direction side )
     {
         return true;
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java
index 65d186659..974411072 100644
--- a/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/DirectionUtil.java
@@ -20,8 +20,8 @@ public final class DirectionUtil
 
         if( dir == front ) return ComputerSide.FRONT;
         if( dir == front.getOpposite() ) return ComputerSide.BACK;
-        if( dir == front.rotateYCCW() ) return ComputerSide.LEFT;
-        if( dir == front.rotateY() ) return ComputerSide.RIGHT;
+        if( dir == front.getCounterClockWise() ) return ComputerSide.LEFT;
+        if( dir == front.getClockWise() ) return ComputerSide.RIGHT;
         if( dir == Direction.UP ) return ComputerSide.TOP;
         return ComputerSide.BOTTOM;
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java
index cb861edba..7aeaee014 100644
--- a/src/main/java/dan200/computercraft/shared/util/DropConsumer.java
+++ b/src/main/java/dan200/computercraft/shared/util/DropConsumer.java
@@ -40,8 +40,8 @@ public final class DropConsumer
         dropConsumer = consumer;
         remainingDrops = new ArrayList<>();
         dropEntity = entity;
-        dropWorld = entity.world;
-        dropBounds = new AxisAlignedBB( entity.getPosition() ).grow( 2, 2, 2 );
+        dropWorld = entity.level;
+        dropBounds = new AxisAlignedBB( entity.getCommandSenderBlockPosition() ).inflate( 2, 2, 2 );
     }
 
     public static void set( World world, BlockPos pos, Function consumer )
@@ -50,7 +50,7 @@ public final class DropConsumer
         remainingDrops = new ArrayList<>( 2 );
         dropEntity = null;
         dropWorld = world;
-        dropBounds = new AxisAlignedBB( pos ).grow( 2, 2, 2 );
+        dropBounds = new AxisAlignedBB( pos ).inflate( 2, 2, 2 );
     }
 
     public static List clear()
@@ -77,7 +77,7 @@ public final class DropConsumer
     {
         // Capture any nearby item spawns
         if( dropWorld == event.getWorld() && event.getEntity() instanceof ItemEntity
-            && dropBounds.contains( event.getEntity().getPositionVector() ) )
+            && dropBounds.contains( event.getEntity().getCommandSenderWorldPosition() ) )
         {
             handleDrops( ((ItemEntity) event.getEntity()).getItem() );
             event.setCanceled( true );
diff --git a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java
index d153b633d..9670068ea 100644
--- a/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java
+++ b/src/main/java/dan200/computercraft/shared/util/FakeNetHandler.java
@@ -22,7 +22,7 @@ public class FakeNetHandler extends ServerPlayNetHandler
 {
     public FakeNetHandler( @Nonnull FakePlayer player )
     {
-        super( player.getServerWorld().getServer(), new FakeNetworkManager(), player );
+        super( player.getLevel().getServer(), new FakeNetworkManager(), player );
     }
 
     @Override
@@ -41,32 +41,32 @@ public class FakeNetHandler extends ServerPlayNetHandler
     }
 
     @Override
-    public void sendPacket( @Nonnull IPacket packet )
+    public void send( @Nonnull IPacket packet )
     {
     }
 
     @Override
-    public void sendPacket( @Nonnull IPacket packet, @Nullable GenericFutureListener> whenSent )
+    public void send( @Nonnull IPacket packet, @Nullable GenericFutureListener> whenSent )
     {
     }
 
     @Override
-    public void processInput( @Nonnull CInputPacket packet )
+    public void handlePlayerInput( @Nonnull CInputPacket packet )
     {
     }
 
     @Override
-    public void processVehicleMove( @Nonnull CMoveVehiclePacket packet )
+    public void handleMoveVehicle( @Nonnull CMoveVehiclePacket packet )
     {
     }
 
     @Override
-    public void processConfirmTeleport( @Nonnull CConfirmTeleportPacket packet )
+    public void handleAcceptTeleportPacket( @Nonnull CConfirmTeleportPacket packet )
     {
     }
 
     @Override
-    public void handleRecipeBookUpdate( @Nonnull CRecipeInfoPacket packet )
+    public void handleRecipeBookUpdatePacket( @Nonnull CRecipeInfoPacket packet )
     {
     }
 
@@ -76,192 +76,192 @@ public class FakeNetHandler extends ServerPlayNetHandler
     }
 
     @Override
-    public void processTabComplete( @Nonnull CTabCompletePacket packet )
+    public void handleCustomCommandSuggestions( @Nonnull CTabCompletePacket packet )
     {
     }
 
     @Override
-    public void processUpdateCommandBlock( @Nonnull CUpdateCommandBlockPacket packet )
+    public void handleSetCommandBlock( @Nonnull CUpdateCommandBlockPacket packet )
     {
     }
 
     @Override
-    public void processUpdateCommandMinecart( @Nonnull CUpdateMinecartCommandBlockPacket packet )
+    public void handleSetCommandMinecart( @Nonnull CUpdateMinecartCommandBlockPacket packet )
     {
     }
 
     @Override
-    public void processPickItem( @Nonnull CPickItemPacket packet )
+    public void handlePickItem( @Nonnull CPickItemPacket packet )
     {
     }
 
     @Override
-    public void processRenameItem( @Nonnull CRenameItemPacket packet )
+    public void handleRenameItem( @Nonnull CRenameItemPacket packet )
     {
     }
 
     @Override
-    public void processUpdateBeacon( @Nonnull CUpdateBeaconPacket packet )
+    public void handleSetBeaconPacket( @Nonnull CUpdateBeaconPacket packet )
     {
     }
 
     @Override
-    public void processUpdateStructureBlock( @Nonnull CUpdateStructureBlockPacket packet )
+    public void handleSetStructureBlock( @Nonnull CUpdateStructureBlockPacket packet )
     {
     }
 
     @Override
-    public void func_217262_a( @Nonnull CUpdateJigsawBlockPacket packet )
+    public void handleSetJigsawBlock( @Nonnull CUpdateJigsawBlockPacket packet )
     {
     }
 
     @Override
-    public void processSelectTrade( @Nonnull CSelectTradePacket packet )
+    public void handleSelectTrade( @Nonnull CSelectTradePacket packet )
     {
     }
 
     @Override
-    public void processEditBook( @Nonnull CEditBookPacket packet )
+    public void handleEditBook( @Nonnull CEditBookPacket packet )
     {
     }
 
     @Override
-    public void processNBTQueryEntity( @Nonnull CQueryEntityNBTPacket packet )
+    public void handleEntityTagQuery( @Nonnull CQueryEntityNBTPacket packet )
     {
     }
 
     @Override
-    public void processNBTQueryBlockEntity( @Nonnull CQueryTileEntityNBTPacket packet )
+    public void handleBlockEntityTagQuery( @Nonnull CQueryTileEntityNBTPacket packet )
     {
     }
 
     @Override
-    public void processPlayer( @Nonnull CPlayerPacket packet )
+    public void handleMovePlayer( @Nonnull CPlayerPacket packet )
     {
     }
 
     @Override
-    public void processPlayerDigging( @Nonnull CPlayerDiggingPacket packet )
+    public void handlePlayerAction( @Nonnull CPlayerDiggingPacket packet )
     {
     }
 
     @Override
-    public void processTryUseItemOnBlock( @Nonnull CPlayerTryUseItemOnBlockPacket packet )
+    public void handleUseItemOn( @Nonnull CPlayerTryUseItemOnBlockPacket packet )
     {
     }
 
     @Override
-    public void processTryUseItem( @Nonnull CPlayerTryUseItemPacket packet )
+    public void handleUseItem( @Nonnull CPlayerTryUseItemPacket packet )
     {
     }
 
     @Override
-    public void handleSpectate( @Nonnull CSpectatePacket packet )
+    public void handleTeleportToEntityPacket( @Nonnull CSpectatePacket packet )
     {
     }
 
     @Override
-    public void handleResourcePackStatus( @Nonnull CResourcePackStatusPacket packet )
+    public void handleResourcePackResponse( @Nonnull CResourcePackStatusPacket packet )
     {
     }
 
     @Override
-    public void processSteerBoat( @Nonnull CSteerBoatPacket packet )
+    public void handlePaddleBoat( @Nonnull CSteerBoatPacket packet )
     {
     }
 
     @Override
-    public void processHeldItemChange( @Nonnull CHeldItemChangePacket packet )
+    public void handleSetCarriedItem( @Nonnull CHeldItemChangePacket packet )
     {
     }
 
     @Override
-    public void processChatMessage( @Nonnull CChatMessagePacket packet )
+    public void handleChat( @Nonnull CChatMessagePacket packet )
     {
     }
 
     @Override
-    public void handleAnimation( @Nonnull CAnimateHandPacket packet )
+    public void handleAnimate( @Nonnull CAnimateHandPacket packet )
     {
     }
 
     @Override
-    public void processEntityAction( @Nonnull CEntityActionPacket packet )
+    public void handlePlayerCommand( @Nonnull CEntityActionPacket packet )
     {
     }
 
     @Override
-    public void processUseEntity( @Nonnull CUseEntityPacket packet )
+    public void handleInteract( @Nonnull CUseEntityPacket packet )
     {
     }
 
     @Override
-    public void processClientStatus( @Nonnull CClientStatusPacket packet )
+    public void handleClientCommand( @Nonnull CClientStatusPacket packet )
     {
     }
 
     @Override
-    public void processCloseWindow( @Nonnull CCloseWindowPacket packet )
+    public void handleContainerClose( @Nonnull CCloseWindowPacket packet )
     {
     }
 
     @Override
-    public void processClickWindow( @Nonnull CClickWindowPacket packet )
+    public void handleContainerClick( @Nonnull CClickWindowPacket packet )
     {
     }
 
     @Override
-    public void processPlaceRecipe( @Nonnull CPlaceRecipePacket packet )
+    public void handlePlaceRecipe( @Nonnull CPlaceRecipePacket packet )
     {
     }
 
     @Override
-    public void processEnchantItem( @Nonnull CEnchantItemPacket packet )
+    public void handleContainerButtonClick( @Nonnull CEnchantItemPacket packet )
     {
     }
 
     @Override
-    public void processCreativeInventoryAction( @Nonnull CCreativeInventoryActionPacket packet )
+    public void handleSetCreativeModeSlot( @Nonnull CCreativeInventoryActionPacket packet )
     {
     }
 
     @Override
-    public void processConfirmTransaction( @Nonnull CConfirmTransactionPacket packet )
+    public void handleContainerAck( @Nonnull CConfirmTransactionPacket packet )
     {
     }
 
     @Override
-    public void processUpdateSign( @Nonnull CUpdateSignPacket packet )
+    public void handleSignUpdate( @Nonnull CUpdateSignPacket packet )
     {
     }
 
     @Override
-    public void processKeepAlive( @Nonnull CKeepAlivePacket packet )
+    public void handleKeepAlive( @Nonnull CKeepAlivePacket packet )
     {
     }
 
     @Override
-    public void processPlayerAbilities( @Nonnull CPlayerAbilitiesPacket packet )
+    public void handlePlayerAbilities( @Nonnull CPlayerAbilitiesPacket packet )
     {
     }
 
     @Override
-    public void processClientSettings( @Nonnull CClientSettingsPacket packet )
+    public void handleClientInformation( @Nonnull CClientSettingsPacket packet )
     {
     }
 
     @Override
-    public void processCustomPayload( @Nonnull CCustomPayloadPacket packet )
+    public void handleCustomPayload( @Nonnull CCustomPayloadPacket packet )
     {
     }
 
     @Override
-    public void func_217263_a( @Nonnull CSetDifficultyPacket packet )
+    public void handleChangeDifficulty( @Nonnull CSetDifficultyPacket packet )
     {
     }
 
     @Override
-    public void func_217261_a( @Nonnull CLockDifficultyPacket packet )
+    public void handleLockDifficulty( @Nonnull CLockDifficultyPacket packet )
     {
     }
 
@@ -281,7 +281,7 @@ public class FakeNetHandler extends ServerPlayNetHandler
         }
 
         @Override
-        public void setConnectionState( @Nonnull ProtocolType state )
+        public void setProtocol( @Nonnull ProtocolType state )
         {
         }
 
@@ -301,18 +301,18 @@ public class FakeNetHandler extends ServerPlayNetHandler
         }
 
         @Override
-        public void setNetHandler( @Nonnull INetHandler handler )
+        public void setListener( @Nonnull INetHandler handler )
         {
             this.handler = handler;
         }
 
         @Override
-        public void sendPacket( @Nonnull IPacket packet )
+        public void send( @Nonnull IPacket packet )
         {
         }
 
         @Override
-        public void sendPacket( @Nonnull IPacket packet, @Nullable GenericFutureListener> whenSent )
+        public void send( @Nonnull IPacket packet, @Nullable GenericFutureListener> whenSent )
         {
         }
 
@@ -322,37 +322,37 @@ public class FakeNetHandler extends ServerPlayNetHandler
         }
 
         @Override
-        public void closeChannel( @Nonnull ITextComponent message )
+        public void disconnect( @Nonnull ITextComponent message )
         {
             this.closeReason = message;
         }
 
         @Override
-        public void enableEncryption( @Nonnull SecretKey key )
+        public void setEncryptionKey( @Nonnull SecretKey key )
         {
         }
 
         @Nonnull
         @Override
-        public INetHandler getNetHandler()
+        public INetHandler getPacketListener()
         {
             return handler;
         }
 
         @Nullable
         @Override
-        public ITextComponent getExitMessage()
+        public ITextComponent getDisconnectedReason()
         {
             return closeReason;
         }
 
         @Override
-        public void disableAutoRead()
+        public void setReadOnly()
         {
         }
 
         @Override
-        public void setCompressionThreshold( int threshold )
+        public void setupCompression( int threshold )
         {
         }
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java
index ffc2fc411..2eb921f20 100644
--- a/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java
+++ b/src/main/java/dan200/computercraft/shared/util/FixedPointTileEntityType.java
@@ -35,7 +35,7 @@ public final class FixedPointTileEntityType extends TileEn
     }
 
     @Override
-    public boolean isValidBlock( @Nonnull Block block )
+    public boolean isValid( @Nonnull Block block )
     {
         return block == this.block.get();
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java
index dfa7a8ac4..d8aeba4a2 100644
--- a/src/main/java/dan200/computercraft/shared/util/IDAssigner.java
+++ b/src/main/java/dan200/computercraft/shared/util/IDAssigner.java
@@ -42,7 +42,7 @@ public final class IDAssigner
     public static File getDir()
     {
         MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
-        File worldDirectory = server.getWorld( DimensionType.OVERWORLD ).getSaveHandler().getWorldDirectory();
+        File worldDirectory = server.getLevel( DimensionType.OVERWORLD ).getLevelStorage().getFolder();
         return new File( worldDirectory, ComputerCraft.MOD_ID );
     }
 
diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java
index eed4f920f..418fa9449 100644
--- a/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/util/ImpostorRecipe.java
@@ -45,7 +45,7 @@ public final class ImpostorRecipe extends ShapedRecipe
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory )
+    public ItemStack assemble( @Nonnull CraftingInventory inventory )
     {
         return ItemStack.EMPTY;
     }
@@ -60,34 +60,34 @@ public final class ImpostorRecipe extends ShapedRecipe
     public static final IRecipeSerializer SERIALIZER = new BasicRecipeSerializer()
     {
         @Override
-        public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json )
+        public ImpostorRecipe fromJson( @Nonnull ResourceLocation identifier, @Nonnull JsonObject json )
         {
-            String group = JSONUtils.getString( json, "group", "" );
-            ShapedRecipe recipe = IRecipeSerializer.CRAFTING_SHAPED.read( identifier, json );
-            ItemStack result = CraftingHelper.getItemStack( JSONUtils.getJsonObject( json, "result" ), true );
+            String group = JSONUtils.getAsString( json, "group", "" );
+            ShapedRecipe recipe = IRecipeSerializer.SHAPED_RECIPE.fromJson( identifier, json );
+            ItemStack result = CraftingHelper.getItemStack( JSONUtils.getAsJsonObject( json, "result" ), true );
             return new ImpostorRecipe( identifier, group, recipe.getWidth(), recipe.getHeight(), recipe.getIngredients(), result );
         }
 
         @Override
-        public ImpostorRecipe read( @Nonnull ResourceLocation identifier, @Nonnull PacketBuffer buf )
+        public ImpostorRecipe fromNetwork( @Nonnull ResourceLocation identifier, @Nonnull PacketBuffer buf )
         {
             int width = buf.readVarInt();
             int height = buf.readVarInt();
-            String group = buf.readString( Short.MAX_VALUE );
+            String group = buf.readUtf( Short.MAX_VALUE );
             NonNullList items = NonNullList.withSize( width * height, Ingredient.EMPTY );
-            for( int k = 0; k < items.size(); ++k ) items.set( k, Ingredient.read( buf ) );
-            ItemStack result = buf.readItemStack();
+            for( int k = 0; k < items.size(); ++k ) items.set( k, Ingredient.fromNetwork( buf ) );
+            ItemStack result = buf.readItem();
             return new ImpostorRecipe( identifier, group, width, height, items, result );
         }
 
         @Override
-        public void write( @Nonnull PacketBuffer buf, @Nonnull ImpostorRecipe recipe )
+        public void toNetwork( @Nonnull PacketBuffer buf, @Nonnull ImpostorRecipe recipe )
         {
             buf.writeVarInt( recipe.getRecipeWidth() );
             buf.writeVarInt( recipe.getRecipeHeight() );
-            buf.writeString( recipe.getGroup() );
-            for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buf );
-            buf.writeItemStack( recipe.getRecipeOutput() );
+            buf.writeUtf( recipe.getGroup() );
+            for( Ingredient ingredient : recipe.getIngredients() ) ingredient.toNetwork( buf );
+            buf.writeItem( recipe.getResultItem() );
         }
     };
 }
diff --git a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java
index 42b77e9fe..60d449ef7 100644
--- a/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/util/ImpostorShapelessRecipe.java
@@ -47,7 +47,7 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe
 
     @Nonnull
     @Override
-    public ItemStack getCraftingResult( @Nonnull CraftingInventory inventory )
+    public ItemStack assemble( @Nonnull CraftingInventory inventory )
     {
         return ItemStack.EMPTY;
     }
@@ -62,10 +62,10 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe
     public static final IRecipeSerializer SERIALIZER = new BasicRecipeSerializer()
     {
         @Override
-        public ImpostorShapelessRecipe read( @Nonnull ResourceLocation id, @Nonnull JsonObject json )
+        public ImpostorShapelessRecipe fromJson( @Nonnull ResourceLocation id, @Nonnull JsonObject json )
         {
-            String s = JSONUtils.getString( json, "group", "" );
-            NonNullList ingredients = readIngredients( JSONUtils.getJsonArray( json, "ingredients" ) );
+            String s = JSONUtils.getAsString( json, "group", "" );
+            NonNullList ingredients = readIngredients( JSONUtils.getAsJsonArray( json, "ingredients" ) );
 
             if( ingredients.isEmpty() ) throw new JsonParseException( "No ingredients for shapeless recipe" );
             if( ingredients.size() > 9 )
@@ -73,7 +73,7 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe
                 throw new JsonParseException( "Too many ingredients for shapeless recipe the max is 9" );
             }
 
-            ItemStack itemstack = CraftingHelper.getItemStack( JSONUtils.getJsonObject( json, "result" ), true );
+            ItemStack itemstack = CraftingHelper.getItemStack( JSONUtils.getAsJsonObject( json, "result" ), true );
             return new ImpostorShapelessRecipe( id, s, itemstack, ingredients );
         }
 
@@ -82,34 +82,34 @@ public final class ImpostorShapelessRecipe extends ShapelessRecipe
             NonNullList items = NonNullList.create();
             for( int i = 0; i < arrays.size(); ++i )
             {
-                Ingredient ingredient = Ingredient.deserialize( arrays.get( i ) );
-                if( !ingredient.hasNoMatchingItems() ) items.add( ingredient );
+                Ingredient ingredient = Ingredient.fromJson( arrays.get( i ) );
+                if( !ingredient.isEmpty() ) items.add( ingredient );
             }
 
             return items;
         }
 
         @Override
-        public ImpostorShapelessRecipe read( @Nonnull ResourceLocation id, PacketBuffer buffer )
+        public ImpostorShapelessRecipe fromNetwork( @Nonnull ResourceLocation id, PacketBuffer buffer )
         {
-            String s = buffer.readString( 32767 );
+            String s = buffer.readUtf( 32767 );
             int i = buffer.readVarInt();
             NonNullList items = NonNullList.withSize( i, Ingredient.EMPTY );
 
-            for( int j = 0; j < items.size(); j++ ) items.set( j, Ingredient.read( buffer ) );
-            ItemStack result = buffer.readItemStack();
+            for( int j = 0; j < items.size(); j++ ) items.set( j, Ingredient.fromNetwork( buffer ) );
+            ItemStack result = buffer.readItem();
 
             return new ImpostorShapelessRecipe( id, s, result, items );
         }
 
         @Override
-        public void write( @Nonnull PacketBuffer buffer, @Nonnull ImpostorShapelessRecipe recipe )
+        public void toNetwork( @Nonnull PacketBuffer buffer, @Nonnull ImpostorShapelessRecipe recipe )
         {
-            buffer.writeString( recipe.getGroup() );
+            buffer.writeUtf( recipe.getGroup() );
             buffer.writeVarInt( recipe.getIngredients().size() );
 
-            for( Ingredient ingredient : recipe.getIngredients() ) ingredient.write( buffer );
-            buffer.writeItemStack( recipe.getRecipeOutput() );
+            for( Ingredient ingredient : recipe.getIngredients() ) ingredient.toNetwork( buffer );
+            buffer.writeItem( recipe.getResultItem() );
         }
     };
 }
diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java
index 9e07db877..bf01c855b 100644
--- a/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java
+++ b/src/main/java/dan200/computercraft/shared/util/InventoryDelegate.java
@@ -25,9 +25,9 @@ public interface InventoryDelegate extends IInventory
     IInventory getInventory();
 
     @Override
-    default int getSizeInventory()
+    default int getContainerSize()
     {
-        return getInventory().getSizeInventory();
+        return getInventory().getContainerSize();
     }
 
     @Override
@@ -38,82 +38,82 @@ public interface InventoryDelegate extends IInventory
 
     @Nonnull
     @Override
-    default ItemStack getStackInSlot( int slot )
+    default ItemStack getItem( int slot )
     {
-        return getInventory().getStackInSlot( slot );
+        return getInventory().getItem( slot );
     }
 
     @Nonnull
     @Override
-    default ItemStack decrStackSize( int slot, int count )
+    default ItemStack removeItem( int slot, int count )
     {
-        return getInventory().decrStackSize( slot, count );
+        return getInventory().removeItem( slot, count );
     }
 
     @Nonnull
     @Override
-    default ItemStack removeStackFromSlot( int slot )
+    default ItemStack removeItemNoUpdate( int slot )
     {
-        return getInventory().removeStackFromSlot( slot );
+        return getInventory().removeItemNoUpdate( slot );
     }
 
     @Override
-    default void setInventorySlotContents( int slot, @Nonnull ItemStack stack )
+    default void setItem( int slot, @Nonnull ItemStack stack )
     {
-        getInventory().setInventorySlotContents( slot, stack );
+        getInventory().setItem( slot, stack );
     }
 
     @Override
-    default int getInventoryStackLimit()
+    default int getMaxStackSize()
     {
-        return getInventory().getInventoryStackLimit();
+        return getInventory().getMaxStackSize();
     }
 
     @Override
-    default void markDirty()
+    default void setChanged()
     {
-        getInventory().markDirty();
+        getInventory().setChanged();
     }
 
     @Override
-    default boolean isUsableByPlayer( @Nonnull PlayerEntity player )
+    default boolean stillValid( @Nonnull PlayerEntity player )
     {
-        return getInventory().isUsableByPlayer( player );
+        return getInventory().stillValid( player );
     }
 
     @Override
-    default void openInventory( @Nonnull PlayerEntity player )
+    default void startOpen( @Nonnull PlayerEntity player )
     {
-        getInventory().openInventory( player );
+        getInventory().startOpen( player );
     }
 
     @Override
-    default void closeInventory( @Nonnull PlayerEntity player )
+    default void stopOpen( @Nonnull PlayerEntity player )
     {
-        getInventory().closeInventory( player );
+        getInventory().stopOpen( player );
     }
 
     @Override
-    default boolean isItemValidForSlot( int slot, @Nonnull ItemStack stack )
+    default boolean canPlaceItem( int slot, @Nonnull ItemStack stack )
     {
-        return getInventory().isItemValidForSlot( slot, stack );
+        return getInventory().canPlaceItem( slot, stack );
     }
 
     @Override
-    default void clear()
+    default void clearContent()
     {
-        getInventory().clear();
+        getInventory().clearContent();
     }
 
     @Override
-    default int count( @Nonnull Item stack )
+    default int countItem( @Nonnull Item stack )
     {
-        return getInventory().count( stack );
+        return getInventory().countItem( stack );
     }
 
     @Override
-    default boolean hasAny( @Nonnull Set set )
+    default boolean hasAnyOf( @Nonnull Set set )
     {
-        return getInventory().hasAny( set );
+        return getInventory().hasAnyOf( set );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java
index 46fb5b37e..faab94b04 100644
--- a/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/InventoryUtil.java
@@ -31,7 +31,7 @@ public final class InventoryUtil
 
     public static boolean areItemsEqual( @Nonnull ItemStack a, @Nonnull ItemStack b )
     {
-        return a == b || ItemStack.areItemStacksEqual( a, b );
+        return a == b || ItemStack.matches( a, b );
     }
 
     public static boolean areItemsStackable( @Nonnull ItemStack a, @Nonnull ItemStack b )
@@ -44,7 +44,7 @@ public final class InventoryUtil
     public static IItemHandler getInventory( World world, BlockPos pos, Direction side )
     {
         // Look for tile with inventory
-        TileEntity tileEntity = world.getTileEntity( pos );
+        TileEntity tileEntity = world.getBlockEntity( pos );
         if( tileEntity != null )
         {
             LazyOptional itemHandler = tileEntity.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, side );
@@ -64,13 +64,13 @@ public final class InventoryUtil
 
         // Look for entity with inventory
         Vec3d vecStart = new Vec3d(
-            pos.getX() + 0.5 + 0.6 * side.getXOffset(),
-            pos.getY() + 0.5 + 0.6 * side.getYOffset(),
-            pos.getZ() + 0.5 + 0.6 * side.getZOffset()
+            pos.getX() + 0.5 + 0.6 * side.getStepX(),
+            pos.getY() + 0.5 + 0.6 * side.getStepY(),
+            pos.getZ() + 0.5 + 0.6 * side.getStepZ()
         );
         Direction dir = side.getOpposite();
         Vec3d vecDir = new Vec3d(
-            dir.getXOffset(), dir.getYOffset(), dir.getZOffset()
+            dir.getStepX(), dir.getStepY(), dir.getStepZ()
         );
         Pair hit = WorldUtil.rayTraceEntities( world, vecStart, vecDir, 1.1 );
         if( hit != null )
diff --git a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java
index 2d534ac5b..5895ebdfb 100644
--- a/src/main/java/dan200/computercraft/shared/util/NBTUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/NBTUtil.java
@@ -76,12 +76,12 @@ public final class NBTUtil
         switch( tag.getId() )
         {
             case TAG_BYTE:
-                return ((ByteNBT) tag).getByte() > 0;
+                return ((ByteNBT) tag).getAsByte() > 0;
             case TAG_DOUBLE:
-                return ((DoubleNBT) tag).getDouble();
+                return ((DoubleNBT) tag).getAsDouble();
             default:
             case TAG_STRING:
-                return tag.getString();
+                return tag.getAsString();
             case TAG_COMPOUND:
             {
                 CompoundNBT c = (CompoundNBT) tag;
@@ -109,17 +109,17 @@ public final class NBTUtil
             case Constants.NBT.TAG_SHORT:
             case Constants.NBT.TAG_INT:
             case Constants.NBT.TAG_LONG:
-                return ((NumberNBT) tag).getLong();
+                return ((NumberNBT) tag).getAsLong();
             case Constants.NBT.TAG_FLOAT:
             case Constants.NBT.TAG_DOUBLE:
-                return ((NumberNBT) tag).getDouble();
+                return ((NumberNBT) tag).getAsDouble();
             case Constants.NBT.TAG_STRING: // String
-                return tag.getString();
+                return tag.getAsString();
             case Constants.NBT.TAG_COMPOUND: // Compound
             {
                 CompoundNBT compound = (CompoundNBT) tag;
                 Map map = new HashMap<>( compound.size() );
-                for( String key : compound.keySet() )
+                for( String key : compound.getAllKeys() )
                 {
                     Object value = toLua( compound.get( key ) );
                     if( value != null ) map.put( key, value );
@@ -135,14 +135,14 @@ public final class NBTUtil
             }
             case Constants.NBT.TAG_BYTE_ARRAY:
             {
-                byte[] array = ((ByteArrayNBT) tag).getByteArray();
+                byte[] array = ((ByteArrayNBT) tag).getAsByteArray();
                 Map map = new HashMap<>( array.length );
                 for( int i = 0; i < array.length; i++ ) map.put( i + 1, array[i] );
                 return map;
             }
             case Constants.NBT.TAG_INT_ARRAY:
             {
-                int[] array = ((IntArrayNBT) tag).getIntArray();
+                int[] array = ((IntArrayNBT) tag).getAsIntArray();
                 Map map = new HashMap<>( array.length );
                 for( int i = 0; i < array.length; i++ ) map.put( i + 1, array[i] );
                 return map;
diff --git a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java
index b142b7f70..b27cb75b9 100644
--- a/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/RecipeUtil.java
@@ -42,7 +42,7 @@ public final class RecipeUtil
     public static ShapedTemplate getTemplate( JsonObject json )
     {
         Map ingMap = Maps.newHashMap();
-        for( Map.Entry entry : JSONUtils.getJsonObject( json, "key" ).entrySet() )
+        for( Map.Entry entry : JSONUtils.getAsJsonObject( json, "key" ).entrySet() )
         {
             if( entry.getKey().length() != 1 )
             {
@@ -53,12 +53,12 @@ public final class RecipeUtil
                 throw new JsonSyntaxException( "Invalid key entry: ' ' is a reserved symbol." );
             }
 
-            ingMap.put( entry.getKey().charAt( 0 ), Ingredient.deserialize( entry.getValue() ) );
+            ingMap.put( entry.getKey().charAt( 0 ), Ingredient.fromJson( entry.getValue() ) );
         }
 
         ingMap.put( ' ', Ingredient.EMPTY );
 
-        JsonArray patternJ = JSONUtils.getJsonArray( json, "pattern" );
+        JsonArray patternJ = JSONUtils.getAsJsonArray( json, "pattern" );
 
         if( patternJ.size() == 0 )
         {
@@ -68,7 +68,7 @@ public final class RecipeUtil
         String[] pattern = new String[patternJ.size()];
         for( int x = 0; x < pattern.length; x++ )
         {
-            String line = JSONUtils.getString( patternJ.get( x ), "pattern[" + x + "]" );
+            String line = JSONUtils.convertToString( patternJ.get( x ), "pattern[" + x + "]" );
             if( x > 0 && pattern[0].length() != line.length() )
             {
                 throw new JsonSyntaxException( "Invalid pattern: each row must  be the same width" );
@@ -108,7 +108,7 @@ public final class RecipeUtil
 
     public static ComputerFamily getFamily( JsonObject json, String name )
     {
-        String familyName = JSONUtils.getString( json, name );
+        String familyName = JSONUtils.getAsString( json, name );
         for( ComputerFamily family : ComputerFamily.values() )
         {
             if( family.name().equalsIgnoreCase( familyName ) ) return family;
diff --git a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java
index 933a287cb..41c632dc9 100644
--- a/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/RedstoneUtil.java
@@ -21,8 +21,8 @@ public final class RedstoneUtil
         BlockState block = world.getBlockState( pos );
         if( ForgeEventFactory.onNeighborNotify( world, pos, block, EnumSet.of( side ), false ).isCanceled() ) return;
 
-        BlockPos neighbourPos = pos.offset( side );
+        BlockPos neighbourPos = pos.relative( side );
         world.neighborChanged( neighbourPos, block.getBlock(), pos );
-        world.notifyNeighborsOfStateExcept( neighbourPos, block.getBlock(), side.getOpposite() );
+        world.updateNeighborsAtExceptFromFacing( neighbourPos, block.getBlock(), side.getOpposite() );
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java
index 19f763e67..cad7144b5 100644
--- a/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java
+++ b/src/main/java/dan200/computercraft/shared/util/SingleIntArray.java
@@ -24,7 +24,7 @@ public interface SingleIntArray extends IIntArray
     }
 
     @Override
-    default int size()
+    default int getCount()
     {
         return 1;
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java
index 760ad6a8c..6a1a78627 100644
--- a/src/main/java/dan200/computercraft/shared/util/TickScheduler.java
+++ b/src/main/java/dan200/computercraft/shared/util/TickScheduler.java
@@ -40,8 +40,8 @@ public final class TickScheduler
 
     public static void schedule( TileGeneric tile )
     {
-        World world = tile.getWorld();
-        if( world != null && !world.isRemote ) toTick.add( tile );
+        World world = tile.getLevel();
+        if( world != null && !world.isClientSide ) toTick.add( tile );
     }
 
     @SubscribeEvent
@@ -55,12 +55,12 @@ public final class TickScheduler
             TileEntity tile = iterator.next();
             iterator.remove();
 
-            World world = tile.getWorld();
-            BlockPos pos = tile.getPos();
+            World world = tile.getLevel();
+            BlockPos pos = tile.getBlockPos();
 
-            if( world != null && pos != null && world.isAreaLoaded( pos, 0 ) && world.getTileEntity( pos ) == tile )
+            if( world != null && pos != null && world.isAreaLoaded( pos, 0 ) && world.getBlockEntity( pos ) == tile )
             {
-                world.getPendingBlockTicks().scheduleTick( pos, tile.getBlockState().getBlock(), 0 );
+                world.getBlockTicks().scheduleTick( pos, tile.getBlockState().getBlock(), 0 );
             }
         }
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java
index ec541024d..57904d60a 100644
--- a/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java
+++ b/src/main/java/dan200/computercraft/shared/util/ValidatingSlot.java
@@ -19,7 +19,7 @@ public class ValidatingSlot extends Slot
     }
 
     @Override
-    public boolean isItemValid( @Nonnull ItemStack stack )
+    public boolean mayPlace( @Nonnull ItemStack stack )
     {
         return true; // inventory.isItemValidForSlot( slotNumber, stack );
     }
diff --git a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java
index e9d6e9c54..76dda67af 100644
--- a/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java
+++ b/src/main/java/dan200/computercraft/shared/util/WaterloggableHelpers.java
@@ -36,7 +36,7 @@ public final class WaterloggableHelpers
      */
     public static IFluidState getWaterloggedFluidState( BlockState state )
     {
-        return state.get( WATERLOGGED ) ? Fluids.WATER.getStillFluidState( false ) : Fluids.EMPTY.getDefaultState();
+        return state.getValue( WATERLOGGED ) ? Fluids.WATER.getSource( false ) : Fluids.EMPTY.defaultFluidState();
     }
 
     /**
@@ -48,14 +48,14 @@ public final class WaterloggableHelpers
      */
     public static void updateWaterloggedPostPlacement( BlockState state, IWorld world, BlockPos pos )
     {
-        if( state.get( WATERLOGGED ) )
+        if( state.getValue( WATERLOGGED ) )
         {
-            world.getPendingFluidTicks().scheduleTick( pos, Fluids.WATER, Fluids.WATER.getTickRate( world ) );
+            world.getLiquidTicks().scheduleTick( pos, Fluids.WATER, Fluids.WATER.getTickDelay( world ) );
         }
     }
 
     public static boolean getWaterloggedStateForPlacement( BlockItemUseContext context )
     {
-        return context.getWorld().getFluidState( context.getPos() ).getFluid() == Fluids.WATER;
+        return context.getLevel().getFluidState( context.getClickedPos() ).getType() == Fluids.WATER;
     }
 }
diff --git a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java
index d7415a5d5..a11eb97a4 100644
--- a/src/main/java/dan200/computercraft/shared/util/WorldUtil.java
+++ b/src/main/java/dan200/computercraft/shared/util/WorldUtil.java
@@ -24,7 +24,7 @@ import java.util.Map;
 public final class WorldUtil
 {
     @SuppressWarnings( "Guava" )
-    private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.canBeCollidedWith();
+    private static final Predicate CAN_COLLIDE = x -> x != null && x.isAlive() && x.isPickable();
 
     private static final Map entityCache = new MapMaker().weakKeys().weakValues().makeMap();
 
@@ -38,21 +38,21 @@ public final class WorldUtil
         {
             @Nonnull
             @Override
-            public EntitySize getSize( @Nonnull Pose pose )
+            public EntitySize getDimensions( @Nonnull Pose pose )
             {
                 return EntitySize.fixed( 0, 0 );
             }
         };
 
-        entity.noClip = true;
-        entity.recalculateSize();
+        entity.noPhysics = true;
+        entity.refreshDimensions();
         entityCache.put( world, entity );
         return entity;
     }
 
     public static boolean isLiquidBlock( World world, BlockPos pos )
     {
-        if( !World.isValid( pos ) ) return false;
+        if( !World.isInWorldBounds( pos ) ) return false;
         return world.getBlockState( pos ).getMaterial().isLiquid();
     }
 
@@ -60,7 +60,7 @@ public final class WorldUtil
     {
         if( shape.isEmpty() ) return false;
         // AxisAlignedBB.contains, but without strict inequalities.
-        AxisAlignedBB bb = shape.getBoundingBox();
+        AxisAlignedBB bb = shape.bounds();
         return vec.x >= bb.minX && vec.x <= bb.maxX && vec.y >= bb.minY && vec.y <= bb.maxY && vec.z >= bb.minZ && vec.z <= bb.maxZ;
     }
 
@@ -70,12 +70,12 @@ public final class WorldUtil
 
         // Raycast for blocks
         Entity collisionEntity = getEntity( world );
-        collisionEntity.setPosition( vecStart.x, vecStart.y, vecStart.z );
+        collisionEntity.setPos( vecStart.x, vecStart.y, vecStart.z );
         RayTraceContext context = new RayTraceContext( vecStart, vecEnd, RayTraceContext.BlockMode.COLLIDER, RayTraceContext.FluidMode.NONE, collisionEntity );
-        RayTraceResult result = world.rayTraceBlocks( context );
+        RayTraceResult result = world.clip( context );
         if( result != null && result.getType() == RayTraceResult.Type.BLOCK )
         {
-            distance = vecStart.distanceTo( result.getHitVec() );
+            distance = vecStart.distanceTo( result.getLocation() );
             vecEnd = vecStart.add( vecDir.x * distance, vecDir.y * distance, vecDir.z * distance );
         }
 
@@ -94,7 +94,7 @@ public final class WorldUtil
 
         Entity closest = null;
         double closestDist = 99.0;
-        List list = world.getEntitiesWithinAABB( Entity.class, bigBox, CAN_COLLIDE );
+        List list = world.getEntitiesOfClass( Entity.class, bigBox, CAN_COLLIDE );
         for( Entity entity : list )
         {
             AxisAlignedBB littleBox = entity.getBoundingBox();
@@ -105,7 +105,7 @@ public final class WorldUtil
                 continue;
             }
 
-            Vec3d littleBoxResult = littleBox.rayTrace( vecStart, vecEnd ).orElse( null );
+            Vec3d littleBoxResult = littleBox.clip( vecStart, vecEnd ).orElse( null );
             if( littleBoxResult != null )
             {
                 double dist = vecStart.distanceTo( littleBoxResult );
@@ -140,7 +140,7 @@ public final class WorldUtil
     public static Vec3d getRayEnd( PlayerEntity player )
     {
         double reach = player.getAttribute( PlayerEntity.REACH_DISTANCE ).getValue();
-        Vec3d look = player.getLookVec();
+        Vec3d look = player.getLookAngle();
         return getRayStart( player ).add( look.x * reach, look.y * reach, look.z * reach );
     }
 
@@ -156,9 +156,9 @@ public final class WorldUtil
         double zDir;
         if( direction != null )
         {
-            xDir = direction.getXOffset();
-            yDir = direction.getYOffset();
-            zDir = direction.getZOffset();
+            xDir = direction.getStepX();
+            yDir = direction.getStepY();
+            zDir = direction.getStepZ();
         }
         else
         {
@@ -181,12 +181,12 @@ public final class WorldUtil
     public static void dropItemStack( @Nonnull ItemStack stack, World world, Vec3d pos, double xDir, double yDir, double zDir )
     {
         ItemEntity item = new ItemEntity( world, pos.x, pos.y, pos.z, stack.copy() );
-        item.setMotion(
+        item.setDeltaMovement(
             xDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1,
             yDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1,
             zDir * 0.7 + world.getRandom().nextFloat() * 0.2 - 0.1
         );
-        item.setDefaultPickupDelay();
-        world.addEntity( item );
+        item.setDefaultPickUpDelay();
+        world.addFreshEntity( item );
     }
 }
diff --git a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java
index b66d9accb..9077172b8 100644
--- a/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java
+++ b/src/test/java/dan200/computercraft/core/filesystem/ResourceMountTest.java
@@ -29,7 +29,7 @@ public class ResourceMountTest
     public void before()
     {
         SimpleReloadableResourceManager manager = new SimpleReloadableResourceManager( ResourcePackType.SERVER_DATA, null );
-        manager.addResourcePack( new FolderPack( new File( "src/main/resources" ) ) );
+        manager.add( new FolderPack( new File( "src/main/resources" ) ) );
 
         mount = ResourceMount.get( "computercraft", "lua/rom", manager );
     }
diff --git a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java
index a329fb565..ae6dd9117 100644
--- a/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java
+++ b/src/test/java/dan200/computercraft/shared/wired/NetworkTest.java
@@ -259,7 +259,7 @@ public class NetworkTest
             grid.forEach( ( existing, pos ) -> {
                 for( Direction facing : DirectionUtil.FACINGS )
                 {
-                    BlockPos offset = pos.offset( facing );
+                    BlockPos offset = pos.relative( facing );
                     if( offset.getX() > BRUTE_SIZE / 2 == pos.getX() > BRUTE_SIZE / 2 )
                     {
                         IWiredNode other = grid.get( offset );

From 331031be450a2eab062ea7b71d3a98758f57f230 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 19:50:27 +0000
Subject: [PATCH 420/711] Run integration tests in-game

Name a more iconic duo than @SquidDev and over-engineered test
frameworks.

This uses Minecraft's test core[1] plus a home-grown framework to run
tests against computers in-world.

The general idea is:
 - Build a structure in game.
 - Save the structure to a file. This will be spawned in every time the
   test is run.
 - Write some code which asserts the structure behaves in a particular
   way. This is done in Kotlin (shock, horror), as coroutines give us a
   nice way to run asynchronous code while still running on the main
   thread.

As with all my testing efforts, I still haven't actually written any
tests!  It'd be good to go through some of the historic ones and write
some tests though. Turtle block placing and computer redstone
interactions are probably a good place to start.

[1]: https://www.youtube.com/watch?v=vXaWOJTCYNg
---
 .gitattributes                                |   1 +
 .github/workflows/main-ci.yml                 |   5 +
 build.gradle                                  |  35 +-
 .../computercraft/ingame/ComputerTest.kt      |  27 +
 .../dan200/computercraft/ingame/TurtleTest.kt |  10 +
 .../ingame/api/ComputerState.java             |  37 ++
 .../computercraft/ingame/api/GameTest.java    |  45 ++
 .../computercraft/ingame/api/TestContext.java |  58 ++
 .../ingame/api/TestExtensions.kt              |  61 ++
 .../ingame/mod/CCTestCommand.java             |  56 ++
 .../computercraft/ingame/mod/TestAPI.java     |  63 ++
 .../computercraft/ingame/mod/TestLoader.java  | 119 ++++
 .../computercraft/ingame/mod/TestMod.java     | 117 ++++
 .../computercraft/ingame/mod/TestRunner.kt    |  62 ++
 .../dan200/computercraft/utils/Copier.java    |  49 ++
 src/test/resources/META-INF/mods.toml         |  18 +
 .../computercraft/lua/rom/autorun/cctest.lua  |  17 +
 src/test/resources/pack.mcmeta                |   6 +
 .../computers/computer/1/startup.lua          |   5 +
 src/test/server-files/computers/ids.json      |   3 +
 src/test/server-files/eula.txt                |   2 +
 src/test/server-files/server.properties       |  46 ++
 .../computer_test.no_through_signal.snbt      | 560 ++++++++++++++++++
 ...tle_test.unequip_refreshes_peripheral.snbt | 550 +++++++++++++++++
 24 files changed, 1950 insertions(+), 2 deletions(-)
 create mode 100644 src/test/java/dan200/computercraft/ingame/ComputerTest.kt
 create mode 100644 src/test/java/dan200/computercraft/ingame/TurtleTest.kt
 create mode 100644 src/test/java/dan200/computercraft/ingame/api/ComputerState.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/api/GameTest.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/api/TestContext.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt
 create mode 100644 src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/mod/TestAPI.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/mod/TestMod.java
 create mode 100644 src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt
 create mode 100644 src/test/java/dan200/computercraft/utils/Copier.java
 create mode 100644 src/test/resources/META-INF/mods.toml
 create mode 100644 src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua
 create mode 100755 src/test/resources/pack.mcmeta
 create mode 100644 src/test/server-files/computers/computer/1/startup.lua
 create mode 100644 src/test/server-files/computers/ids.json
 create mode 100644 src/test/server-files/eula.txt
 create mode 100644 src/test/server-files/server.properties
 create mode 100644 src/test/server-files/structures/computer_test.no_through_signal.snbt
 create mode 100644 src/test/server-files/structures/turtle_test.unequip_refreshes_peripheral.snbt

diff --git a/.gitattributes b/.gitattributes
index e05a3a6dd..6e40cf02e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,2 +1,3 @@
 # Ignore changes in generated files
 src/generated/resources/data/** linguist-generated
+src/test/server-files/structures linguist-generated
diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml
index 51895fcec..df76fca79 100644
--- a/.github/workflows/main-ci.yml
+++ b/.github/workflows/main-ci.yml
@@ -26,6 +26,11 @@ jobs:
     - name: Build with Gradle
       run: ./gradlew build --no-daemon || ./gradlew build --no-daemon
 
+    - name: Run in-game tests
+      run: |
+        ./gradlew setupServer --no-daemon
+        ./gradlew runTestServerRun --no-daemon
+
     - name: Upload Jar
       uses: actions/upload-artifact@v1
       with:
diff --git a/build.gradle b/build.gradle
index 559e9b54c..f0df19a88 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,6 +21,7 @@ plugins {
     id "com.github.hierynomus.license" version "0.15.0"
     id "com.matthewprenger.cursegradle" version "1.3.0"
     id "com.github.breadmoirai.github-release" version "2.2.4"
+    id "org.jetbrains.kotlin.jvm" version "1.3.72"
 }
 
 apply plugin: 'net.minecraftforge.gradle'
@@ -51,8 +52,9 @@ minecraft {
 
         server {
             workingDirectory project.file("run/server")
-            property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP'
+            property 'forge.logging.markers', 'REGISTRIES'
             property 'forge.logging.console.level', 'debug'
+            arg "--nogui"
 
             mods {
                 computercraft {
@@ -63,7 +65,7 @@ minecraft {
 
         data {
             workingDirectory project.file('run')
-            property 'forge.logging.markers', 'REGISTRIES,REGISTRYDUMP'
+            property 'forge.logging.markers', 'REGISTRIES'
             property 'forge.logging.console.level', 'debug'
 
             args '--mod', 'computercraft', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
@@ -73,6 +75,24 @@ minecraft {
                 }
             }
         }
+
+        testServer {
+            workingDirectory project.file('test-files/server')
+            parent runs.server
+
+            mods {
+                cctest {
+                    source sourceSets.test
+                }
+            }
+        }
+
+        testServerRun {
+            parent runs.testServer
+            property 'forge.logging.console.level', 'info'
+            property 'cctest.run', 'true'
+            forceExit false
+        }
     }
 
     mappings channel: 'official', version: project.mc_version
@@ -120,6 +140,9 @@ dependencies {
     testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
     testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
     testImplementation 'org.hamcrest:hamcrest:2.2'
+    testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72'
+    testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72'
+    testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
 
     deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
 
@@ -416,6 +439,14 @@ task licenseFormatAPI(type: LicenseFormat);
     }
 }
 
+task setupServer(type: Copy) {
+    from("src/test/server-files") {
+        include "eula.txt"
+        include "server.properties"
+    }
+    into "test-files/server"
+}
+
 // Upload tasks
 
 task checkRelease {
diff --git a/src/test/java/dan200/computercraft/ingame/ComputerTest.kt b/src/test/java/dan200/computercraft/ingame/ComputerTest.kt
new file mode 100644
index 000000000..48cd70204
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/ComputerTest.kt
@@ -0,0 +1,27 @@
+package dan200.computercraft.ingame
+
+import dan200.computercraft.ingame.api.*
+import net.minecraft.block.LeverBlock
+import net.minecraft.block.RedstoneLampBlock
+import net.minecraft.util.math.BlockPos
+import org.junit.jupiter.api.Assertions.assertFalse
+
+class ComputerTest {
+    /**
+     * Ensures redstone signals do not travel through computers.
+     *
+     * @see [Issue #548](https://github.com/SquidDev-CC/CC-Tweaked/issues/548)
+     */
+    @GameTest
+    suspend fun `No through signal`(context: TestContext) {
+        val lamp = BlockPos(2, 0, 4)
+        val lever = BlockPos(2, 0, 0)
+
+        assertFalse(context.getBlock(lamp).getValue(RedstoneLampBlock.LIT), "Lamp should not be lit")
+
+        context.modifyBlock(lever) { x -> x.setValue(LeverBlock.POWERED, true) }
+        context.sleep(3)
+
+        assertFalse(context.getBlock(lamp).getValue(RedstoneLampBlock.LIT), "Lamp should still not be lit")
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/TurtleTest.kt b/src/test/java/dan200/computercraft/ingame/TurtleTest.kt
new file mode 100644
index 000000000..37102388b
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/TurtleTest.kt
@@ -0,0 +1,10 @@
+package dan200.computercraft.ingame
+
+import dan200.computercraft.ingame.api.GameTest
+import dan200.computercraft.ingame.api.TestContext
+import dan200.computercraft.ingame.api.checkComputerOk
+
+class TurtleTest {
+    @GameTest(required = false)
+    suspend fun `Unequip refreshes peripheral`(context: TestContext) = context.checkComputerOk(1)
+}
diff --git a/src/test/java/dan200/computercraft/ingame/api/ComputerState.java b/src/test/java/dan200/computercraft/ingame/api/ComputerState.java
new file mode 100644
index 000000000..311945d8b
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/api/ComputerState.java
@@ -0,0 +1,37 @@
+package dan200.computercraft.ingame.api;
+
+import dan200.computercraft.ingame.mod.TestAPI;
+import kotlin.coroutines.Continuation;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Assertion state of a computer.
+ *
+ * @see TestAPI For the Lua interface for this.
+ * @see TestExtensionsKt#checkComputerOk(TestContext, int, Continuation)
+ */
+public class ComputerState
+{
+    protected static final Map lookup = new ConcurrentHashMap<>();
+
+    protected boolean done;
+    protected String error;
+
+    public boolean isDone()
+    {
+        return done;
+    }
+
+    public void check()
+    {
+        if( !done ) throw new IllegalStateException( "Not yet done" );
+        if( error != null ) throw new AssertionError( error );
+    }
+
+    public static ComputerState get( int id )
+    {
+        return lookup.get( id );
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/api/GameTest.java b/src/test/java/dan200/computercraft/ingame/api/GameTest.java
new file mode 100644
index 000000000..25707c14e
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/api/GameTest.java
@@ -0,0 +1,45 @@
+package dan200.computercraft.ingame.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A test which manipulates the game. This should applied on an instance function, and should accept a single
+ * {@link TestContext} argument.
+ *
+ * Tests may/should be written as Kotlin coroutines.
+ */
+@Retention( RetentionPolicy.RUNTIME )
+@Target( ElementType.METHOD )
+public @interface GameTest
+{
+    /**
+     * Maximum time the test can run, in ticks.
+     *
+     * @return The time the test can run in ticks.
+     */
+    int timeout() default 200;
+
+    /**
+     * Number of ticks to delay between building the structure and running the test code.
+     *
+     * @return Test delay in ticks.
+     */
+    long setup() default 5;
+
+    /**
+     * The batch to run tests in. This may be used to run tests which manipulate other bits of state.
+     *
+     * @return This test's batch.
+     */
+    String batch() default "default";
+
+    /**
+     * If this test must pass. When false, test failures do not cause a build failure.
+     *
+     * @return If this test is required.
+     */
+    boolean required() default true;
+}
diff --git a/src/test/java/dan200/computercraft/ingame/api/TestContext.java b/src/test/java/dan200/computercraft/ingame/api/TestContext.java
new file mode 100644
index 000000000..750497931
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/api/TestContext.java
@@ -0,0 +1,58 @@
+package dan200.computercraft.ingame.api;
+
+import net.minecraft.block.Block;
+import net.minecraft.block.Blocks;
+import net.minecraft.test.TestTracker;
+import net.minecraft.test.TestTrackerHolder;
+import net.minecraft.test.TestUtils;
+import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
+
+import java.lang.reflect.Method;
+
+/**
+ * The context a test is run within.
+ *
+ * @see TestExtensionsKt For additional test helper methods.
+ */
+public final class TestContext
+{
+    private final TestTracker tracker;
+
+    public TestContext( TestTrackerHolder holder )
+    {
+        this.tracker = ObfuscationReflectionHelper.getPrivateValue( TestTrackerHolder.class, holder, "field_229487_a_" );
+    }
+
+    public TestTracker getTracker()
+    {
+        return tracker;
+    }
+
+    public void ok()
+    {
+        try
+        {
+            Method finish = TestTracker.class.getDeclaredMethod( "finish" );
+            finish.setAccessible( true );
+            finish.invoke( tracker );
+
+            Method spawn = TestUtils.class.getDeclaredMethod( "spawnBeacon", TestTracker.class, Block.class );
+            spawn.setAccessible( true );
+            spawn.invoke( null, tracker, Blocks.LIME_STAINED_GLASS );
+        }
+        catch( ReflectiveOperationException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+    public void fail( Throwable e )
+    {
+        if( !tracker.isDone() ) tracker.fail( e );
+    }
+
+    public boolean isDone()
+    {
+        return tracker.isDone();
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt b/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt
new file mode 100644
index 000000000..963addb55
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt
@@ -0,0 +1,61 @@
+package dan200.computercraft.ingame.api
+
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.delay
+import net.minecraft.block.BlockState
+import net.minecraft.util.math.BlockPos
+
+/**
+ * Wait until a predicate matches (or the test times out).
+ */
+suspend inline fun TestContext.waitUntil(fn: () -> Boolean) {
+    while (true) {
+        if (isDone) throw CancellationException()
+        if (fn()) return
+
+        delay(50)
+    }
+}
+
+/**
+ * Wait until a computer has finished running and check it is OK.
+ */
+suspend fun TestContext.checkComputerOk(id: Int) {
+    waitUntil {
+        val computer = ComputerState.get(id)
+        computer != null && computer.isDone
+    }
+
+    ComputerState.get(id).check()
+}
+
+/**
+ * Sleep for a given number of ticks.
+ */
+suspend fun TestContext.sleep(ticks: Int = 1) {
+    val target = tracker.level.gameTime + ticks
+    waitUntil { tracker.level.gameTime >= target }
+}
+
+private fun TestContext.offset(pos: BlockPos): BlockPos = tracker.testPos.offset(pos.x, pos.y + 2, pos.z)
+
+/**
+ * Get a block within the test structure.
+ */
+fun TestContext.getBlock(pos: BlockPos): BlockState = tracker.level.getBlockState(offset(pos))
+
+/**
+ * Set a block within the test structure.
+ */
+fun TestContext.setBlock(pos: BlockPos, state: BlockState) {
+    tracker.level.setBlockAndUpdate(offset(pos), state)
+}
+
+/**
+ * Modify a block state within the test.
+ */
+fun TestContext.modifyBlock(pos: BlockPos, modify: (BlockState) -> BlockState) {
+    val level = tracker.level
+    val offset = offset(pos)
+    level.setBlockAndUpdate(offset, modify(level.getBlockState(offset)))
+}
diff --git a/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java b/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java
new file mode 100644
index 000000000..71c19d099
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java
@@ -0,0 +1,56 @@
+package dan200.computercraft.ingame.mod;
+
+import com.mojang.brigadier.CommandDispatcher;
+import dan200.computercraft.utils.Copier;
+import net.minecraft.command.CommandSource;
+import net.minecraft.server.MinecraftServer;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.choice;
+import static net.minecraft.command.Commands.literal;
+
+/**
+ * Helper commands for importing/exporting the computer directory.
+ */
+class CCTestCommand
+{
+    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() );
+                return 0;
+            } ) )
+        );
+    }
+
+    public static void importFiles( MinecraftServer server )
+    {
+        try
+        {
+            Copier.replicate( TestMod.sourceDir.resolve( "computers" ), server.getServerDirectory().toPath().resolve( "world/computercraft" ) );
+        }
+        catch( IOException e )
+        {
+            throw new UncheckedIOException( e );
+        }
+    }
+
+    public static void exportFiles( MinecraftServer server )
+    {
+        try
+        {
+            Copier.replicate( server.getServerDirectory().toPath().resolve( "world/computercraft" ), TestMod.sourceDir.resolve( "computers" ) );
+        }
+        catch( IOException e )
+        {
+            throw new UncheckedIOException( e );
+        }
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java b/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java
new file mode 100644
index 000000000..a8479dbf7
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java
@@ -0,0 +1,63 @@
+package dan200.computercraft.ingame.mod;
+
+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 dan200.computercraft.ingame.api.ComputerState;
+import dan200.computercraft.ingame.api.TestContext;
+import dan200.computercraft.ingame.api.TestExtensionsKt;
+import kotlin.coroutines.Continuation;
+
+/**
+ * API exposed to computers to help write tests.
+ *
+ * Note, we extend this API within startup file of computers (see {@code cctest.lua}).
+ *
+ * @see TestExtensionsKt#checkComputerOk(TestContext, int, Continuation) To check tests on the computer have passed.
+ */
+public class TestAPI extends ComputerState implements ILuaAPI
+{
+    private final int id;
+
+    TestAPI( IComputerSystem system )
+    {
+        id = system.getID();
+    }
+
+    @Override
+    public void startup()
+    {
+        done = false;
+        error = null;
+        lookup.put( id, this );
+    }
+
+    @Override
+    public void shutdown()
+    {
+        if( lookup.get( id ) == this ) lookup.remove( id );
+    }
+
+    @Override
+    public String[] getNames()
+    {
+        return new String[] { "test" };
+    }
+
+    @LuaFunction
+    public final void fail( String message ) throws LuaException
+    {
+        if( done ) throw new LuaException( "Cannot call fail/ok multiple times." );
+        done = true;
+        error = message;
+        throw new LuaException( message );
+    }
+
+    @LuaFunction
+    public final void ok() throws LuaException
+    {
+        if( done ) throw new LuaException( "Cannot call fail/ok multiple times." );
+        done = true;
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
new file mode 100644
index 000000000..ab740e5f1
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
@@ -0,0 +1,119 @@
+package dan200.computercraft.ingame.mod;
+
+import com.google.common.base.CaseFormat;
+import dan200.computercraft.ingame.api.GameTest;
+import net.minecraft.test.TestFunctionInfo;
+import net.minecraft.test.TestRegistry;
+import net.minecraft.test.TestTrackerHolder;
+import net.minecraftforge.fml.ModList;
+import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
+import net.minecraftforge.forgespi.language.ModFileScanData;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import java.util.function.Consumer;
+
+/**
+ * Loads methods annotated with {@link GameTest} and adds them to the {@link TestRegistry}. This involves some horrible
+ * reflection hacks, as Proguard makes many methods (and constructors) private.
+ */
+class TestLoader
+{
+    private static final Type gameTest = Type.getType( GameTest.class );
+    private static final Collection testFunctions = ObfuscationReflectionHelper.getPrivateValue( TestRegistry.class, null, "field_229526_a_" );
+    private static final Set testClassNames = ObfuscationReflectionHelper.getPrivateValue( TestRegistry.class, null, "field_229527_b_" );
+
+    public static void setup()
+    {
+        ModList.get().getAllScanData().stream()
+            .flatMap( x -> x.getAnnotations().stream() )
+            .filter( x -> x.getAnnotationType().equals( gameTest ) )
+            .forEach( TestLoader::loadTest );
+    }
+
+
+    private static void loadTest( ModFileScanData.AnnotationData annotation )
+    {
+        Class klass;
+        Method method;
+        try
+        {
+            klass = TestLoader.class.getClassLoader().loadClass( annotation.getClassType().getClassName() );
+
+            // We don't know the exact signature (could suspend or not), so find something with the correct descriptor instead.
+            String methodName = annotation.getMemberName();
+            method = Arrays.stream( klass.getMethods() ).filter( x -> (x.getName() + Type.getMethodDescriptor( x )).equals( methodName ) ).findFirst()
+                .orElseThrow( () -> new NoSuchMethodException( "No method " + annotation.getClassType().getClassName() + "." + annotation.getMemberName() ) );
+        }
+        catch( ReflectiveOperationException e )
+        {
+            throw new RuntimeException( e );
+        }
+
+        String className = CaseFormat.UPPER_CAMEL.to( CaseFormat.LOWER_UNDERSCORE, klass.getSimpleName() );
+        String name = className + "." + method.getName().toLowerCase().replace( ' ', '_' );
+
+        GameTest test = method.getAnnotation( GameTest.class );
+
+        TestMod.log.info( "Adding test " + name );
+        testClassNames.add( className );
+        testFunctions.add( createTestFunction(
+            test.batch(), name, name,
+            test.required(),
+            new TestRunner( name, method ),
+            test.timeout(),
+            test.setup()
+        ) );
+    }
+
+    private static TestFunctionInfo createTestFunction(
+        String batchName,
+        String testName,
+        String structureName,
+        boolean required,
+        Consumer function,
+        int maxTicks,
+        long setupTicks
+    )
+    {
+        try
+        {
+            Constructor ctor = TestFunctionInfo.class.getDeclaredConstructor();
+            ctor.setAccessible( true );
+
+            TestFunctionInfo func = ctor.newInstance();
+            setFinalField( func, "batchName", batchName );
+            setFinalField( func, "testName", testName );
+            setFinalField( func, "structureName", structureName );
+            setFinalField( func, "required", required );
+            setFinalField( func, "function", function );
+            setFinalField( func, "maxTicks", maxTicks );
+            setFinalField( func, "setupTicks", setupTicks );
+            return func;
+        }
+        catch( ReflectiveOperationException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+    private static void setFinalField( TestFunctionInfo func, String name, Object value ) throws ReflectiveOperationException
+    {
+        Field field = TestFunctionInfo.class.getDeclaredField( name );
+        if( (field.getModifiers() & Modifier.FINAL) != 0 )
+        {
+            Field modifiers = Field.class.getDeclaredField( "modifiers" );
+            modifiers.setAccessible( true );
+            modifiers.set( field, field.getModifiers() & ~Modifier.FINAL );
+        }
+
+        field.setAccessible( true );
+        field.set( func, value );
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestMod.java b/src/test/java/dan200/computercraft/ingame/mod/TestMod.java
new file mode 100644
index 000000000..65a7162c7
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestMod.java
@@ -0,0 +1,117 @@
+package dan200.computercraft.ingame.mod;
+
+import dan200.computercraft.api.ComputerCraftAPI;
+import net.minecraft.command.CommandSource;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.test.*;
+import net.minecraft.util.math.BlockPos;
+import net.minecraft.world.GameRules;
+import net.minecraft.world.gen.Heightmap;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.event.TickEvent;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
+import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
+import net.minecraftforge.fml.server.ServerLifecycleHooks;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+
+@Mod( TestMod.MOD_ID )
+public class TestMod
+{
+    public static final Path sourceDir = Paths.get( "../../src/test/server-files/" ).toAbsolutePath();
+
+    public static final String MOD_ID = "cctest";
+
+    public static final Logger log = LogManager.getLogger( MOD_ID );
+
+    private TestResultList runningTests = null;
+    private int countdown = 20;
+
+    public TestMod()
+    {
+        log.info( "CC: Test initialised" );
+        ComputerCraftAPI.registerAPIFactory( TestAPI::new );
+        TestLoader.setup();
+
+        StructureHelper.testStructuresDir = sourceDir.resolve( "structures" ).toString();
+
+        MinecraftForge.EVENT_BUS.addListener( ( FMLServerStartingEvent event ) -> {
+            log.info( "Starting server, registering command helpers." );
+            TestCommand.register( event.getCommandDispatcher() );
+            CCTestCommand.register( event.getCommandDispatcher() );
+        } );
+
+        MinecraftForge.EVENT_BUS.addListener( ( FMLServerStartedEvent event ) -> {
+            MinecraftServer server = event.getServer();
+            GameRules rules = server.getGameRules();
+            rules.getRule( GameRules.RULE_DAYLIGHT ).set( false, server );
+            rules.getRule( GameRules.RULE_WEATHER_CYCLE ).set( false, server );
+            rules.getRule( GameRules.RULE_DOMOBSPAWNING ).set( false, server );
+
+            log.info( "Cleaning up after last run" );
+            CommandSource source = server.createCommandSourceStack();
+            TestUtils.clearAllTests( source.getLevel(), getStart( source ), TestCollection.singleton, 200 );
+
+            log.info( "Importing files" );
+            CCTestCommand.importFiles( server );
+        } );
+
+        MinecraftForge.EVENT_BUS.addListener( ( TickEvent.ServerTickEvent event ) -> {
+            if( event.phase != TickEvent.Phase.START ) return;
+
+            // Let the world settle a bit before starting tests.
+            countdown--;
+            if( countdown == 0 && System.getProperty( "cctest.run", "false" ).equals( "true" ) ) startTests();
+
+            TestCollection.singleton.tick();
+            MainThread.INSTANCE.tick();
+
+            if( runningTests != null && runningTests.isDone() ) finishTests();
+        } );
+    }
+
+    private void startTests()
+    {
+        MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
+        CommandSource source = server.createCommandSourceStack();
+        Collection tests = TestRegistry.getAllTestFunctions();
+
+        log.info( "Running {} tests...", tests.size() );
+        runningTests = new TestResultList( TestUtils.runTests( tests, getStart( source ), source.getLevel(), TestCollection.singleton ) );
+    }
+
+    private void finishTests()
+    {
+        log.info( "Finished tests - {} were run", runningTests.getTotalCount() );
+        if( runningTests.hasFailedRequired() )
+        {
+            log.error( "{} required tests failed", runningTests.getFailedRequiredCount() );
+        }
+        if( runningTests.hasFailedOptional() )
+        {
+            log.warn( "{} optional tests failed", runningTests.getFailedOptionalCount() );
+        }
+
+        if( ServerLifecycleHooks.getCurrentServer().isDedicatedServer() )
+        {
+            log.info( "Stopping server." );
+
+            // We can't exit in the main thread, as Minecraft registers a shutdown hook which results
+            // in a deadlock. So we do this weird janky thing!
+            Thread thread = new Thread( () -> System.exit( runningTests.hasFailedRequired() ? 1 : 0 ) );
+            thread.setDaemon( true );
+            thread.start();
+        }
+    }
+
+    private BlockPos getStart( CommandSource source )
+    {
+        BlockPos pos = new BlockPos( source.getPosition() );
+        return new BlockPos( pos.getX(), source.getLevel().getHeightmapPos( Heightmap.Type.WORLD_SURFACE, pos ).getY(), pos.getZ() + 3 );
+    }
+}
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt b/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt
new file mode 100644
index 000000000..4c2c8be8f
--- /dev/null
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt
@@ -0,0 +1,62 @@
+package dan200.computercraft.ingame.mod
+
+import dan200.computercraft.ingame.api.TestContext
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import net.minecraft.test.TestCollection
+import net.minecraft.test.TestTrackerHolder
+import java.lang.reflect.Method
+import java.util.*
+import java.util.concurrent.ConcurrentLinkedDeque
+import java.util.function.Consumer
+import kotlin.coroutines.AbstractCoroutineContextElement
+import kotlin.coroutines.Continuation
+import kotlin.coroutines.ContinuationInterceptor
+import kotlin.coroutines.CoroutineContext
+import kotlin.reflect.full.callSuspend
+import kotlin.reflect.jvm.kotlinFunction
+
+internal class TestRunner(private val name: String, private val method: Method) : Consumer {
+    override fun accept(t: TestTrackerHolder) {
+        GlobalScope.launch(MainThread + CoroutineName(name)) {
+            val testContext = TestContext(t)
+            try {
+                val instance = method.declaringClass.newInstance()
+                val function = method.kotlinFunction;
+                if (function == null) {
+                    method.invoke(instance, testContext)
+                } else {
+                    function.callSuspend(instance, testContext)
+                }
+                testContext.ok()
+            } catch (e: Exception) {
+                testContext.fail(e)
+            }
+        }
+    }
+}
+
+/**
+ * A coroutine scope which runs everything on the main thread.
+ */
+internal object MainThread : AbstractCoroutineContextElement(ContinuationInterceptor), ContinuationInterceptor {
+    private val queue: Queue<() -> Unit> = ConcurrentLinkedDeque()
+
+    fun tick() {
+        while (true) {
+            val q = queue.poll() ?: break;
+            q.invoke()
+        }
+    }
+
+    override fun  interceptContinuation(continuation: Continuation): Continuation = MainThreadInterception(continuation)
+
+    private class MainThreadInterception(val cont: Continuation) : Continuation {
+        override val context: CoroutineContext get() = cont.context
+
+        override fun resumeWith(result: Result) {
+            queue.add { cont.resumeWith(result) }
+        }
+    }
+}
diff --git a/src/test/java/dan200/computercraft/utils/Copier.java b/src/test/java/dan200/computercraft/utils/Copier.java
new file mode 100644
index 000000000..fe9c94d35
--- /dev/null
+++ b/src/test/java/dan200/computercraft/utils/Copier.java
@@ -0,0 +1,49 @@
+package dan200.computercraft.utils;
+
+import com.google.common.io.MoreFiles;
+
+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;
+
+public class Copier extends SimpleFileVisitor
+{
+    private final Path sourceDir;
+    private final Path targetDir;
+
+    private Copier( Path sourceDir, Path targetDir )
+    {
+        this.sourceDir = sourceDir;
+        this.targetDir = targetDir;
+    }
+
+    @Override
+    public FileVisitResult visitFile( Path file, BasicFileAttributes attributes ) throws IOException
+    {
+        Path targetFile = targetDir.resolve( sourceDir.relativize( file ) );
+        Files.copy( file, targetFile );
+        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 ) );
+    }
+
+    public static void replicate( Path from, Path to ) throws IOException
+    {
+        if( Files.exists( to ) ) MoreFiles.deleteRecursively( to );
+        copy( from, to );
+    }
+}
diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml
new file mode 100644
index 000000000..520f3542f
--- /dev/null
+++ b/src/test/resources/META-INF/mods.toml
@@ -0,0 +1,18 @@
+modLoader="javafml"
+loaderVersion="[30,)"
+
+issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues"
+displayURL="https://github.com/SquidDev-CC/CC-Tweaked"
+logoFile="pack.png"
+
+credits="Created by Daniel Ratcliffe (@DanTwoHundred)"
+authors="Daniel Ratcliffe, Aaron Mills, SquidDev"
+
+[[mods]]
+modId="cctest"
+version="1.0.0"
+displayName="CC: Tweaked test framework"
+description='''
+A test framework for ensuring CC: Tweaked works correctly.
+'''
+
diff --git a/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua b/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua
new file mode 100644
index 000000000..1b4f6d778
--- /dev/null
+++ b/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua
@@ -0,0 +1,17 @@
+--- 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
diff --git a/src/test/resources/pack.mcmeta b/src/test/resources/pack.mcmeta
new file mode 100755
index 000000000..0958f2f90
--- /dev/null
+++ b/src/test/resources/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+    "pack": {
+        "pack_format": 4,
+        "description": "CC: Test"
+    }
+}
diff --git a/src/test/server-files/computers/computer/1/startup.lua b/src/test/server-files/computers/computer/1/startup.lua
new file mode 100644
index 000000000..ac2e8f8f5
--- /dev/null
+++ b/src/test/server-files/computers/computer/1/startup.lua
@@ -0,0 +1,5 @@
+test.eq("modem", peripheral.getType("right"), "Starts with a modem")
+turtle.equipRight()
+test.eq("drive", peripheral.getType("right"), "Unequipping gives a drive")
+
+test.ok()
diff --git a/src/test/server-files/computers/ids.json b/src/test/server-files/computers/ids.json
new file mode 100644
index 000000000..234976137
--- /dev/null
+++ b/src/test/server-files/computers/ids.json
@@ -0,0 +1,3 @@
+{
+  "computer": 2
+}
diff --git a/src/test/server-files/eula.txt b/src/test/server-files/eula.txt
new file mode 100644
index 000000000..e6765d6c9
--- /dev/null
+++ b/src/test/server-files/eula.txt
@@ -0,0 +1,2 @@
+# Automatically generated EULA. Please don't use this for a real server.
+eula=true
diff --git a/src/test/server-files/server.properties b/src/test/server-files/server.properties
new file mode 100644
index 000000000..c7efd2230
--- /dev/null
+++ b/src/test/server-files/server.properties
@@ -0,0 +1,46 @@
+#Minecraft server properties
+#Fri Jan 08 18:54:30 GMT 2021
+allow-flight=false
+allow-nether=true
+broadcast-console-to-ops=true
+broadcast-rcon-to-ops=true
+difficulty=easy
+enable-command-block=true
+enable-query=false
+enable-rcon=false
+enforce-whitelist=false
+force-gamemode=false
+function-permission-level=2
+gamemode=creative
+generate-structures=true
+generator-settings=
+hardcore=false
+level-name=world
+level-seed=
+level-type=flat
+max-build-height=256
+max-players=20
+max-tick-time=60000
+max-world-size=29999984
+motd=A testing server
+network-compression-threshold=256
+online-mode=false
+op-permission-level=4
+player-idle-timeout=0
+prevent-proxy-connections=false
+pvp=true
+query.port=25565
+rcon.password=
+rcon.port=25575
+resource-pack=
+resource-pack-sha1=
+server-ip=
+server-port=25565
+snooper-enabled=true
+spawn-animals=true
+spawn-monsters=true
+spawn-npcs=true
+spawn-protection=16
+use-native-transport=true
+view-distance=10
+white-list=false
diff --git a/src/test/server-files/structures/computer_test.no_through_signal.snbt b/src/test/server-files/structures/computer_test.no_through_signal.snbt
new file mode 100644
index 000000000..1d66e7b51
--- /dev/null
+++ b/src/test/server-files/structures/computer_test.no_through_signal.snbt
@@ -0,0 +1,560 @@
+{
+    size: [5, 5, 5],
+    entities: [],
+    blocks: [
+        {
+            pos: [0, 0, 0],
+            state: 0
+        },
+        {
+            pos: [1, 0, 0],
+            state: 0
+        },
+        {
+            pos: [2, 0, 0],
+            state: 0
+        },
+        {
+            pos: [3, 0, 0],
+            state: 0
+        },
+        {
+            pos: [4, 0, 0],
+            state: 0
+        },
+        {
+            pos: [0, 0, 1],
+            state: 0
+        },
+        {
+            pos: [1, 0, 1],
+            state: 0
+        },
+        {
+            pos: [2, 0, 1],
+            state: 0
+        },
+        {
+            pos: [3, 0, 1],
+            state: 0
+        },
+        {
+            pos: [4, 0, 1],
+            state: 0
+        },
+        {
+            pos: [0, 0, 2],
+            state: 0
+        },
+        {
+            pos: [1, 0, 2],
+            state: 0
+        },
+        {
+            pos: [2, 0, 2],
+            state: 0
+        },
+        {
+            pos: [3, 0, 2],
+            state: 0
+        },
+        {
+            pos: [4, 0, 2],
+            state: 0
+        },
+        {
+            pos: [0, 0, 3],
+            state: 0
+        },
+        {
+            pos: [1, 0, 3],
+            state: 0
+        },
+        {
+            pos: [2, 0, 3],
+            state: 0
+        },
+        {
+            pos: [3, 0, 3],
+            state: 0
+        },
+        {
+            pos: [4, 0, 3],
+            state: 0
+        },
+        {
+            pos: [0, 0, 4],
+            state: 0
+        },
+        {
+            pos: [1, 0, 4],
+            state: 0
+        },
+        {
+            pos: [2, 0, 4],
+            state: 0
+        },
+        {
+            pos: [3, 0, 4],
+            state: 0
+        },
+        {
+            pos: [4, 0, 4],
+            state: 0
+        },
+        {
+            pos: [2, 1, 4],
+            state: 1
+        },
+        {
+            nbt: {
+                id: "computercraft:computer_advanced",
+                ComputerId: 2,
+                On: 1b
+            },
+            pos: [2, 1, 2],
+            state: 2
+        },
+        {
+            pos: [0, 1, 0],
+            state: 3
+        },
+        {
+            pos: [1, 1, 0],
+            state: 3
+        },
+        {
+            pos: [2, 1, 0],
+            state: 4
+        },
+        {
+            pos: [3, 1, 0],
+            state: 3
+        },
+        {
+            pos: [4, 1, 0],
+            state: 3
+        },
+        {
+            pos: [0, 2, 0],
+            state: 3
+        },
+        {
+            pos: [1, 2, 0],
+            state: 3
+        },
+        {
+            pos: [2, 2, 0],
+            state: 3
+        },
+        {
+            pos: [3, 2, 0],
+            state: 3
+        },
+        {
+            pos: [4, 2, 0],
+            state: 3
+        },
+        {
+            pos: [0, 3, 0],
+            state: 3
+        },
+        {
+            pos: [1, 3, 0],
+            state: 3
+        },
+        {
+            pos: [2, 3, 0],
+            state: 3
+        },
+        {
+            pos: [3, 3, 0],
+            state: 3
+        },
+        {
+            pos: [4, 3, 0],
+            state: 3
+        },
+        {
+            pos: [0, 4, 0],
+            state: 3
+        },
+        {
+            pos: [1, 4, 0],
+            state: 3
+        },
+        {
+            pos: [2, 4, 0],
+            state: 3
+        },
+        {
+            pos: [3, 4, 0],
+            state: 3
+        },
+        {
+            pos: [4, 4, 0],
+            state: 3
+        },
+        {
+            pos: [0, 1, 1],
+            state: 3
+        },
+        {
+            pos: [1, 1, 1],
+            state: 3
+        },
+        {
+            pos: [2, 1, 1],
+            state: 5
+        },
+        {
+            pos: [3, 1, 1],
+            state: 3
+        },
+        {
+            pos: [4, 1, 1],
+            state: 3
+        },
+        {
+            pos: [0, 2, 1],
+            state: 3
+        },
+        {
+            pos: [1, 2, 1],
+            state: 3
+        },
+        {
+            pos: [2, 2, 1],
+            state: 3
+        },
+        {
+            pos: [3, 2, 1],
+            state: 3
+        },
+        {
+            pos: [4, 2, 1],
+            state: 3
+        },
+        {
+            pos: [0, 3, 1],
+            state: 3
+        },
+        {
+            pos: [1, 3, 1],
+            state: 3
+        },
+        {
+            pos: [2, 3, 1],
+            state: 3
+        },
+        {
+            pos: [3, 3, 1],
+            state: 3
+        },
+        {
+            pos: [4, 3, 1],
+            state: 3
+        },
+        {
+            pos: [0, 4, 1],
+            state: 3
+        },
+        {
+            pos: [1, 4, 1],
+            state: 3
+        },
+        {
+            pos: [2, 4, 1],
+            state: 3
+        },
+        {
+            pos: [3, 4, 1],
+            state: 3
+        },
+        {
+            pos: [4, 4, 1],
+            state: 3
+        },
+        {
+            pos: [0, 1, 2],
+            state: 3
+        },
+        {
+            pos: [1, 1, 2],
+            state: 3
+        },
+        {
+            pos: [3, 1, 2],
+            state: 3
+        },
+        {
+            pos: [4, 1, 2],
+            state: 3
+        },
+        {
+            pos: [0, 2, 2],
+            state: 3
+        },
+        {
+            pos: [1, 2, 2],
+            state: 3
+        },
+        {
+            pos: [2, 2, 2],
+            state: 3
+        },
+        {
+            pos: [3, 2, 2],
+            state: 3
+        },
+        {
+            pos: [4, 2, 2],
+            state: 3
+        },
+        {
+            pos: [0, 3, 2],
+            state: 3
+        },
+        {
+            pos: [1, 3, 2],
+            state: 3
+        },
+        {
+            pos: [2, 3, 2],
+            state: 3
+        },
+        {
+            pos: [3, 3, 2],
+            state: 3
+        },
+        {
+            pos: [4, 3, 2],
+            state: 3
+        },
+        {
+            pos: [0, 4, 2],
+            state: 3
+        },
+        {
+            pos: [1, 4, 2],
+            state: 3
+        },
+        {
+            pos: [2, 4, 2],
+            state: 3
+        },
+        {
+            pos: [3, 4, 2],
+            state: 3
+        },
+        {
+            pos: [4, 4, 2],
+            state: 3
+        },
+        {
+            pos: [0, 1, 3],
+            state: 3
+        },
+        {
+            pos: [1, 1, 3],
+            state: 3
+        },
+        {
+            pos: [2, 1, 3],
+            state: 6
+        },
+        {
+            pos: [3, 1, 3],
+            state: 3
+        },
+        {
+            pos: [4, 1, 3],
+            state: 3
+        },
+        {
+            pos: [0, 2, 3],
+            state: 3
+        },
+        {
+            pos: [1, 2, 3],
+            state: 3
+        },
+        {
+            pos: [2, 2, 3],
+            state: 3
+        },
+        {
+            pos: [3, 2, 3],
+            state: 3
+        },
+        {
+            pos: [4, 2, 3],
+            state: 3
+        },
+        {
+            pos: [0, 3, 3],
+            state: 3
+        },
+        {
+            pos: [1, 3, 3],
+            state: 3
+        },
+        {
+            pos: [2, 3, 3],
+            state: 3
+        },
+        {
+            pos: [3, 3, 3],
+            state: 3
+        },
+        {
+            pos: [4, 3, 3],
+            state: 3
+        },
+        {
+            pos: [0, 4, 3],
+            state: 3
+        },
+        {
+            pos: [1, 4, 3],
+            state: 3
+        },
+        {
+            pos: [2, 4, 3],
+            state: 3
+        },
+        {
+            pos: [3, 4, 3],
+            state: 3
+        },
+        {
+            pos: [4, 4, 3],
+            state: 3
+        },
+        {
+            pos: [0, 1, 4],
+            state: 3
+        },
+        {
+            pos: [1, 1, 4],
+            state: 3
+        },
+        {
+            pos: [3, 1, 4],
+            state: 3
+        },
+        {
+            pos: [4, 1, 4],
+            state: 3
+        },
+        {
+            pos: [0, 2, 4],
+            state: 3
+        },
+        {
+            pos: [1, 2, 4],
+            state: 3
+        },
+        {
+            pos: [2, 2, 4],
+            state: 3
+        },
+        {
+            pos: [3, 2, 4],
+            state: 3
+        },
+        {
+            pos: [4, 2, 4],
+            state: 3
+        },
+        {
+            pos: [0, 3, 4],
+            state: 3
+        },
+        {
+            pos: [1, 3, 4],
+            state: 3
+        },
+        {
+            pos: [2, 3, 4],
+            state: 3
+        },
+        {
+            pos: [3, 3, 4],
+            state: 3
+        },
+        {
+            pos: [4, 3, 4],
+            state: 3
+        },
+        {
+            pos: [0, 4, 4],
+            state: 3
+        },
+        {
+            pos: [1, 4, 4],
+            state: 3
+        },
+        {
+            pos: [2, 4, 4],
+            state: 3
+        },
+        {
+            pos: [3, 4, 4],
+            state: 3
+        },
+        {
+            pos: [4, 4, 4],
+            state: 3
+        }
+    ],
+    palette: [
+        {
+            Name: "minecraft:polished_andesite"
+        },
+        {
+            Properties: {
+                lit: "false"
+            },
+            Name: "minecraft:redstone_lamp"
+        },
+        {
+            Properties: {
+                facing: "north",
+                state: "blinking"
+            },
+            Name: "computercraft:computer_advanced"
+        },
+        {
+            Name: "minecraft:air"
+        },
+        {
+            Properties: {
+                face: "floor",
+                powered: "false",
+                facing: "south"
+            },
+            Name: "minecraft:lever"
+        },
+        {
+            Properties: {
+                delay: "1",
+                powered: "false",
+                facing: "north",
+                locked: "false"
+            },
+            Name: "minecraft:repeater"
+        },
+        {
+            Properties: {
+                east: "none",
+                south: "none",
+                north: "side",
+                west: "none",
+                power: "0"
+            },
+            Name: "minecraft:redstone_wire"
+        }
+    ],
+    DataVersion: 2230
+}
diff --git a/src/test/server-files/structures/turtle_test.unequip_refreshes_peripheral.snbt b/src/test/server-files/structures/turtle_test.unequip_refreshes_peripheral.snbt
new file mode 100644
index 000000000..ff9613efd
--- /dev/null
+++ b/src/test/server-files/structures/turtle_test.unequip_refreshes_peripheral.snbt
@@ -0,0 +1,550 @@
+{
+    size: [5, 5, 5],
+    entities: [],
+    blocks: [
+        {
+            pos: [0, 0, 0],
+            state: 0
+        },
+        {
+            pos: [1, 0, 0],
+            state: 0
+        },
+        {
+            pos: [2, 0, 0],
+            state: 0
+        },
+        {
+            pos: [3, 0, 0],
+            state: 0
+        },
+        {
+            pos: [4, 0, 0],
+            state: 0
+        },
+        {
+            pos: [0, 0, 1],
+            state: 0
+        },
+        {
+            pos: [1, 0, 1],
+            state: 0
+        },
+        {
+            pos: [2, 0, 1],
+            state: 0
+        },
+        {
+            pos: [3, 0, 1],
+            state: 0
+        },
+        {
+            pos: [4, 0, 1],
+            state: 0
+        },
+        {
+            pos: [0, 0, 2],
+            state: 0
+        },
+        {
+            pos: [1, 0, 2],
+            state: 0
+        },
+        {
+            pos: [2, 0, 2],
+            state: 0
+        },
+        {
+            pos: [3, 0, 2],
+            state: 0
+        },
+        {
+            pos: [4, 0, 2],
+            state: 0
+        },
+        {
+            pos: [0, 0, 3],
+            state: 0
+        },
+        {
+            pos: [1, 0, 3],
+            state: 0
+        },
+        {
+            pos: [2, 0, 3],
+            state: 0
+        },
+        {
+            pos: [3, 0, 3],
+            state: 0
+        },
+        {
+            pos: [4, 0, 3],
+            state: 0
+        },
+        {
+            pos: [0, 0, 4],
+            state: 0
+        },
+        {
+            pos: [1, 0, 4],
+            state: 0
+        },
+        {
+            pos: [2, 0, 4],
+            state: 0
+        },
+        {
+            pos: [3, 0, 4],
+            state: 0
+        },
+        {
+            pos: [4, 0, 4],
+            state: 0
+        },
+        {
+            nbt: {
+                id: "computercraft:disk_drive"
+            },
+            pos: [1, 1, 2],
+            state: 1
+        },
+        {
+            nbt: {
+                Owner: {
+                    UpperId: 4039158846114182220L,
+                    LowerId: -6876936588741668278L,
+                    Name: "Dev"
+                },
+                RightUpgrade: "computercraft:wireless_modem_normal",
+                Fuel: 0,
+                Label: "Unequip refreshes peripheral",
+                Slot: 0,
+                Items: [],
+                id: "computercraft:turtle_normal",
+                RightUpgradeNbt: {
+                    active: 0b
+                },
+                ComputerId: 1,
+                On: 1b
+            },
+            pos: [2, 1, 2],
+            state: 2
+        },
+        {
+            pos: [0, 1, 0],
+            state: 3
+        },
+        {
+            pos: [1, 1, 0],
+            state: 3
+        },
+        {
+            pos: [2, 1, 0],
+            state: 3
+        },
+        {
+            pos: [3, 1, 0],
+            state: 3
+        },
+        {
+            pos: [4, 1, 0],
+            state: 3
+        },
+        {
+            pos: [0, 2, 0],
+            state: 3
+        },
+        {
+            pos: [1, 2, 0],
+            state: 3
+        },
+        {
+            pos: [2, 2, 0],
+            state: 3
+        },
+        {
+            pos: [3, 2, 0],
+            state: 3
+        },
+        {
+            pos: [4, 2, 0],
+            state: 3
+        },
+        {
+            pos: [0, 3, 0],
+            state: 3
+        },
+        {
+            pos: [1, 3, 0],
+            state: 3
+        },
+        {
+            pos: [2, 3, 0],
+            state: 3
+        },
+        {
+            pos: [3, 3, 0],
+            state: 3
+        },
+        {
+            pos: [4, 3, 0],
+            state: 3
+        },
+        {
+            pos: [0, 4, 0],
+            state: 3
+        },
+        {
+            pos: [1, 4, 0],
+            state: 3
+        },
+        {
+            pos: [2, 4, 0],
+            state: 3
+        },
+        {
+            pos: [3, 4, 0],
+            state: 3
+        },
+        {
+            pos: [4, 4, 0],
+            state: 3
+        },
+        {
+            pos: [0, 1, 1],
+            state: 3
+        },
+        {
+            pos: [1, 1, 1],
+            state: 3
+        },
+        {
+            pos: [2, 1, 1],
+            state: 3
+        },
+        {
+            pos: [3, 1, 1],
+            state: 3
+        },
+        {
+            pos: [4, 1, 1],
+            state: 3
+        },
+        {
+            pos: [0, 2, 1],
+            state: 3
+        },
+        {
+            pos: [1, 2, 1],
+            state: 3
+        },
+        {
+            pos: [2, 2, 1],
+            state: 3
+        },
+        {
+            pos: [3, 2, 1],
+            state: 3
+        },
+        {
+            pos: [4, 2, 1],
+            state: 3
+        },
+        {
+            pos: [0, 3, 1],
+            state: 3
+        },
+        {
+            pos: [1, 3, 1],
+            state: 3
+        },
+        {
+            pos: [2, 3, 1],
+            state: 3
+        },
+        {
+            pos: [3, 3, 1],
+            state: 3
+        },
+        {
+            pos: [4, 3, 1],
+            state: 3
+        },
+        {
+            pos: [0, 4, 1],
+            state: 3
+        },
+        {
+            pos: [1, 4, 1],
+            state: 3
+        },
+        {
+            pos: [2, 4, 1],
+            state: 3
+        },
+        {
+            pos: [3, 4, 1],
+            state: 3
+        },
+        {
+            pos: [4, 4, 1],
+            state: 3
+        },
+        {
+            pos: [0, 1, 2],
+            state: 3
+        },
+        {
+            pos: [3, 1, 2],
+            state: 3
+        },
+        {
+            pos: [4, 1, 2],
+            state: 3
+        },
+        {
+            pos: [0, 2, 2],
+            state: 3
+        },
+        {
+            pos: [1, 2, 2],
+            state: 3
+        },
+        {
+            pos: [2, 2, 2],
+            state: 3
+        },
+        {
+            pos: [3, 2, 2],
+            state: 3
+        },
+        {
+            pos: [4, 2, 2],
+            state: 3
+        },
+        {
+            pos: [0, 3, 2],
+            state: 3
+        },
+        {
+            pos: [1, 3, 2],
+            state: 3
+        },
+        {
+            pos: [2, 3, 2],
+            state: 3
+        },
+        {
+            pos: [3, 3, 2],
+            state: 3
+        },
+        {
+            pos: [4, 3, 2],
+            state: 3
+        },
+        {
+            pos: [0, 4, 2],
+            state: 3
+        },
+        {
+            pos: [1, 4, 2],
+            state: 3
+        },
+        {
+            pos: [2, 4, 2],
+            state: 3
+        },
+        {
+            pos: [3, 4, 2],
+            state: 3
+        },
+        {
+            pos: [4, 4, 2],
+            state: 3
+        },
+        {
+            pos: [0, 1, 3],
+            state: 3
+        },
+        {
+            pos: [1, 1, 3],
+            state: 3
+        },
+        {
+            pos: [2, 1, 3],
+            state: 3
+        },
+        {
+            pos: [3, 1, 3],
+            state: 3
+        },
+        {
+            pos: [4, 1, 3],
+            state: 3
+        },
+        {
+            pos: [0, 2, 3],
+            state: 3
+        },
+        {
+            pos: [1, 2, 3],
+            state: 3
+        },
+        {
+            pos: [2, 2, 3],
+            state: 3
+        },
+        {
+            pos: [3, 2, 3],
+            state: 3
+        },
+        {
+            pos: [4, 2, 3],
+            state: 3
+        },
+        {
+            pos: [0, 3, 3],
+            state: 3
+        },
+        {
+            pos: [1, 3, 3],
+            state: 3
+        },
+        {
+            pos: [2, 3, 3],
+            state: 3
+        },
+        {
+            pos: [3, 3, 3],
+            state: 3
+        },
+        {
+            pos: [4, 3, 3],
+            state: 3
+        },
+        {
+            pos: [0, 4, 3],
+            state: 3
+        },
+        {
+            pos: [1, 4, 3],
+            state: 3
+        },
+        {
+            pos: [2, 4, 3],
+            state: 3
+        },
+        {
+            pos: [3, 4, 3],
+            state: 3
+        },
+        {
+            pos: [4, 4, 3],
+            state: 3
+        },
+        {
+            pos: [0, 1, 4],
+            state: 3
+        },
+        {
+            pos: [1, 1, 4],
+            state: 3
+        },
+        {
+            pos: [2, 1, 4],
+            state: 3
+        },
+        {
+            pos: [3, 1, 4],
+            state: 3
+        },
+        {
+            pos: [4, 1, 4],
+            state: 3
+        },
+        {
+            pos: [0, 2, 4],
+            state: 3
+        },
+        {
+            pos: [1, 2, 4],
+            state: 3
+        },
+        {
+            pos: [2, 2, 4],
+            state: 3
+        },
+        {
+            pos: [3, 2, 4],
+            state: 3
+        },
+        {
+            pos: [4, 2, 4],
+            state: 3
+        },
+        {
+            pos: [0, 3, 4],
+            state: 3
+        },
+        {
+            pos: [1, 3, 4],
+            state: 3
+        },
+        {
+            pos: [2, 3, 4],
+            state: 3
+        },
+        {
+            pos: [3, 3, 4],
+            state: 3
+        },
+        {
+            pos: [4, 3, 4],
+            state: 3
+        },
+        {
+            pos: [0, 4, 4],
+            state: 3
+        },
+        {
+            pos: [1, 4, 4],
+            state: 3
+        },
+        {
+            pos: [2, 4, 4],
+            state: 3
+        },
+        {
+            pos: [3, 4, 4],
+            state: 3
+        },
+        {
+            pos: [4, 4, 4],
+            state: 3
+        }
+    ],
+    palette: [
+        {
+            Name: "minecraft:polished_andesite"
+        },
+        {
+            Properties: {
+                facing: "north",
+                state: "empty"
+            },
+            Name: "computercraft:disk_drive"
+        },
+        {
+            Properties: {
+                waterlogged: "false",
+                facing: "south"
+            },
+            Name: "computercraft:turtle_normal"
+        },
+        {
+            Name: "minecraft:air"
+        }
+    ],
+    DataVersion: 2230
+}

From 88f5b20353d7189e6a9195e1fa668b6ad140047f Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 20:00:15 +0000
Subject: [PATCH 421/711] Fix checkstyle and licence checks

Of all the things to fail in this absurdy complex change >_>.
---
 .../dan200/computercraft/ingame/api/ComputerState.java     | 5 +++++
 .../java/dan200/computercraft/ingame/api/GameTest.java     | 5 +++++
 .../java/dan200/computercraft/ingame/api/TestContext.java  | 5 +++++
 .../dan200/computercraft/ingame/mod/CCTestCommand.java     | 5 +++++
 src/test/java/dan200/computercraft/ingame/mod/TestAPI.java | 5 +++++
 .../java/dan200/computercraft/ingame/mod/TestLoader.java   | 5 +++++
 src/test/java/dan200/computercraft/ingame/mod/TestMod.java | 5 +++++
 src/test/java/dan200/computercraft/utils/Copier.java       | 7 ++++++-
 8 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/src/test/java/dan200/computercraft/ingame/api/ComputerState.java b/src/test/java/dan200/computercraft/ingame/api/ComputerState.java
index 311945d8b..fbb082815 100644
--- a/src/test/java/dan200/computercraft/ingame/api/ComputerState.java
+++ b/src/test/java/dan200/computercraft/ingame/api/ComputerState.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.api;
 
 import dan200.computercraft.ingame.mod.TestAPI;
diff --git a/src/test/java/dan200/computercraft/ingame/api/GameTest.java b/src/test/java/dan200/computercraft/ingame/api/GameTest.java
index 25707c14e..ff9e80c2b 100644
--- a/src/test/java/dan200/computercraft/ingame/api/GameTest.java
+++ b/src/test/java/dan200/computercraft/ingame/api/GameTest.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.api;
 
 import java.lang.annotation.ElementType;
diff --git a/src/test/java/dan200/computercraft/ingame/api/TestContext.java b/src/test/java/dan200/computercraft/ingame/api/TestContext.java
index 750497931..33bbfece6 100644
--- a/src/test/java/dan200/computercraft/ingame/api/TestContext.java
+++ b/src/test/java/dan200/computercraft/ingame/api/TestContext.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.api;
 
 import net.minecraft.block.Block;
diff --git a/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java b/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java
index 71c19d099..a5cf0a958 100644
--- a/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java
+++ b/src/test/java/dan200/computercraft/ingame/mod/CCTestCommand.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.mod;
 
 import com.mojang.brigadier.CommandDispatcher;
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java b/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java
index a8479dbf7..066ffdf65 100644
--- a/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestAPI.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.mod;
 
 import dan200.computercraft.api.lua.IComputerSystem;
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
index ab740e5f1..5d7d7a6fc 100644
--- a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.mod;
 
 import com.google.common.base.CaseFormat;
diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestMod.java b/src/test/java/dan200/computercraft/ingame/mod/TestMod.java
index 65a7162c7..2cdf01862 100644
--- a/src/test/java/dan200/computercraft/ingame/mod/TestMod.java
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestMod.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.ingame.mod;
 
 import dan200.computercraft.api.ComputerCraftAPI;
diff --git a/src/test/java/dan200/computercraft/utils/Copier.java b/src/test/java/dan200/computercraft/utils/Copier.java
index fe9c94d35..5759e026d 100644
--- a/src/test/java/dan200/computercraft/utils/Copier.java
+++ b/src/test/java/dan200/computercraft/utils/Copier.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.utils;
 
 import com.google.common.io.MoreFiles;
@@ -9,7 +14,7 @@ import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
 
-public class Copier extends SimpleFileVisitor
+public final class Copier extends SimpleFileVisitor
 {
     private final Path sourceDir;
     private final Path targetDir;

From f78e24f9a0d3fa0b8e370d49aee1959806a8cc87 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 20:12:13 +0000
Subject: [PATCH 422/711] Use UnsafeHacks to construct the test function info

This has been stripped (only in CI on 1.15, always in 1.16) so blows up
when we try to call it.
---
 .../java/dan200/computercraft/ingame/mod/TestLoader.java   | 7 ++-----
 src/test/resources/META-INF/mods.toml                      | 1 -
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
index 5d7d7a6fc..a73829688 100644
--- a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
+++ b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java
@@ -12,10 +12,10 @@ import net.minecraft.test.TestRegistry;
 import net.minecraft.test.TestTrackerHolder;
 import net.minecraftforge.fml.ModList;
 import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
+import net.minecraftforge.fml.unsafe.UnsafeHacks;
 import net.minecraftforge.forgespi.language.ModFileScanData;
 import org.objectweb.asm.Type;
 
-import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -89,10 +89,7 @@ class TestLoader
     {
         try
         {
-            Constructor ctor = TestFunctionInfo.class.getDeclaredConstructor();
-            ctor.setAccessible( true );
-
-            TestFunctionInfo func = ctor.newInstance();
+            TestFunctionInfo func = UnsafeHacks.newInstance( TestFunctionInfo.class );
             setFinalField( func, "batchName", batchName );
             setFinalField( func, "testName", testName );
             setFinalField( func, "structureName", structureName );
diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml
index 520f3542f..819c841a4 100644
--- a/src/test/resources/META-INF/mods.toml
+++ b/src/test/resources/META-INF/mods.toml
@@ -15,4 +15,3 @@ displayName="CC: Tweaked test framework"
 description='''
 A test framework for ensuring CC: Tweaked works correctly.
 '''
-

From b838efedd2d552cb02665425ea86c0a475c59cf7 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 9 Jan 2021 20:17:32 +0000
Subject: [PATCH 423/711] Retry the prepare step one time

Hopefully ensures failed assets assets don't entirely break the build.
---
 .github/workflows/main-ci.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml
index df76fca79..196c65915 100644
--- a/.github/workflows/main-ci.yml
+++ b/.github/workflows/main-ci.yml
@@ -29,6 +29,7 @@ jobs:
     - name: Run in-game tests
       run: |
         ./gradlew setupServer --no-daemon
+        ./gradlew prepareRunTestServerRun --no-daemon || ./gradlew prepareRunTestServerRun --no-daemon
         ./gradlew runTestServerRun --no-daemon
 
     - name: Upload Jar

From 1f84480a80677cfaaf19d319290f5b44635eba47 Mon Sep 17 00:00:00 2001
From: Wojbie 
Date: Mon, 11 Jan 2021 22:59:29 +0100
Subject: [PATCH 424/711] Make rightAlt only close menu, never open it. (#672)

Fixes #669
---
 .../data/computercraft/lua/rom/programs/edit.lua         | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
index 8656798df..78c6f5ca9 100644
--- a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
+++ b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua
@@ -687,7 +687,7 @@ while bRunning do
 
             end
 
-        elseif param == keys.leftCtrl or param == keys.rightCtrl or param == keys.rightAlt then
+        elseif param == keys.leftCtrl or param == keys.rightCtrl then
             -- Menu toggle
             bMenu = not bMenu
             if bMenu then
@@ -696,7 +696,12 @@ while bRunning do
                 term.setCursorBlink(true)
             end
             redrawMenu()
-
+        elseif param == keys.rightAlt then
+            if bMenu then
+                bMenu = false
+                term.setCursorBlink(true)
+                redrawMenu()
+            end
         end
 
     elseif sEvent == "char" then

From 1255bd00fd21247a50046020d7d9a396f66bc6bd Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 13 Jan 2021 22:10:44 +0000
Subject: [PATCH 425/711] Fix mounts being usable after a disk is ejected

This probably fails "responsible disclosure", but it's not an RCE and
frankly the whole bug is utterly hilarious so here we are...

It's possible to open a file on a disk drive and continue to read/write
to them after the disk has been removed:

    local disk = peripheral.find("drive")
    local input = fs.open(fs.combine(disk.getMountPath(), "stream"), "rb")
    local output = fs.open(fs.combine(disk.getMountPath(), "stream"), "wb")
    disk.ejectDisk()

    -- input/output can still be interacted with.

This is pretty amusing, as now it allows us to move the disk somewhere
else and repeat - we've now got a private tunnel which two computers can
use to communicate.

Fixing this is intuitively quite simple - just close any open files
belonging to this mount. However, this is where things get messy thanks
to the wonderful joy of how CC's streams are handled.

As things stand, the filesystem effectively does the following flow::
 - There is a function `open : String -> Channel' (file modes are
   irrelevant here).

 - Once a file is opened, we transform it into some . This is, for instance, a BufferedReader.

 - We generate a "token" (i.e. FileSystemWrapper), which we generate
   a week reference to and map it to a tuple of our Channel and T. If
   this token is ever garbage collected (someone forgot to call close()
   on a file), then we close our T and Channel.

 - This token and T are returned to the calling function, which then
   constructs a Lua object.

The problem here is that if we close the underlying Channel+T before the
Lua object calls .close(), then it won't know the underlying channel is
closed, and you get some pretty ugly errors (e.g. "Stream Closed"). So
we've moved the "is open" state into the FileSystemWrapper.

The whole system is incredibly complex at this point, and I'd really
like to clean it up. Ideally we could treat the HandleGeneric as the
token instead - this way we could potentially also clean up
FileSystemWrapperMount.

BBut something to play with in the future, and not when it's 10:30pm.

---

All this wall of text, and this isn't the only bug I've found with disks
today :/.
---
 .../apis/handles/BinaryReadableHandle.java    |  9 ++--
 .../apis/handles/BinaryWritableHandle.java    |  9 ++--
 .../apis/handles/EncodedReadableHandle.java   |  5 ++-
 .../apis/handles/EncodedWritableHandle.java   |  3 +-
 .../core/apis/handles/HandleGeneric.java      | 18 ++++----
 .../core/filesystem/ChannelWrapper.java       |  2 +-
 .../core/filesystem/FileSystem.java           | 42 ++++++++++++-------
 .../core/filesystem/FileSystemWrapper.java    | 22 +++++++++-
 .../core/filesystem/TrackingCloseable.java    | 39 +++++++++++++++++
 .../core/filesystem/FileSystemTest.java       | 28 ++++++++++++-
 10 files changed, 137 insertions(+), 40 deletions(-)
 create mode 100644 src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java

diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java
index 553504748..6d98e7d57 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java
@@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.handles;
 
 import dan200.computercraft.api.lua.LuaException;
 import dan200.computercraft.api.lua.LuaFunction;
+import dan200.computercraft.core.filesystem.TrackingCloseable;
 
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
@@ -32,14 +33,14 @@ public class BinaryReadableHandle extends HandleGeneric
     final SeekableByteChannel seekable;
     private final ByteBuffer single = ByteBuffer.allocate( 1 );
 
-    BinaryReadableHandle( ReadableByteChannel reader, SeekableByteChannel seekable, Closeable closeable )
+    BinaryReadableHandle( ReadableByteChannel reader, SeekableByteChannel seekable, TrackingCloseable closeable )
     {
         super( closeable );
         this.reader = reader;
         this.seekable = seekable;
     }
 
-    public static BinaryReadableHandle of( ReadableByteChannel channel, Closeable closeable )
+    public static BinaryReadableHandle of( ReadableByteChannel channel, TrackingCloseable closeable )
     {
         SeekableByteChannel seekable = asSeekable( channel );
         return seekable == null ? new BinaryReadableHandle( channel, null, closeable ) : new Seekable( seekable, closeable );
@@ -47,7 +48,7 @@ public class BinaryReadableHandle extends HandleGeneric
 
     public static BinaryReadableHandle of( ReadableByteChannel channel )
     {
-        return of( channel, channel );
+        return of( channel, new TrackingCloseable.Impl( channel ) );
     }
 
     /**
@@ -237,7 +238,7 @@ public class BinaryReadableHandle extends HandleGeneric
 
     public static class Seekable extends BinaryReadableHandle
     {
-        Seekable( SeekableByteChannel seekable, Closeable closeable )
+        Seekable( SeekableByteChannel seekable, TrackingCloseable closeable )
         {
             super( seekable, seekable, closeable );
         }
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java
index c494e702f..bbc523697 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java
@@ -9,6 +9,7 @@ import dan200.computercraft.api.lua.IArguments;
 import dan200.computercraft.api.lua.LuaException;
 import dan200.computercraft.api.lua.LuaFunction;
 import dan200.computercraft.api.lua.LuaValues;
+import dan200.computercraft.core.filesystem.TrackingCloseable;
 
 import java.io.Closeable;
 import java.io.IOException;
@@ -30,14 +31,14 @@ public class BinaryWritableHandle extends HandleGeneric
     final SeekableByteChannel seekable;
     private final ByteBuffer single = ByteBuffer.allocate( 1 );
 
-    protected BinaryWritableHandle( WritableByteChannel writer, SeekableByteChannel seekable, Closeable closeable )
+    protected BinaryWritableHandle( WritableByteChannel writer, SeekableByteChannel seekable, TrackingCloseable closeable )
     {
         super( closeable );
         this.writer = writer;
         this.seekable = seekable;
     }
 
-    public static BinaryWritableHandle of( WritableByteChannel channel, Closeable closeable )
+    public static BinaryWritableHandle of( WritableByteChannel channel, TrackingCloseable closeable )
     {
         SeekableByteChannel seekable = asSeekable( channel );
         return seekable == null ? new BinaryWritableHandle( channel, null, closeable ) : new Seekable( seekable, closeable );
@@ -45,7 +46,7 @@ public class BinaryWritableHandle extends HandleGeneric
 
     public static BinaryWritableHandle of( WritableByteChannel channel )
     {
-        return of( channel, channel );
+        return of( channel, new TrackingCloseable.Impl( channel ) );
     }
 
     /**
@@ -108,7 +109,7 @@ public class BinaryWritableHandle extends HandleGeneric
 
     public static class Seekable extends BinaryWritableHandle
     {
-        public Seekable( SeekableByteChannel seekable, Closeable closeable )
+        public Seekable( SeekableByteChannel seekable, TrackingCloseable closeable )
         {
             super( seekable, seekable, closeable );
         }
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java
index c64690e62..979afb99b 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java
@@ -7,6 +7,7 @@ package dan200.computercraft.core.apis.handles;
 
 import dan200.computercraft.api.lua.LuaException;
 import dan200.computercraft.api.lua.LuaFunction;
+import dan200.computercraft.core.filesystem.TrackingCloseable;
 
 import javax.annotation.Nonnull;
 import java.io.BufferedReader;
@@ -32,7 +33,7 @@ public class EncodedReadableHandle extends HandleGeneric
 
     private final BufferedReader reader;
 
-    public EncodedReadableHandle( @Nonnull BufferedReader reader, @Nonnull Closeable closable )
+    public EncodedReadableHandle( @Nonnull BufferedReader reader, @Nonnull TrackingCloseable closable )
     {
         super( closable );
         this.reader = reader;
@@ -40,7 +41,7 @@ public class EncodedReadableHandle extends HandleGeneric
 
     public EncodedReadableHandle( @Nonnull BufferedReader reader )
     {
-        this( reader, reader );
+        this( reader, new TrackingCloseable.Impl( reader ) );
     }
 
     /**
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java
index 400393d12..00c12629b 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java
@@ -8,6 +8,7 @@ package dan200.computercraft.core.apis.handles;
 import dan200.computercraft.api.lua.IArguments;
 import dan200.computercraft.api.lua.LuaException;
 import dan200.computercraft.api.lua.LuaFunction;
+import dan200.computercraft.core.filesystem.TrackingCloseable;
 import dan200.computercraft.shared.util.StringUtil;
 
 import javax.annotation.Nonnull;
@@ -30,7 +31,7 @@ public class EncodedWritableHandle extends HandleGeneric
 {
     private final BufferedWriter writer;
 
-    public EncodedWritableHandle( @Nonnull BufferedWriter writer, @Nonnull Closeable closable )
+    public EncodedWritableHandle( @Nonnull BufferedWriter writer, @Nonnull TrackingCloseable closable )
     {
         super( closable );
         this.writer = writer;
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java
index d9291c173..fc1954354 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/HandleGeneric.java
@@ -7,10 +7,10 @@ package dan200.computercraft.core.apis.handles;
 
 import dan200.computercraft.api.lua.LuaException;
 import dan200.computercraft.api.lua.LuaFunction;
+import dan200.computercraft.core.filesystem.TrackingCloseable;
 import dan200.computercraft.shared.util.IoUtil;
 
 import javax.annotation.Nonnull;
-import java.io.Closeable;
 import java.io.IOException;
 import java.nio.channels.Channel;
 import java.nio.channels.SeekableByteChannel;
@@ -18,25 +18,23 @@ import java.util.Optional;
 
 public abstract class HandleGeneric
 {
-    private Closeable closable;
-    private boolean open = true;
+    private TrackingCloseable closeable;
 
-    protected HandleGeneric( @Nonnull Closeable closable )
+    protected HandleGeneric( @Nonnull TrackingCloseable closeable )
     {
-        this.closable = closable;
+        this.closeable = closeable;
     }
 
     protected void checkOpen() throws LuaException
     {
-        if( !open ) throw new LuaException( "attempt to use a closed file" );
+        TrackingCloseable closeable = this.closeable;
+        if( closeable == null || !closeable.isOpen() ) throw new LuaException( "attempt to use a closed file" );
     }
 
     protected final void close()
     {
-        open = false;
-
-        IoUtil.closeQuietly( closable );
-        closable = null;
+        IoUtil.closeQuietly( closeable );
+        closeable = null;
     }
 
     /**
diff --git a/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java
index ab9d532d4..f5de836bc 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/ChannelWrapper.java
@@ -42,7 +42,7 @@ class ChannelWrapper implements Closeable
         }
     }
 
-    public T get()
+    T get()
     {
         return wrapper;
     }
diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java
index 2556822bc..2904f0fb3 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java
@@ -95,7 +95,29 @@ public class FileSystem
 
     public synchronized void unmount( String path )
     {
-        mounts.remove( sanitizePath( path ) );
+        MountWrapper mount = mounts.remove( sanitizePath( path ) );
+        if( mount == null ) return;
+
+        cleanup();
+
+        // Close any files which belong to this mount - don't want people writing to a disk after it's been ejected!
+        // There's no point storing a Mount -> Wrapper[] map, as m_openFiles is small and unmount isn't called very
+        // often.
+        synchronized( m_openFiles )
+        {
+            for( Iterator>> iterator = m_openFiles.keySet().iterator(); iterator.hasNext(); )
+            {
+                WeakReference> reference = iterator.next();
+                FileSystemWrapper wrapper = reference.get();
+                if( wrapper == null ) continue;
+
+                if( wrapper.mount == mount )
+                {
+                    wrapper.closeExternally();
+                    iterator.remove();
+                }
+            }
+        }
     }
 
     public String combine( String path, String childPath )
@@ -371,7 +393,7 @@ public class FileSystem
         }
     }
 
-    private synchronized  FileSystemWrapper openFile( @Nonnull Channel channel, @Nonnull T file ) throws FileSystemException
+    private synchronized  FileSystemWrapper openFile( @Nonnull MountWrapper mount, @Nonnull Channel channel, @Nonnull T file ) throws FileSystemException
     {
         synchronized( m_openFiles )
         {
@@ -384,13 +406,13 @@ public class FileSystem
             }
 
             ChannelWrapper channelWrapper = new ChannelWrapper<>( file, channel );
-            FileSystemWrapper fsWrapper = new FileSystemWrapper<>( this, channelWrapper, m_openFileQueue );
+            FileSystemWrapper fsWrapper = new FileSystemWrapper<>( this, mount, channelWrapper, m_openFileQueue );
             m_openFiles.put( fsWrapper.self, channelWrapper );
             return fsWrapper;
         }
     }
 
-    synchronized void removeFile( FileSystemWrapper handle )
+    void removeFile( FileSystemWrapper handle )
     {
         synchronized( m_openFiles )
         {
@@ -405,11 +427,7 @@ public class FileSystem
         path = sanitizePath( path );
         MountWrapper mount = getMount( path );
         ReadableByteChannel channel = mount.openForRead( path );
-        if( channel != null )
-        {
-            return openFile( channel, open.apply( channel ) );
-        }
-        return null;
+        return channel != null ? openFile( mount, channel, open.apply( channel ) ) : null;
     }
 
     public synchronized  FileSystemWrapper openForWrite( String path, boolean append, Function open ) throws FileSystemException
@@ -419,11 +437,7 @@ public class FileSystem
         path = sanitizePath( path );
         MountWrapper mount = getMount( path );
         WritableByteChannel channel = append ? mount.openForAppend( path ) : mount.openForWrite( path );
-        if( channel != null )
-        {
-            return openFile( channel, open.apply( channel ) );
-        }
-        return null;
+        return channel != null ? openFile( mount, channel, open.apply( channel ) ) : null;
     }
 
     public synchronized long getFreeSpace( String path ) throws FileSystemException
diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java
index 5d1ad2d74..a65e04326 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapper.java
@@ -5,6 +5,8 @@
  */
 package dan200.computercraft.core.filesystem;
 
+import dan200.computercraft.shared.util.IoUtil;
+
 import javax.annotation.Nonnull;
 import java.io.Closeable;
 import java.io.IOException;
@@ -24,15 +26,18 @@ import java.lang.ref.WeakReference;
  *
  * @param  The type of writer or channel to wrap.
  */
-public class FileSystemWrapper implements Closeable
+public class FileSystemWrapper implements TrackingCloseable
 {
     private final FileSystem fileSystem;
+    final MountWrapper mount;
     private final ChannelWrapper closeable;
     final WeakReference> self;
+    private boolean isOpen = true;
 
-    FileSystemWrapper( FileSystem fileSystem, ChannelWrapper closeable, ReferenceQueue> queue )
+    FileSystemWrapper( FileSystem fileSystem, MountWrapper mount, ChannelWrapper closeable, ReferenceQueue> queue )
     {
         this.fileSystem = fileSystem;
+        this.mount = mount;
         this.closeable = closeable;
         self = new WeakReference<>( this, queue );
     }
@@ -40,10 +45,23 @@ public class FileSystemWrapper implements Closeable
     @Override
     public void close() throws IOException
     {
+        isOpen = false;
         fileSystem.removeFile( this );
         closeable.close();
     }
 
+    void closeExternally()
+    {
+        isOpen = false;
+        IoUtil.closeQuietly( closeable );
+    }
+
+    @Override
+    public boolean isOpen()
+    {
+        return isOpen;
+    }
+
     @Nonnull
     public T get()
     {
diff --git a/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java b/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java
new file mode 100644
index 000000000..7fec31b2f
--- /dev/null
+++ b/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java
@@ -0,0 +1,39 @@
+package dan200.computercraft.core.filesystem;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+/**
+ * A {@link Closeable} which knows when it has been closed.
+ *
+ * This is a quick (though racey) way of providing more friendly (and more similar to Lua)
+ * error messages to the user.
+ */
+public interface TrackingCloseable extends Closeable
+{
+    boolean isOpen();
+
+    class Impl implements TrackingCloseable
+    {
+        private final Closeable object;
+        private boolean isOpen = true;
+
+        public Impl( Closeable object )
+        {
+            this.object = object;
+        }
+
+        @Override
+        public boolean isOpen()
+        {
+            return isOpen;
+        }
+
+        @Override
+        public void close() throws IOException
+        {
+            isOpen = false;
+            object.close();
+        }
+    }
+}
diff --git a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java
index 17855cf4a..6d4e52278 100644
--- a/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java
+++ b/src/test/java/dan200/computercraft/core/filesystem/FileSystemTest.java
@@ -18,10 +18,19 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 public class FileSystemTest
 {
     private static final File ROOT = new File( "test-files/filesystem" );
+    private static final long CAPACITY = 1000000;
+
+    private static FileSystem mkFs() throws FileSystemException
+    {
+        IWritableMount writableMount = new FileMount( ROOT, CAPACITY );
+        return new FileSystem( "hdd", writableMount );
+
+    }
 
     /**
      * Ensures writing a file truncates it.
@@ -33,8 +42,7 @@ public class FileSystemTest
     @Test
     public void testWriteTruncates() throws FileSystemException, LuaException, IOException
     {
-        IWritableMount writableMount = new FileMount( ROOT, 1000000 );
-        FileSystem fs = new FileSystem( "hdd", writableMount );
+        FileSystem fs = mkFs();
 
         {
             FileSystemWrapper writer = fs.openForWrite( "out.txt", false, EncodedWritableHandle::openUtf8 );
@@ -54,4 +62,20 @@ public class FileSystemTest
 
         assertEquals( "Tiny line", Files.asCharSource( new File( ROOT, "out.txt" ), StandardCharsets.UTF_8 ).read() );
     }
+
+    @Test
+    public void testUnmountCloses() throws FileSystemException
+    {
+        FileSystem fs = mkFs();
+        IWritableMount mount = new FileMount( new File( ROOT, "child" ), CAPACITY );
+        fs.mountWritable( "disk", "disk", mount );
+
+        FileSystemWrapper writer = fs.openForWrite( "disk/out.txt", false, EncodedWritableHandle::openUtf8 );
+        ObjectWrapper wrapper = new ObjectWrapper( new EncodedWritableHandle( writer.get(), writer ) );
+
+        fs.unmount( "disk" );
+
+        LuaException err = assertThrows( LuaException.class, () -> wrapper.call( "write", "Tiny line" ) );
+        assertEquals( "attempt to use a closed file", err.getMessage() );
+    }
 }

From 58054ad2d1a9a967f1ef5dc981da5db938bb2c71 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Thu, 14 Jan 2021 09:09:02 +0000
Subject: [PATCH 426/711] Reformat src/main/java

Removes several pointless imports. And, more importantly, fixes the
build.
---
 .../dan200/computercraft/core/apis/FSAPI.java |  2 +-
 .../dan200/computercraft/core/apis/OSAPI.java | 24 +++++++++----------
 .../apis/handles/BinaryReadableHandle.java    |  1 -
 .../apis/handles/BinaryWritableHandle.java    |  1 -
 .../apis/handles/EncodedReadableHandle.java   |  1 -
 .../apis/handles/EncodedWritableHandle.java   |  1 -
 .../core/computer/Environment.java            |  2 --
 .../core/filesystem/TrackingCloseable.java    |  5 ++++
 .../dan200/computercraft/shared/Config.java   |  8 ++-----
 .../shared/common/BlockGeneric.java           |  2 --
 .../shared/computer/blocks/BlockComputer.java |  2 --
 .../computer/blocks/BlockComputerBase.java    |  2 --
 .../shared/computer/items/ItemComputer.java   |  2 --
 .../computer/items/ItemComputerBase.java      |  2 --
 .../recipe/ComputerUpgradeRecipe.java         |  2 --
 .../data/BlockNamedEntityLootCondition.java   |  2 --
 .../data/HasComputerIdLootCondition.java      |  2 --
 .../data/PlayerCreativeLootCondition.java     |  2 --
 .../shared/media/items/ItemDisk.java          |  2 --
 .../shared/media/items/ItemPrintout.java      |  2 --
 .../shared/media/items/ItemTreasureDisk.java  |  2 --
 .../peripheral/diskdrive/BlockDiskDrive.java  |  2 --
 .../generic/methods/InventoryMethods.java     | 22 ++++++++---------
 .../peripheral/modem/wired/BlockCable.java    |  2 --
 .../modem/wired/BlockWiredModemFull.java      |  2 --
 .../modem/wired/ItemBlockCable.java           |  2 --
 .../modem/wireless/BlockWirelessModem.java    |  2 --
 .../peripheral/monitor/BlockMonitor.java      |  2 --
 .../peripheral/printer/BlockPrinter.java      |  2 --
 .../peripheral/printer/PrinterPeripheral.java |  6 ++---
 .../peripheral/printer/TilePrinter.java       |  5 +++-
 .../peripheral/speaker/BlockSpeaker.java      |  2 --
 .../peripheral/speaker/SpeakerPeripheral.java |  8 +++----
 .../pocket/items/ItemPocketComputer.java      |  2 --
 .../shared/turtle/blocks/BlockTurtle.java     |  2 --
 .../shared/turtle/items/ItemTurtle.java       |  2 --
 .../shared/turtle/recipes/TurtleRecipe.java   |  2 --
 37 files changed, 41 insertions(+), 93 deletions(-)

diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java
index fada96ecd..5cd6b9e2c 100644
--- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java
+++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java
@@ -89,9 +89,9 @@ public class FSAPI implements ILuaAPI
      *
      * @param arguments The paths to combine.
      * @return The new path, with separators added between parts as needed.
+     * @throws LuaException On argument errors.
      * @cc.tparam string path The first part of the path. For example, a parent directory path.
      * @cc.tparam string ... Additional parts of the path to combine.
-     * @throws LuaException On argument errors.
      */
     @LuaFunction
     public final String combine( IArguments arguments ) throws LuaException
diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java
index 5634ed6ed..d8da0a23d 100644
--- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java
+++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java
@@ -180,7 +180,7 @@ public class OSAPI implements ILuaAPI
      *
      * @param timer The number of seconds until the timer fires.
      * @return The ID of the new timer. This can be used to filter the
-     *   {@code timer} event, or {@link #cancelTimer cancel the timer}.
+     * {@code timer} event, or {@link #cancelTimer cancel the timer}.
      * @throws LuaException If the time is below zero.
      * @see #cancelTimer To cancel a timer.
      */
@@ -210,7 +210,7 @@ public class OSAPI implements ILuaAPI
      *
      * @param time The time at which to fire the alarm, in the range [0.0, 24.0).
      * @return The ID of the new alarm. This can be used to filter the
-     *   {@code alarm} event, or {@link #cancelAlarm cancel the alarm}.
+     * {@code alarm} event, or {@link #cancelAlarm cancel the alarm}.
      * @throws LuaException If the time is out of range.
      * @see #cancelAlarm To cancel an alarm.
      */
@@ -312,10 +312,10 @@ public class OSAPI implements ILuaAPI
      * always be in the range [0.0, 24.0).
      *
      * * If called with {@code ingame}, the current world time will be returned.
-     *   This is the default if nothing is passed.
+     * This is the default if nothing is passed.
      * * If called with {@code utc}, returns the hour of the day in UTC time.
      * * If called with {@code local}, returns the hour of the day in the
-     *   timezone the server is located in.
+     * timezone the server is located in.
      *
      * This function can also be called with a table returned from {@link #date},
      * which will convert the date fields into a UNIX timestamp (number of
@@ -323,9 +323,9 @@ public class OSAPI implements ILuaAPI
      *
      * @param args The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified.
      * @return The hour of the selected locale, or a UNIX timestamp from the table, depending on the argument passed in.
+     * @throws LuaException If an invalid locale is passed.
      * @cc.tparam [opt] string|table locale The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code ingame} locale if not specified.
      * @see #date To get a date table that can be converted with this function.
-     * @throws LuaException If an invalid locale is passed.
      */
     @LuaFunction
     public final Object time( IArguments args ) throws LuaException
@@ -351,11 +351,11 @@ public class OSAPI implements ILuaAPI
      * Returns the day depending on the locale specified.
      *
      * * If called with {@code ingame}, returns the number of days since the
-     *   world was created. This is the default.
+     * world was created. This is the default.
      * * If called with {@code utc}, returns the number of days since 1 January
-     *   1970 in the UTC timezone.
+     * 1970 in the UTC timezone.
      * * If called with {@code local}, returns the number of days since 1
-     *   January 1970 in the server's local timezone.
+     * January 1970 in the server's local timezone.
      *
      * @param args The locale to get the day for. Defaults to {@code ingame} if not set.
      * @return The day depending on the selected locale.
@@ -381,11 +381,11 @@ public class OSAPI implements ILuaAPI
      * Returns the number of milliseconds since an epoch depending on the locale.
      *
      * * If called with {@code ingame}, returns the number of milliseconds since the
-     *   world was created. This is the default.
+     * world was created. This is the default.
      * * If called with {@code utc}, returns the number of milliseconds since 1
-     *   January 1970 in the UTC timezone.
+     * January 1970 in the UTC timezone.
      * * If called with {@code local}, returns the number of milliseconds since 1
-     *   January 1970 in the server's local timezone.
+     * January 1970 in the server's local timezone.
      *
      * @param args The locale to get the milliseconds for. Defaults to {@code ingame} if not set.
      * @return The milliseconds since the epoch depending on the selected locale.
@@ -435,7 +435,7 @@ public class OSAPI implements ILuaAPI
      * timestamp (days since 1 January 1970) with {@link #date}.
      *
      * @param formatA The format of the string to return. This defaults to {@code %c}, which expands to a string similar to "Sat Dec 24 16:58:00 2011".
-     * @param timeA The time to convert to a string. This defaults to the current time.
+     * @param timeA   The time to convert to a string. This defaults to the current time.
      * @return The resulting format string.
      * @throws LuaException If an invalid format is passed.
      */
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java
index 6d98e7d57..4477dde92 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java
@@ -10,7 +10,6 @@ import dan200.computercraft.api.lua.LuaFunction;
 import dan200.computercraft.core.filesystem.TrackingCloseable;
 
 import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.ReadableByteChannel;
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java
index bbc523697..796582855 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java
@@ -11,7 +11,6 @@ import dan200.computercraft.api.lua.LuaFunction;
 import dan200.computercraft.api.lua.LuaValues;
 import dan200.computercraft.core.filesystem.TrackingCloseable;
 
-import java.io.Closeable;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java
index 979afb99b..28576f70d 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java
@@ -11,7 +11,6 @@ import dan200.computercraft.core.filesystem.TrackingCloseable;
 
 import javax.annotation.Nonnull;
 import java.io.BufferedReader;
-import java.io.Closeable;
 import java.io.IOException;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
diff --git a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java
index 00c12629b..b012b6d0d 100644
--- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java
+++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedWritableHandle.java
@@ -13,7 +13,6 @@ import dan200.computercraft.shared.util.StringUtil;
 
 import javax.annotation.Nonnull;
 import java.io.BufferedWriter;
-import java.io.Closeable;
 import java.io.IOException;
 import java.nio.channels.Channels;
 import java.nio.channels.WritableByteChannel;
diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java
index 9aebcfd33..3931629f1 100644
--- a/src/main/java/dan200/computercraft/core/computer/Environment.java
+++ b/src/main/java/dan200/computercraft/core/computer/Environment.java
@@ -20,8 +20,6 @@ import javax.annotation.Nonnull;
 import java.util.Arrays;
 import java.util.Iterator;
 
-import dan200.computercraft.core.apis.IAPIEnvironment.IPeripheralChangeListener;
-
 /**
  * Represents the "environment" that a {@link Computer} exists in.
  *
diff --git a/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java b/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java
index 7fec31b2f..19ffc978f 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/TrackingCloseable.java
@@ -1,3 +1,8 @@
+/*
+ * This file is part of ComputerCraft - http://www.computercraft.info
+ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
+ * Send enquiries to dratcliffe@gmail.com
+ */
 package dan200.computercraft.core.filesystem;
 
 import java.io.Closeable;
diff --git a/src/main/java/dan200/computercraft/shared/Config.java b/src/main/java/dan200/computercraft/shared/Config.java
index a3e43029b..121a8f882 100644
--- a/src/main/java/dan200/computercraft/shared/Config.java
+++ b/src/main/java/dan200/computercraft/shared/Config.java
@@ -16,6 +16,8 @@ import dan200.computercraft.core.apis.http.options.Action;
 import dan200.computercraft.core.apis.http.options.AddressRuleConfig;
 import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
 import net.minecraftforge.common.ForgeConfigSpec;
+import net.minecraftforge.common.ForgeConfigSpec.Builder;
+import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
 import net.minecraftforge.eventbus.api.SubscribeEvent;
 import net.minecraftforge.fml.ModLoadingContext;
 import net.minecraftforge.fml.common.Mod;
@@ -28,12 +30,6 @@ import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-import static net.minecraftforge.common.ForgeConfigSpec.Builder;
-import static net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
-
-import net.minecraftforge.common.ForgeConfigSpec.Builder;
-import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
-
 @Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD )
 public final class Config
 {
diff --git a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java
index 0de119b43..eaa521f3f 100644
--- a/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java
+++ b/src/main/java/dan200/computercraft/shared/common/BlockGeneric.java
@@ -24,8 +24,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Random;
 
-import net.minecraft.block.Block.Properties;
-
 public abstract class BlockGeneric extends Block
 {
     private final RegistryObject> type;
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java
index e6daec420..f44f01e52 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputer.java
@@ -23,8 +23,6 @@ import net.minecraftforge.fml.RegistryObject;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockComputer extends BlockComputerBase
 {
     public static final EnumProperty STATE = EnumProperty.create( "state", ComputerState.class );
diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java
index 75f3e3a08..64ea607c4 100644
--- a/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java
+++ b/src/main/java/dan200/computercraft/shared/computer/blocks/BlockComputerBase.java
@@ -34,8 +34,6 @@ import net.minecraftforge.fml.RegistryObject;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import net.minecraft.block.Block.Properties;
-
 public abstract class BlockComputerBase extends BlockGeneric implements IBundledRedstoneBlock
 {
     private static final ResourceLocation DROP = new ResourceLocation( ComputerCraft.MOD_ID, "computer" );
diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java
index caab0cbaf..a3d98ba19 100644
--- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java
+++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputer.java
@@ -12,8 +12,6 @@ import net.minecraft.util.text.StringTextComponent;
 
 import javax.annotation.Nonnull;
 
-import net.minecraft.item.Item.Properties;
-
 public class ItemComputer extends ItemComputerBase
 {
     public ItemComputer( BlockComputer block, Properties settings )
diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java
index e2ed053a5..7551a3141 100644
--- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java
+++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java
@@ -24,8 +24,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 
-import net.minecraft.item.Item.Properties;
-
 public abstract class ItemComputerBase extends BlockItem implements IComputerItem, IMedia
 {
     private final ComputerFamily family;
diff --git a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java
index 35d7d8c7a..cd50542ff 100644
--- a/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/computer/recipe/ComputerUpgradeRecipe.java
@@ -15,8 +15,6 @@ import net.minecraft.util.ResourceLocation;
 
 import javax.annotation.Nonnull;
 
-import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe.Serializer;
-
 public class ComputerUpgradeRecipe extends ComputerFamilyRecipe
 {
     public ComputerUpgradeRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family )
diff --git a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java
index 8597b7eae..9e978fb8e 100644
--- a/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java
+++ b/src/main/java/dan200/computercraft/shared/data/BlockNamedEntityLootCondition.java
@@ -16,8 +16,6 @@ import javax.annotation.Nonnull;
 import java.util.Collections;
 import java.util.Set;
 
-import net.minecraft.world.storage.loot.conditions.ILootCondition.IBuilder;
-
 /**
  * A loot condition which checks if the tile entity has a name.
  */
diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java
index e734bf836..b7f353961 100644
--- a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java
+++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java
@@ -16,8 +16,6 @@ import javax.annotation.Nonnull;
 import java.util.Collections;
 import java.util.Set;
 
-import net.minecraft.world.storage.loot.conditions.ILootCondition.IBuilder;
-
 /**
  * A loot condition which checks if the tile entity has has a non-0 ID.
  */
diff --git a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java
index 346634b6e..a9a681db7 100644
--- a/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java
+++ b/src/main/java/dan200/computercraft/shared/data/PlayerCreativeLootCondition.java
@@ -16,8 +16,6 @@ import javax.annotation.Nonnull;
 import java.util.Collections;
 import java.util.Set;
 
-import net.minecraft.world.storage.loot.conditions.ILootCondition.IBuilder;
-
 /**
  * A loot condition which checks if the entity is in creative mode.
  */
diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java
index b62396e3d..aa455688a 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/ItemDisk.java
@@ -31,8 +31,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 
-import net.minecraft.item.Item.Properties;
-
 public class ItemDisk extends Item implements IMedia, IColouredItem
 {
     private static final String NBT_ID = "DiskId";
diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java
index 52be0cfe4..0c76789ed 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/ItemPrintout.java
@@ -23,8 +23,6 @@ import net.minecraft.world.World;
 import javax.annotation.Nonnull;
 import java.util.List;
 
-import net.minecraft.item.Item.Properties;
-
 public class ItemPrintout extends Item
 {
     private static final String NBT_TITLE = "Title";
diff --git a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java
index 49cc07dc9..6b663ed34 100644
--- a/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java
+++ b/src/main/java/dan200/computercraft/shared/media/items/ItemTreasureDisk.java
@@ -29,8 +29,6 @@ import javax.annotation.Nullable;
 import java.io.IOException;
 import java.util.List;
 
-import net.minecraft.item.Item.Properties;
-
 public class ItemTreasureDisk extends Item implements IMedia
 {
     private static final String NBT_TITLE = "Title";
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java
index fc8cb0162..caa64e460 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/BlockDiskDrive.java
@@ -27,8 +27,6 @@ import net.minecraft.world.World;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockDiskDrive extends BlockGeneric
 {
     static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java
index 8aa20a105..0663d66ad 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java
@@ -90,7 +90,7 @@ public class InventoryMethods implements GenericSource
      * Get detailed information about an item.
      *
      * @param inventory The current inventory.
-     * @param slot The slot to get information about.
+     * @param slot      The slot to get information about.
      * @return Information about the item in this slot, or {@code nil} if not present.
      * @throws LuaException If the slot is out of range.
      * @cc.treturn table Information about the item in this slot, or {@code nil} if not present.
@@ -111,17 +111,16 @@ public class InventoryMethods implements GenericSource
      * This allows you to push an item in an inventory to another inventory on the same wired network. Both
      * inventories must attached to wired modems which are connected via a cable.
      *
-     * @param from Inventory to move items from.
+     * @param from     Inventory to move items from.
      * @param computer The current computer.
-     * @param toName The name of the peripheral/inventory to push to. This is the string given to @{peripheral.wrap},
-     * and displayed by the wired modem.
+     * @param toName   The name of the peripheral/inventory to push to. This is the string given to @{peripheral.wrap},
+     *                 and displayed by the wired modem.
      * @param fromSlot The slot in the current inventory to move items to.
-     * @param limit The maximum number of items to move. Defaults to the current stack limit.
-     * @param toSlot The slot in the target inventory to move to. If not given, the item will be inserted into any slot.
+     * @param limit    The maximum number of items to move. Defaults to the current stack limit.
+     * @param toSlot   The slot in the target inventory to move to. If not given, the item will be inserted into any slot.
      * @return The number of transferred items.
      * @throws LuaException If the peripheral to transfer to doesn't exist or isn't an inventory.
      * @throws LuaException If either source or destination slot is out of range.
-     *
      * @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
      * @cc.usage Wrap two chests, and push an item from one to another.
      * 
{@code
@@ -159,17 +158,16 @@ public class InventoryMethods implements GenericSource
      * This allows you to transfer items between inventories on the same wired network. Both this and the source
      * inventory must attached to wired modems which are connected via a cable.
      *
-     * @param to Inventory to move items to.
+     * @param to       Inventory to move items to.
      * @param computer The current computer.
      * @param fromName The name of the peripheral/inventory to pull from. This is the string given to @{peripheral.wrap},
-     * and displayed by the wired modem.
+     *                 and displayed by the wired modem.
      * @param fromSlot The slot in the source inventory to move items from.
-     * @param limit The maximum number of items to move. Defaults to the current stack limit.
-     * @param toSlot The slot in current inventory to move to. If not given, the item will be inserted into any slot.
+     * @param limit    The maximum number of items to move. Defaults to the current stack limit.
+     * @param toSlot   The slot in current inventory to move to. If not given, the item will be inserted into any slot.
      * @return The number of transferred items.
      * @throws LuaException If the peripheral to transfer to doesn't exist or isn't an inventory.
      * @throws LuaException If either source or destination slot is out of range.
-     *
      * @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
      * @cc.usage Wrap two chests, and push an item from one to another.
      * 
{@code
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java
index 8c5f6ec03..3332e4c7c 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockCable.java
@@ -40,8 +40,6 @@ import java.util.EnumMap;
 
 import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockCable extends BlockGeneric implements IWaterLoggable
 {
     public static final EnumProperty MODEM = EnumProperty.create( "modem", CableModemVariant.class );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java
index a56282d4f..13c01aa7e 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/BlockWiredModemFull.java
@@ -12,8 +12,6 @@ import net.minecraft.block.BlockState;
 import net.minecraft.state.BooleanProperty;
 import net.minecraft.state.StateContainer;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockWiredModemFull extends BlockGeneric
 {
     public static final BooleanProperty MODEM_ON = BooleanProperty.create( "modem" );
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java
index ca7ca69a5..4d0905962 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/ItemBlockCable.java
@@ -23,8 +23,6 @@ import javax.annotation.Nonnull;
 
 import static dan200.computercraft.shared.peripheral.modem.wired.BlockCable.*;
 
-import net.minecraft.item.Item.Properties;
-
 public abstract class ItemBlockCable extends BlockItem
 {
     private String translationKey;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java
index 7655d15a3..6bcd95126 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/BlockWirelessModem.java
@@ -31,8 +31,6 @@ import javax.annotation.Nullable;
 
 import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockWirelessModem extends BlockGeneric implements IWaterLoggable
 {
     public static final DirectionProperty FACING = BlockStateProperties.FACING;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
index b863f9e89..3e6efdbc0 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/BlockMonitor.java
@@ -25,8 +25,6 @@ import net.minecraftforge.fml.RegistryObject;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockMonitor extends BlockGeneric
 {
     public static final DirectionProperty ORIENTATION = DirectionProperty.create( "orientation",
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java
index 9dde86617..78f098347 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/BlockPrinter.java
@@ -27,8 +27,6 @@ import net.minecraft.world.World;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockPrinter extends BlockGeneric
 {
     private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java
index a51849a8e..1b13315fb 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/PrinterPeripheral.java
@@ -46,8 +46,8 @@ public class PrinterPeripheral implements IPeripheral
      * Writes text to the current page.
      *
      * @param arguments The values to write to the page.
-     * @cc.tparam string|number ... The values to write to the page.
      * @throws LuaException If any values couldn't be converted to a string, or if no page is started.
+     * @cc.tparam string|number ... The values to write to the page.
      */
     @LuaFunction
     public final void write( IArguments arguments ) throws LuaException
@@ -62,9 +62,9 @@ public class PrinterPeripheral implements IPeripheral
      * Returns the current position of the cursor on the page.
      *
      * @return The position of the cursor.
+     * @throws LuaException If a page isn't being printed.
      * @cc.treturn number The X position of the cursor.
      * @cc.treturn number The Y position of the cursor.
-     * @throws LuaException If a page isn't being printed.
      */
     @LuaFunction
     public final Object[] getCursorPos() throws LuaException
@@ -93,9 +93,9 @@ public class PrinterPeripheral implements IPeripheral
      * Returns the size of the current page.
      *
      * @return The size of the page.
+     * @throws LuaException If a page isn't being printed.
      * @cc.treturn number The width of the page.
      * @cc.treturn number The height of the page.
-     * @throws LuaException If a page isn't being printed.
      */
     @LuaFunction
     public final Object[] getPageSize() throws LuaException
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
index 17ad232da..6320a13ff 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java
@@ -17,7 +17,10 @@ import net.minecraft.entity.player.ServerPlayerEntity;
 import net.minecraft.inventory.ItemStackHelper;
 import net.minecraft.inventory.container.Container;
 import net.minecraft.inventory.container.INamedContainerProvider;
-import net.minecraft.item.*;
+import net.minecraft.item.DyeColor;
+import net.minecraft.item.Item;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
 import net.minecraft.nbt.CompoundNBT;
 import net.minecraft.tileentity.TileEntityType;
 import net.minecraft.util.*;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java
index 1aa81c6a6..41fd32a85 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/BlockSpeaker.java
@@ -17,8 +17,6 @@ import net.minecraft.util.Direction;
 
 import javax.annotation.Nullable;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockSpeaker extends BlockGeneric
 {
     private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
index 9ebf8c10a..00492d4e9 100644
--- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
+++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java
@@ -66,9 +66,9 @@ public abstract class SpeakerPeripheral implements IPeripheral
      * with an optional volume and speed multiplier, and plays it through the speaker.
      *
      * @param context The Lua context
-     * @param name The name of the sound to play.
+     * @param name    The name of the sound to play.
      * @param volumeA The volume to play the sound at, from 0.0 to 3.0. Defaults to 1.0.
-     * @param pitchA The speed to play the sound at, from 0.5 to 2.0. Defaults to 1.0.
+     * @param pitchA  The speed to play the sound at, from 0.5 to 2.0. Defaults to 1.0.
      * @return Whether the sound could be played.
      * @throws LuaException If the sound name couldn't be decoded.
      */
@@ -102,9 +102,9 @@ public abstract class SpeakerPeripheral implements IPeripheral
      * and 6 and 18 map to C.
      *
      * @param context The Lua context
-     * @param name The name of the note to play.
+     * @param name    The name of the note to play.
      * @param volumeA The volume to play the note at, from 0.0 to 3.0. Defaults to 1.0.
-     * @param pitchA The pitch to play the note at in semitones, from 0 to 24. Defaults to 12.
+     * @param pitchA  The pitch to play the note at in semitones, from 0 to 24. Defaults to 12.
      * @return Whether the note could be played.
      * @throws LuaException If the instrument doesn't exist.
      */
diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
index 12c3228ee..561743557 100644
--- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
+++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java
@@ -45,8 +45,6 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 
-import net.minecraft.item.Item.Properties;
-
 public class ItemPocketComputer extends Item implements IComputerItem, IMedia, IColouredItem
 {
     private static final String NBT_UPGRADE = "Upgrade";
diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java
index 81a42d134..64851e270 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/BlockTurtle.java
@@ -44,8 +44,6 @@ import javax.annotation.Nullable;
 import static dan200.computercraft.shared.util.WaterloggableHelpers.*;
 import static net.minecraft.state.properties.BlockStateProperties.WATERLOGGED;
 
-import net.minecraft.block.Block.Properties;
-
 public class BlockTurtle extends BlockComputerBase implements IWaterLoggable
 {
     public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java
index 331f8e28f..24be2a9f3 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/items/ItemTurtle.java
@@ -27,8 +27,6 @@ import javax.annotation.Nullable;
 
 import static dan200.computercraft.shared.turtle.core.TurtleBrain.*;
 
-import net.minecraft.item.Item.Properties;
-
 public class ItemTurtle extends ItemComputerBase implements ITurtleItem
 {
     public ItemTurtle( BlockTurtle block, Properties settings )
diff --git a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java
index af2dbe8bc..05e598bac 100644
--- a/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java
+++ b/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleRecipe.java
@@ -17,8 +17,6 @@ import net.minecraft.util.ResourceLocation;
 
 import javax.annotation.Nonnull;
 
-import dan200.computercraft.shared.computer.recipe.ComputerFamilyRecipe.Serializer;
-
 public final class TurtleRecipe extends ComputerFamilyRecipe
 {
     private TurtleRecipe( ResourceLocation identifier, String group, int width, int height, NonNullList ingredients, ItemStack result, ComputerFamily family )

From fd262a7995dc3fb31a6417a75fe55bb15f090044 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Thu, 14 Jan 2021 09:11:08 +0000
Subject: [PATCH 427/711] Clarify the cc.strings.wrap docs a little

Also make the example a bit more "useful". Hopefully this should clarify
that the function returns a table rather than a single string.

Closes #678.
---
 .../lua/rom/modules/main/cc/strings.lua       | 29 ++++++++++++-------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua
index 49f5cd0d4..89d6e475c 100644
--- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua
+++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/strings.lua
@@ -5,17 +5,24 @@
 
 local expect = require "cc.expect".expect
 
---- Wraps a block of text, so that each line fits within the given width.
---
--- This may be useful if you want to wrap text before displaying it to a
--- @{monitor} or @{printer} without using @{_G.print|print}.
---
--- @tparam string text The string to wrap.
--- @tparam[opt] number width The width to constrain to, defaults to the width of
--- the terminal.
---
--- @treturn { string... } The wrapped input string.
--- @usage require "cc.strings".wrap("This is a long piece of text", 10)
+--[[- Wraps a block of text, so that each line fits within the given width.
+
+This may be useful if you want to wrap text before displaying it to a
+@{monitor} or @{printer} without using @{_G.print|print}.
+
+@tparam string text The string to wrap.
+@tparam[opt] number width The width to constrain to, defaults to the width of
+the terminal.
+@treturn { string... } The wrapped input string as a list of lines.
+@usage Wrap a string and write it to the terminal.
+
+    term.clear()
+    local lines = require "cc.strings".wrap("This is a long piece of text", 10)
+    for i = 1, #lines do
+      term.setCursorPos(1, i)
+      term.write(lines[i])
+    end
+]]
 local function wrap(text, width)
     expect(1, text, "string")
     expect(2, width, "number", "nil")

From 9ae0f4a993693ffc48ec8a4b5824c50f54026e0a Mon Sep 17 00:00:00 2001
From: SquidDev 
Date: Thu, 14 Jan 2021 18:19:22 +0000
Subject: [PATCH 428/711] Add some initial documentation for events

Credit to @BradyFromDiscord for writing these. See #640 and #565.

Co-authored-by: Brady Ctrl) do not have any
+corresponding character. The @{key} should be used if you want to listen to key presses themselves.
+
+## Return values
+1. @{string}: The event name.
+2. @{string}: The string representing the character that was pressed.
+
+
+## Example
+Prints each character the user presses:
+```lua
+while true do
+  local event, character = os.pullEvent("char")
+  print(character .. " was pressed.")
+end
+```
diff --git a/doc/events/key.md b/doc/events/key.md
new file mode 100644
index 000000000..839dc553f
--- /dev/null
+++ b/doc/events/key.md
@@ -0,0 +1,26 @@
+---
+module: [kind=event] key
+---
+
+This event is fired when any key is pressed while the terminal is focused.
+
+This event returns a numerical "key code" (for instance, F1 is 290). This value may vary between versions and
+so it is recommended to use the constants in the @{keys} API rather than hard coding numeric values.
+
+If the button pressed represented a printable character, then the @{key} event will be followed immediately by a @{char}
+event. If you are consuming text input, use a @{char} event instead!
+
+## Return values
+1. [`string`]: The event name.
+2. [`number`]: The numerical key value of the key pressed.
+3. [`boolean`]: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}).
+
+## Example
+Prints each key when the user presses it, and if the key is being held.
+
+```lua
+while true do
+  local event, key, is_held = os.pullEvent("key")  
+  print(("%s held=%b"):format(keys.getName(key), is_held))
+end
+```
diff --git a/doc/events/key_up.md b/doc/events/key_up.md
new file mode 100644
index 000000000..e957cae6b
--- /dev/null
+++ b/doc/events/key_up.md
@@ -0,0 +1,24 @@
+---
+module: [kind=event] key_up
+see: keys For a lookup table of the given keys.
+---
+
+Fired whenever a key is released (or the terminal is closed while a key was being pressed).
+
+This event returns a numerical "key code" (for instance, F1 is 290). This value may vary between versions and
+so it is recommended to use the constants in the @{keys} API rather than hard coding numeric values.
+
+## Return values
+1. @{string}: The event name.
+2. @{number}: The numerical key value of the key pressed.
+
+## Example
+Prints each key released on the keyboard whenever a @{key_up} event is fired.
+
+```lua
+while true do
+  local event, key = os.pullEvent("key_up")
+  local name = keys.getName(key) or "unknown key"
+  print(name .. " was released.")
+end
+```
diff --git a/doc/events/mouse_click.md b/doc/events/mouse_click.md
new file mode 100644
index 000000000..83d371260
--- /dev/null
+++ b/doc/events/mouse_click.md
@@ -0,0 +1,34 @@
+---
+module: [kind=event] mouse_click
+---
+
+This event is fired when the terminal is clicked with a mouse. This event is only fired on advanced computers (including
+advanced turtles and pocket computers).
+
+## Return values
+1. @{string}: The event name.
+2. @{number}: The mouse button that was clicked.
+3. @{number}: The X-coordinate of the click.
+4. @{number}: The Y-coordinate of the click.
+
+## Mouse buttons
+Several mouse events (@{mouse_click}, @{mouse_up}, @{mouse_scroll}) contain a "mouse button" code. This takes a
+numerical value depending on which button on your mouse was last pressed when this event occurred.
+
+
+    
+    
+    
+    
+    
+
Button codeMouse button
1Left button
2Middle button
3Right button
+ +## Example +Print the button and the coordinates whenever the mouse is clicked. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_click") + print(("The mouse button %s was pressed at %d, %d"):format(button, x, y)) +end +``` diff --git a/doc/events/mouse_drag.md b/doc/events/mouse_drag.md new file mode 100644 index 000000000..6ccb3ee6d --- /dev/null +++ b/doc/events/mouse_drag.md @@ -0,0 +1,24 @@ +--- +module: [kind=event] mouse_drag +see: mouse_click For when a mouse button is initially pressed. +--- + +This event is fired every time the mouse is moved while a mouse button is being held. + +## Return values +1. @{string}: The event name. +2. @{number}: The [mouse button](mouse_click.html#Mouse_buttons) that is being pressed. +3. @{number}: The X-coordinate of the mouse. +4. @{number}: The Y-coordinate of the mouse. + +## Example +Print the button and the coordinates whenever the mouse is dragged. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_drag") + print(("The mouse button %s was dragged at %d, %d"):format(button, x, y)) +end +``` + + diff --git a/doc/events/mouse_scroll.md b/doc/events/mouse_scroll.md new file mode 100644 index 000000000..6248220a5 --- /dev/null +++ b/doc/events/mouse_scroll.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] mouse_scroll +--- + +This event is fired when a mouse wheel is scrolled in the terminal. + +## Return values +1. @{string}: The event name. +2. @{number}: The direction of the scroll. (-1 = up, 1 = down) +3. @{number}: The X-coordinate of the mouse when scrolling. +4. @{number}: The Y-coordinate of the mouse when scrolling. + +## Example +Prints the direction of each scroll, and the position of the mouse at the time. + +```lua +while true do + local event, dir, x, y = os.pullEvent("mouse_scroll") + print(("The mouse was scrolled in direction %s at %d, %d"):format(dir, x, y)) +end +``` diff --git a/doc/events/mouse_up.md b/doc/events/mouse_up.md new file mode 100644 index 000000000..f3b382387 --- /dev/null +++ b/doc/events/mouse_up.md @@ -0,0 +1,24 @@ +--- +module: [kind=event] mouse_up +--- + +This event is fired when a mouse button is released or a held mouse leaves the computer's terminal. + +## Return values +1. @{string}: The event name. +2. @{number}: The [mouse button](mouse_click.html#Mouse_buttons) that was released. +3. @{number}: The X-coordinate of the mouse. +4. @{number}: The Y-coordinate of the mouse. + +## Example +Prints the coordinates and button number whenever the mouse is released. + +```lua +while true do + local event, button, x, y = os.pullEvent("mouse_up") + print(("The mouse button %s was released at %d, %d"):format(button, x, y)) +end +``` + +[`string`]: string +[`number`]: number diff --git a/illuaminate.sexp b/illuaminate.sexp index 0d6850bde..61f671582 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -2,6 +2,7 @@ (sources /doc/stub/ + /doc/events/ /build/docs/luaJavadoc/ /src/main/resources/*/computercraft/lua/bios.lua /src/main/resources/*/computercraft/lua/rom/ @@ -25,7 +26,8 @@ (module-kinds (peripheral Peripherals) - (generic_peripheral "Generic Peripherals")) + (generic_peripheral "Generic Peripherals") + (event Events)) (library-path /doc/stub/ From e1e7ef59c6bdb0dff81268e6442235292f28a6b8 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 Jan 2021 09:54:38 +0000 Subject: [PATCH 429/711] Measure code coverage from in-game tests More importantly, `./gradlew check' actually runs the in-game tests, which makes the CI steps look a little more sensible again. Somewhat depressing that one of the longest files (15th) in CC:T is the build script. --- .github/workflows/main-ci.yml | 9 ++-- build.gradle | 60 ++++++++++++++++++++++--- doc/events/key.md | 2 +- src/test/server-files/server.properties | 3 +- 4 files changed, 58 insertions(+), 16 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 196c65915..66f06fba0 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -24,13 +24,10 @@ jobs: ${{ runner.os }}-gradle- - name: Build with Gradle - run: ./gradlew build --no-daemon || ./gradlew build --no-daemon - - - name: Run in-game tests run: | - ./gradlew setupServer --no-daemon - ./gradlew prepareRunTestServerRun --no-daemon || ./gradlew prepareRunTestServerRun --no-daemon - ./gradlew runTestServerRun --no-daemon + ./gradlew assemble --no-daemon || ./gradlew assemble --no-daemon + ./gradlew downloadAssets --no-daemon || ./gradlew downloadAssets --no-daemon + ./gradlew build - name: Upload Jar uses: actions/upload-artifact@v1 diff --git a/build.gradle b/build.gradle index f0df19a88..856a8173b 100644 --- a/build.gradle +++ b/build.gradle @@ -86,13 +86,6 @@ minecraft { } } } - - testServerRun { - parent runs.testServer - property 'forge.logging.console.level', 'info' - property 'cctest.run', 'true' - forceExit false - } } mappings channel: 'official', version: project.mc_version @@ -392,6 +385,7 @@ test { } jacocoTestReport { + dependsOn('test') reports { xml.enabled true html.enabled true @@ -440,6 +434,9 @@ task licenseFormatAPI(type: LicenseFormat); } task setupServer(type: Copy) { + group "test server" + description "Sets up the environment for the test server." + from("src/test/server-files") { include "eula.txt" include "server.properties" @@ -447,6 +444,55 @@ task setupServer(type: Copy) { into "test-files/server" } +tasks.register('testInGame', JavaExec.class).configure { + it.group('test server') + it.description("Runs tests on a temporary Minecraft server.") + it.dependsOn(setupServer, 'prepareRunTestServer') + + // Copy from runTestServer. We do it in this slightly odd way as runTestServer + // isn't created until the task is configured (which is no good for us). + JavaExec exec = tasks.getByName('runTestServer') + it.setWorkingDir(exec.getWorkingDir()) + it.setSystemProperties(exec.getSystemProperties()) + it.setBootstrapClasspath(exec.getBootstrapClasspath()) + it.setClasspath(exec.getClasspath()) + it.setMain(exec.getMain()) + it.setEnvironment(exec.getEnvironment()) + it.setArgs(exec.getArgs()) + it.setJvmArgs(exec.getJvmArgs()) + + it.systemProperty('forge.logging.console.level', 'info') + it.systemProperty('cctest.run', 'true') + + // Jacoco and modlauncher don't play well together as the classes loaded in-game don't + // match up with those written to disk. We get Jacoco to dump all classes to disk, and + // use that when generating the report. + def coverageOut = new File(buildDir, 'jacocoClassDump/testInGame') + jacoco.applyTo(it) + it.jacoco.setIncludes(["dan200.computercraft.*"]) + it.jacoco.setClassDumpDir(coverageOut) + // Older versions of modlauncher don't include a protection domain (and thus no code + // source). Jacoco skips such classes by default, so we need to explicitly include them. + it.jacoco.setIncludeNoLocationClasses(true) +} + +tasks.register('jacocoTestInGameReport', JacocoReport.class).configure { + it.group('test server') + it.description('Generate coverage reports for in-game tests (testInGame)') + it.dependsOn('testInGame') + + it.executionData(new File(buildDir, 'jacoco/testInGame.exec')) + it.setSourceDirectories(project.files(sourceSets.main.allJava.srcDirs)) + it.setClassDirectories(project.files(new File(buildDir, 'jacocoClassDump/testInGame'))) + + it.reports { + xml.enabled true + html.enabled true + } +} +check.dependsOn('jacocoTestInGameReport') + + // Upload tasks task checkRelease { diff --git a/doc/events/key.md b/doc/events/key.md index 839dc553f..2b4b5aa22 100644 --- a/doc/events/key.md +++ b/doc/events/key.md @@ -21,6 +21,6 @@ Prints each key when the user presses it, and if the key is being held. ```lua while true do local event, key, is_held = os.pullEvent("key") - print(("%s held=%b"):format(keys.getName(key), is_held)) + print(("%s held=%s"):format(keys.getName(key), is_held)) end ``` diff --git a/src/test/server-files/server.properties b/src/test/server-files/server.properties index c7efd2230..46446b36a 100644 --- a/src/test/server-files/server.properties +++ b/src/test/server-files/server.properties @@ -1,5 +1,4 @@ -#Minecraft server properties -#Fri Jan 08 18:54:30 GMT 2021 +# Minecraft server properties allow-flight=false allow-nether=true broadcast-console-to-ops=true From b90611b4b4c176ec1c80df002cc4ac36aa0c4dc8 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 Jan 2021 15:32:11 +0000 Subject: [PATCH 430/711] Preserve registration order of upgrades Makes them display in a more reasonable order within JEI. Closes #647 (note, the title is an entirley separate issue)! --- .../java/dan200/computercraft/shared/PocketUpgrades.java | 4 +++- .../java/dan200/computercraft/shared/TurtleUpgrades.java | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java index 2358d28be..2bb1a0f61 100644 --- a/src/main/java/dan200/computercraft/shared/PocketUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/PocketUpgrades.java @@ -7,7 +7,9 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.pocket.IPocketUpgrade; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap; import net.minecraft.item.ItemStack; +import net.minecraft.util.Util; import net.minecraftforge.fml.ModContainer; import net.minecraftforge.fml.ModLoadingContext; @@ -18,7 +20,7 @@ import java.util.*; public final class PocketUpgrades { private static final Map upgrades = new HashMap<>(); - private static final IdentityHashMap upgradeOwners = new IdentityHashMap<>(); + private static final Map upgradeOwners = new Object2ObjectLinkedOpenCustomHashMap<>( Util.identityStrategy() ); private PocketUpgrades() {} diff --git a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java index c13774b5a..6f5b3b3c2 100644 --- a/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java +++ b/src/main/java/dan200/computercraft/shared/TurtleUpgrades.java @@ -8,12 +8,17 @@ package dan200.computercraft.shared; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.shared.computer.core.ComputerFamily; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap; import net.minecraft.item.ItemStack; +import net.minecraft.util.Util; import net.minecraftforge.fml.ModLoadingContext; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; import java.util.stream.Stream; public final class TurtleUpgrades @@ -37,7 +42,7 @@ public final class TurtleUpgrades private static ITurtleUpgrade[] vanilla; private static final Map upgrades = new HashMap<>(); - private static final IdentityHashMap wrappers = new IdentityHashMap<>(); + private static final Map wrappers = new Object2ObjectLinkedOpenCustomHashMap<>( Util.identityStrategy() ); private static boolean needsRebuild; private TurtleUpgrades() {} From 9d1ee6f61db478f364afa15a439a123ab21175ae Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 Jan 2021 16:35:49 +0000 Subject: [PATCH 431/711] Remove m_ (#658) IT'S GONE! Not looking forward to the merge conflicts on this one. --- build.gradle | 1 + config/checkstyle/checkstyle.xml | 13 +- .../client/ClientTableFormatter.java | 2 +- .../computercraft/client/gui/GuiPrintout.java | 36 +- .../computercraft/client/gui/GuiTurtle.java | 22 +- .../client/render/TurtleMultiModel.java | 62 ++-- .../client/render/TurtleSmartItemModel.java | 70 ++-- .../core/apis/ComputerAccess.java | 34 +- .../computercraft/core/apis/HTTPAPI.java | 10 +- .../dan200/computercraft/core/apis/OSAPI.java | 76 ++--- .../computercraft/core/computer/Computer.java | 56 ++-- .../core/filesystem/ComboMount.java | 28 +- .../core/filesystem/FileMount.java | 74 ++--- .../core/filesystem/FileSystem.java | 40 +-- .../filesystem/FileSystemWrapperMount.java | 30 +- .../core/filesystem/SubMount.java | 4 +- .../core/lua/CobaltLuaMachine.java | 96 +++--- .../computercraft/core/terminal/Terminal.java | 312 +++++++++--------- .../core/terminal/TextBuffer.java | 64 ++-- .../command/builder/CommandBuilder.java | 2 +- .../shared/common/ClientTerminal.java | 38 +-- .../shared/common/ServerTerminal.java | 38 +-- .../shared/computer/blocks/ComputerProxy.java | 6 +- .../computer/blocks/TileComputerBase.java | 74 ++--- .../shared/computer/core/ClientComputer.java | 45 ++- .../computer/core/ComputerRegistry.java | 33 +- .../shared/computer/core/ServerComputer.java | 117 +++---- .../client/ChatTableClientMessage.java | 3 - .../peripheral/diskdrive/TileDiskDrive.java | 136 ++++---- .../peripheral/modem/ModemPeripheral.java | 58 ++-- .../peripheral/modem/wired/TileCable.java | 102 +++--- .../modem/wired/TileWiredModemFull.java | 98 +++--- .../wireless/WirelessModemPeripheral.java | 8 +- .../modem/wireless/WirelessNetwork.java | 21 +- .../peripheral/monitor/TileMonitor.java | 242 +++++++------- .../peripheral/printer/TilePrinter.java | 114 +++---- .../peripheral/speaker/SpeakerPeripheral.java | 20 +- .../pocket/core/PocketServerComputer.java | 48 +-- .../pocket/items/ItemPocketComputer.java | 4 - .../shared/turtle/blocks/TileTurtle.java | 116 +++---- .../shared/turtle/core/TurtleBrain.java | 260 +++++++-------- .../turtle/core/TurtleCompareCommand.java | 6 +- .../turtle/core/TurtleCompareToCommand.java | 17 +- .../turtle/core/TurtleDetectCommand.java | 6 +- .../shared/turtle/core/TurtleDropCommand.java | 14 +- .../turtle/core/TurtleEquipCommand.java | 8 +- .../shared/turtle/core/TurtleMoveCommand.java | 10 +- .../turtle/core/TurtlePlaceCommand.java | 12 +- .../shared/turtle/core/TurtlePlayer.java | 4 +- .../shared/turtle/core/TurtleSuckCommand.java | 18 +- .../turtle/core/TurtleTransferToCommand.java | 12 +- .../shared/turtle/core/TurtleTurnCommand.java | 6 +- .../turtle/upgrades/TurtleCraftingTable.java | 20 +- .../upgrades/TurtleInventoryCrafting.java | 44 ++- .../shared/turtle/upgrades/TurtleModem.java | 58 ++-- .../shared/turtle/upgrades/TurtleSpeaker.java | 28 +- .../shared/util/CreativeTabMain.java | 3 - 57 files changed, 1397 insertions(+), 1482 deletions(-) diff --git a/build.gradle b/build.gradle index 856a8173b..826343e4c 100644 --- a/build.gradle +++ b/build.gradle @@ -471,6 +471,7 @@ tasks.register('testInGame', JavaExec.class).configure { jacoco.applyTo(it) it.jacoco.setIncludes(["dan200.computercraft.*"]) it.jacoco.setClassDumpDir(coverageOut) + it.outputs.dir(coverageOut) // Older versions of modlauncher don't include a protection domain (and thus no code // source). Jacoco skips such classes by default, so we need to explicitly include them. it.jacoco.setIncludeNoLocationClasses(true) diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml index 89de6f153..aaafdfd01 100644 --- a/config/checkstyle/checkstyle.xml +++ b/config/checkstyle/checkstyle.xml @@ -97,20 +97,11 @@ - - - - - - - - - - + - + diff --git a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java index 164c0f70e..e5301601d 100644 --- a/src/main/java/dan200/computercraft/client/ClientTableFormatter.java +++ b/src/main/java/dan200/computercraft/client/ClientTableFormatter.java @@ -25,7 +25,7 @@ public class ClientTableFormatter implements TableFormatter { public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); - private static Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap(); + private static final Int2IntOpenHashMap lastHeights = new Int2IntOpenHashMap(); private static FontRenderer renderer() { diff --git a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java index 9574d3f04..a6252bbc8 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiPrintout.java @@ -24,11 +24,11 @@ public class GuiPrintout extends ContainerScreen { private static final Matrix4f IDENTITY = TransformationMatrix.identity().getMatrix(); - private final boolean m_book; - private final int m_pages; - private final TextBuffer[] m_text; - private final TextBuffer[] m_colours; - private int m_page; + private final boolean book; + private final int pages; + private final TextBuffer[] text; + private final TextBuffer[] colours; + private int page; public GuiPrintout( ContainerHeldItem container, PlayerInventory player, ITextComponent title ) { @@ -37,16 +37,16 @@ public class GuiPrintout extends ContainerScreen imageHeight = Y_SIZE; String[] text = ItemPrintout.getText( container.getStack() ); - m_text = new TextBuffer[text.length]; - for( int i = 0; i < m_text.length; i++ ) m_text[i] = new TextBuffer( text[i] ); + this.text = new TextBuffer[text.length]; + for( int i = 0; i < this.text.length; i++ ) this.text[i] = new TextBuffer( text[i] ); String[] colours = ItemPrintout.getColours( container.getStack() ); - m_colours = new TextBuffer[colours.length]; - for( int i = 0; i < m_colours.length; i++ ) m_colours[i] = new TextBuffer( colours[i] ); + this.colours = new TextBuffer[colours.length]; + for( int i = 0; i < this.colours.length; i++ ) this.colours[i] = new TextBuffer( colours[i] ); - m_page = 0; - m_pages = Math.max( m_text.length / ItemPrintout.LINES_PER_PAGE, 1 ); - m_book = ((ItemPrintout) container.getStack().getItem()).getType() == ItemPrintout.Type.BOOK; + page = 0; + pages = Math.max( this.text.length / ItemPrintout.LINES_PER_PAGE, 1 ); + book = ((ItemPrintout) container.getStack().getItem()).getType() == ItemPrintout.Type.BOOK; } @Override @@ -56,13 +56,13 @@ public class GuiPrintout extends ContainerScreen if( key == GLFW.GLFW_KEY_RIGHT ) { - if( m_page < m_pages - 1 ) m_page++; + if( page < pages - 1 ) page++; return true; } if( key == GLFW.GLFW_KEY_LEFT ) { - if( m_page > 0 ) m_page--; + if( page > 0 ) page--; return true; } @@ -76,14 +76,14 @@ public class GuiPrintout extends ContainerScreen if( delta < 0 ) { // Scroll up goes to the next page - if( m_page < m_pages - 1 ) m_page++; + if( page < pages - 1 ) page++; return true; } if( delta > 0 ) { // Scroll down goes to the previous page - if( m_page > 0 ) m_page--; + if( page > 0 ) page--; return true; } @@ -98,8 +98,8 @@ public class GuiPrintout extends ContainerScreen RenderSystem.enableDepthTest(); IRenderTypeBuffer.Impl renderer = Minecraft.getInstance().renderBuffers().bufferSource(); - drawBorder( IDENTITY, renderer, leftPos, topPos, getBlitOffset(), m_page, m_pages, m_book ); - drawText( IDENTITY, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * m_page, m_text, m_colours ); + drawBorder( IDENTITY, renderer, leftPos, topPos, getBlitOffset(), page, pages, book ); + drawText( IDENTITY, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, ItemPrintout.LINES_PER_PAGE * page, text, colours ); renderer.endBatch(); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 4548bbaa2..6af2a5790 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -20,13 +20,13 @@ import org.lwjgl.glfw.GLFW; public class GuiTurtle extends ContainerScreen { - private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( "computercraft", "textures/gui/turtle_normal.png" ); - private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/turtle_advanced.png" ); + private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/turtle_normal.png" ); + private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/turtle_advanced.png" ); - private ContainerTurtle m_container; + private final ContainerTurtle container; - private final ComputerFamily m_family; - private final ClientComputer m_computer; + private final ComputerFamily family; + private final ClientComputer computer; private WidgetTerminal terminal; private WidgetWrapper terminalWrapper; @@ -35,9 +35,9 @@ public class GuiTurtle extends ContainerScreen { super( container, player, title ); - m_container = container; - m_family = container.getFamily(); - m_computer = (ClientComputer) container.getComputer(); + this.container = container; + family = container.getFamily(); + computer = (ClientComputer) container.getComputer(); imageWidth = 254; imageHeight = 217; @@ -53,7 +53,7 @@ public class GuiTurtle extends ContainerScreen int termPxHeight = ComputerCraft.turtleTermHeight * FixedWidthFontRenderer.FONT_HEIGHT; terminal = new WidgetTerminal( - minecraft, () -> m_computer, + minecraft, () -> computer, ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight, 2, 2, 2, 2 @@ -95,7 +95,7 @@ public class GuiTurtle extends ContainerScreen private void drawSelectionSlot( boolean advanced ) { // Draw selection slot - int slot = m_container.getSelectedSlot(); + int slot = container.getSelectedSlot(); if( slot >= 0 ) { RenderSystem.color4f( 1.0F, 1.0F, 1.0F, 1.0F ); @@ -110,7 +110,7 @@ public class GuiTurtle extends ContainerScreen protected void renderBg( float partialTicks, int mouseX, int mouseY ) { // Draw term - boolean advanced = m_family == ComputerFamily.ADVANCED; + boolean advanced = family == ComputerFamily.ADVANCED; terminal.draw( terminalWrapper.getX(), terminalWrapper.getY() ); // Draw border/inventory diff --git a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java index b099ce309..8613f7464 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleMultiModel.java @@ -23,22 +23,22 @@ import java.util.*; public class TurtleMultiModel implements IBakedModel { - private final IBakedModel m_baseModel; - private final IBakedModel m_overlayModel; - private final TransformationMatrix m_generalTransform; - private final TransformedModel m_leftUpgradeModel; - private final TransformedModel m_rightUpgradeModel; - private List m_generalQuads = null; - private Map> m_faceQuads = new EnumMap<>( Direction.class ); + private final IBakedModel baseModel; + private final IBakedModel overlayModel; + private final TransformationMatrix generalTransform; + private final TransformedModel leftUpgradeModel; + private final TransformedModel rightUpgradeModel; + private List generalQuads = null; + private final Map> faceQuads = new EnumMap<>( Direction.class ); public TurtleMultiModel( IBakedModel baseModel, IBakedModel overlayModel, TransformationMatrix generalTransform, TransformedModel leftUpgradeModel, TransformedModel rightUpgradeModel ) { // Get the models - m_baseModel = baseModel; - m_overlayModel = overlayModel; - m_leftUpgradeModel = leftUpgradeModel; - m_rightUpgradeModel = rightUpgradeModel; - m_generalTransform = generalTransform; + this.baseModel = baseModel; + this.overlayModel = overlayModel; + this.leftUpgradeModel = leftUpgradeModel; + this.rightUpgradeModel = rightUpgradeModel; + this.generalTransform = generalTransform; } @Nonnull @@ -55,13 +55,13 @@ public class TurtleMultiModel implements IBakedModel { if( side != null ) { - if( !m_faceQuads.containsKey( side ) ) m_faceQuads.put( side, buildQuads( state, side, rand ) ); - return m_faceQuads.get( side ); + if( !faceQuads.containsKey( side ) ) faceQuads.put( side, buildQuads( state, side, rand ) ); + return faceQuads.get( side ); } else { - if( m_generalQuads == null ) m_generalQuads = buildQuads( state, side, rand ); - return m_generalQuads; + if( generalQuads == null ) generalQuads = buildQuads( state, side, rand ); + return generalQuads; } } @@ -70,20 +70,20 @@ public class TurtleMultiModel implements IBakedModel ArrayList quads = new ArrayList<>(); - transformQuadsTo( quads, m_baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); - if( m_overlayModel != null ) + transformQuadsTo( quads, baseModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), generalTransform ); + if( overlayModel != null ) { - transformQuadsTo( quads, m_overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), m_generalTransform ); + transformQuadsTo( quads, overlayModel.getQuads( state, side, rand, EmptyModelData.INSTANCE ), generalTransform ); } - if( m_leftUpgradeModel != null ) + if( leftUpgradeModel != null ) { - TransformationMatrix upgradeTransform = m_generalTransform.compose( m_leftUpgradeModel.getMatrix() ); - transformQuadsTo( quads, m_leftUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); + TransformationMatrix upgradeTransform = generalTransform.compose( leftUpgradeModel.getMatrix() ); + transformQuadsTo( quads, leftUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); } - if( m_rightUpgradeModel != null ) + if( rightUpgradeModel != null ) { - TransformationMatrix upgradeTransform = m_generalTransform.compose( m_rightUpgradeModel.getMatrix() ); - transformQuadsTo( quads, m_rightUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); + TransformationMatrix upgradeTransform = generalTransform.compose( rightUpgradeModel.getMatrix() ); + transformQuadsTo( quads, rightUpgradeModel.getModel().getQuads( state, side, rand, EmptyModelData.INSTANCE ), upgradeTransform ); } quads.trimToSize(); return quads; @@ -92,25 +92,25 @@ public class TurtleMultiModel implements IBakedModel @Override public boolean useAmbientOcclusion() { - return m_baseModel.useAmbientOcclusion(); + return baseModel.useAmbientOcclusion(); } @Override public boolean isGui3d() { - return m_baseModel.isGui3d(); + return baseModel.isGui3d(); } @Override public boolean isCustomRenderer() { - return m_baseModel.isCustomRenderer(); + return baseModel.isCustomRenderer(); } @Override public boolean usesBlockLight() { - return m_baseModel.usesBlockLight(); + return baseModel.usesBlockLight(); } @Nonnull @@ -118,7 +118,7 @@ public class TurtleMultiModel implements IBakedModel @Deprecated public TextureAtlasSprite getParticleIcon() { - return m_baseModel.getParticleIcon(); + return baseModel.getParticleIcon(); } @Nonnull @@ -126,7 +126,7 @@ public class TurtleMultiModel implements IBakedModel @Deprecated public net.minecraft.client.renderer.model.ItemCameraTransforms getTransforms() { - return m_baseModel.getTransforms(); + return baseModel.getTransforms(); } @Nonnull diff --git a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java index 047e5470c..f6a244d1b 100644 --- a/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java +++ b/src/main/java/dan200/computercraft/client/render/TurtleSmartItemModel.java @@ -47,21 +47,21 @@ public class TurtleSmartItemModel implements IBakedModel private static class TurtleModelCombination { - final boolean m_colour; - final ITurtleUpgrade m_leftUpgrade; - final ITurtleUpgrade m_rightUpgrade; - final ResourceLocation m_overlay; - final boolean m_christmas; - final boolean m_flip; + final boolean colour; + final ITurtleUpgrade leftUpgrade; + final ITurtleUpgrade rightUpgrade; + final ResourceLocation overlay; + final boolean christmas; + final boolean flip; TurtleModelCombination( boolean colour, ITurtleUpgrade leftUpgrade, ITurtleUpgrade rightUpgrade, ResourceLocation overlay, boolean christmas, boolean flip ) { - m_colour = colour; - m_leftUpgrade = leftUpgrade; - m_rightUpgrade = rightUpgrade; - m_overlay = overlay; - m_christmas = christmas; - m_flip = flip; + this.colour = colour; + this.leftUpgrade = leftUpgrade; + this.rightUpgrade = rightUpgrade; + this.overlay = overlay; + this.christmas = christmas; + this.flip = flip; } @Override @@ -71,12 +71,12 @@ public class TurtleSmartItemModel implements IBakedModel if( !(other instanceof TurtleModelCombination) ) return false; TurtleModelCombination otherCombo = (TurtleModelCombination) other; - return otherCombo.m_colour == m_colour && - otherCombo.m_leftUpgrade == m_leftUpgrade && - otherCombo.m_rightUpgrade == m_rightUpgrade && - Objects.equal( otherCombo.m_overlay, m_overlay ) && - otherCombo.m_christmas == m_christmas && - otherCombo.m_flip == m_flip; + return otherCombo.colour == colour && + otherCombo.leftUpgrade == leftUpgrade && + otherCombo.rightUpgrade == rightUpgrade && + Objects.equal( otherCombo.overlay, overlay ) && + otherCombo.christmas == christmas && + otherCombo.flip == flip; } @Override @@ -84,12 +84,12 @@ public class TurtleSmartItemModel implements IBakedModel { final int prime = 31; int result = 0; - result = prime * result + (m_colour ? 1 : 0); - result = prime * result + (m_leftUpgrade != null ? m_leftUpgrade.hashCode() : 0); - result = prime * result + (m_rightUpgrade != null ? m_rightUpgrade.hashCode() : 0); - result = prime * result + (m_overlay != null ? m_overlay.hashCode() : 0); - result = prime * result + (m_christmas ? 1 : 0); - result = prime * result + (m_flip ? 1 : 0); + result = prime * result + (colour ? 1 : 0); + result = prime * result + (leftUpgrade != null ? leftUpgrade.hashCode() : 0); + result = prime * result + (rightUpgrade != null ? rightUpgrade.hashCode() : 0); + result = prime * result + (overlay != null ? overlay.hashCode() : 0); + result = prime * result + (christmas ? 1 : 0); + result = prime * result + (flip ? 1 : 0); return result; } } @@ -97,15 +97,15 @@ public class TurtleSmartItemModel implements IBakedModel private final IBakedModel familyModel; private final IBakedModel colourModel; - private final HashMap m_cachedModels = new HashMap<>(); - private final ItemOverrideList m_overrides; + private final HashMap cachedModels = new HashMap<>(); + private final ItemOverrideList overrides; public TurtleSmartItemModel( IBakedModel familyModel, IBakedModel colourModel ) { this.familyModel = familyModel; this.colourModel = colourModel; - m_overrides = new ItemOverrideList() + overrides = new ItemOverrideList() { @Nonnull @Override @@ -121,8 +121,8 @@ public class TurtleSmartItemModel implements IBakedModel boolean flip = label != null && (label.equals( "Dinnerbone" ) || label.equals( "Grumm" )); TurtleModelCombination combo = new TurtleModelCombination( colour != -1, leftUpgrade, rightUpgrade, overlay, christmas, flip ); - IBakedModel model = m_cachedModels.get( combo ); - if( model == null ) m_cachedModels.put( combo, model = buildModel( combo ) ); + IBakedModel model = cachedModels.get( combo ); + if( model == null ) cachedModels.put( combo, model = buildModel( combo ) ); return model; } }; @@ -132,20 +132,20 @@ public class TurtleSmartItemModel implements IBakedModel @Override public ItemOverrideList getOverrides() { - return m_overrides; + return overrides; } private IBakedModel buildModel( TurtleModelCombination combo ) { Minecraft mc = Minecraft.getInstance(); ModelManager modelManager = mc.getItemRenderer().getItemModelShaper().getModelManager(); - ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.m_overlay, combo.m_christmas ); + ModelResourceLocation overlayModelLocation = TileEntityTurtleRenderer.getTurtleOverlayModel( combo.overlay, combo.christmas ); - IBakedModel baseModel = combo.m_colour ? colourModel : familyModel; + IBakedModel baseModel = combo.colour ? colourModel : familyModel; IBakedModel overlayModel = overlayModelLocation != null ? modelManager.getModel( overlayModelLocation ) : null; - TransformationMatrix transform = combo.m_flip ? flip : identity; - TransformedModel leftModel = combo.m_leftUpgrade != null ? combo.m_leftUpgrade.getModel( null, TurtleSide.LEFT ) : null; - TransformedModel rightModel = combo.m_rightUpgrade != null ? combo.m_rightUpgrade.getModel( null, TurtleSide.RIGHT ) : null; + TransformationMatrix transform = combo.flip ? flip : identity; + TransformedModel leftModel = combo.leftUpgrade != null ? combo.leftUpgrade.getModel( null, TurtleSide.LEFT ) : null; + TransformedModel rightModel = combo.rightUpgrade != null ? combo.rightUpgrade.getModel( null, TurtleSide.RIGHT ) : null; return new TurtleMultiModel( baseModel, overlayModel, transform, leftModel, rightModel ); } diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index a0f762070..39c4a2ff3 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -19,22 +19,22 @@ import java.util.Set; public abstract class ComputerAccess implements IComputerAccess { - private final IAPIEnvironment m_environment; - private final Set m_mounts = new HashSet<>(); + private final IAPIEnvironment environment; + private final Set mounts = new HashSet<>(); protected ComputerAccess( IAPIEnvironment environment ) { - this.m_environment = environment; + this.environment = environment; } public void unmountAll() { - FileSystem fileSystem = m_environment.getFileSystem(); - for( String mount : m_mounts ) + FileSystem fileSystem = environment.getFileSystem(); + for( String mount : mounts ) { fileSystem.unmount( mount ); } - m_mounts.clear(); + mounts.clear(); } @Override @@ -46,7 +46,7 @@ public abstract class ComputerAccess implements IComputerAccess // Mount the location String location; - FileSystem fileSystem = m_environment.getFileSystem(); + FileSystem fileSystem = environment.getFileSystem(); if( fileSystem == null ) throw new IllegalStateException( "File system has not been created" ); synchronized( fileSystem ) @@ -64,7 +64,7 @@ public abstract class ComputerAccess implements IComputerAccess } } - if( location != null ) m_mounts.add( location ); + if( location != null ) mounts.add( location ); return location; } @@ -77,7 +77,7 @@ public abstract class ComputerAccess implements IComputerAccess // Mount the location String location; - FileSystem fileSystem = m_environment.getFileSystem(); + FileSystem fileSystem = environment.getFileSystem(); if( fileSystem == null ) throw new IllegalStateException( "File system has not been created" ); synchronized( fileSystem ) @@ -95,7 +95,7 @@ public abstract class ComputerAccess implements IComputerAccess } } - if( location != null ) m_mounts.add( location ); + if( location != null ) mounts.add( location ); return location; } @@ -103,37 +103,37 @@ public abstract class ComputerAccess implements IComputerAccess public void unmount( String location ) { if( location == null ) return; - if( !m_mounts.contains( location ) ) throw new IllegalStateException( "You didn't mount this location" ); + if( !mounts.contains( location ) ) throw new IllegalStateException( "You didn't mount this location" ); - m_environment.getFileSystem().unmount( location ); - m_mounts.remove( location ); + environment.getFileSystem().unmount( location ); + mounts.remove( location ); } @Override public int getID() { - return m_environment.getComputerID(); + return environment.getComputerID(); } @Override public void queueEvent( @Nonnull String event, Object... arguments ) { Objects.requireNonNull( event, "event cannot be null" ); - m_environment.queueEvent( event, arguments ); + environment.queueEvent( event, arguments ); } @Nonnull @Override public IWorkMonitor getMainThreadMonitor() { - return m_environment.getMainThreadMonitor(); + return environment.getMainThreadMonitor(); } private String findFreeLocation( String desiredLoc ) { try { - FileSystem fileSystem = m_environment.getFileSystem(); + FileSystem fileSystem = environment.getFileSystem(); if( !fileSystem.exists( desiredLoc ) ) return desiredLoc; // We used to check foo2, foo3, foo4, etc here but the disk drive does this itself now diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 4363b9684..0494066ce 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -34,7 +34,7 @@ import static dan200.computercraft.core.apis.TableHelper.*; */ public class HTTPAPI implements ILuaAPI { - private final IAPIEnvironment m_apiEnvironment; + private final IAPIEnvironment apiEnvironment; private final ResourceGroup checkUrls = new ResourceGroup<>(); private final ResourceGroup requests = new ResourceQueue<>( () -> ComputerCraft.httpMaxRequests ); @@ -42,7 +42,7 @@ public class HTTPAPI implements ILuaAPI public HTTPAPI( IAPIEnvironment environment ) { - m_apiEnvironment = environment; + apiEnvironment = environment; } @Override @@ -123,7 +123,7 @@ public class HTTPAPI implements ILuaAPI try { URI uri = HttpRequest.checkUri( address ); - HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect ); + HttpRequest request = new HttpRequest( requests, apiEnvironment, address, postString, headers, binary, redirect ); // Make the request request.queue( r -> r.request( uri, httpMethod ) ); @@ -142,7 +142,7 @@ public class HTTPAPI implements ILuaAPI try { URI uri = HttpRequest.checkUri( address ); - new CheckUrl( checkUrls, m_apiEnvironment, address, uri ).queue( CheckUrl::run ); + new CheckUrl( checkUrls, apiEnvironment, address, uri ).queue( CheckUrl::run ); return new Object[] { true }; } @@ -165,7 +165,7 @@ public class HTTPAPI implements ILuaAPI try { URI uri = Websocket.checkUri( address ); - if( !new Websocket( websockets, m_apiEnvironment, uri, address, headers ).queue( Websocket::connect ) ) + if( !new Websocket( websockets, apiEnvironment, uri, address, headers ).queue( Websocket::connect ) ) { throw new LuaException( "Too many websockets already open" ); } diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index d8da0a23d..9b59ffcef 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -32,29 +32,29 @@ public class OSAPI implements ILuaAPI { private final IAPIEnvironment apiEnvironment; - private final Int2ObjectMap m_alarms = new Int2ObjectOpenHashMap<>(); - private int m_clock; - private double m_time; - private int m_day; + private final Int2ObjectMap alarms = new Int2ObjectOpenHashMap<>(); + private int clock; + private double time; + private int day; - private int m_nextAlarmToken = 0; + private int nextAlarmToken = 0; private static class Alarm implements Comparable { - final double m_time; - final int m_day; + final double time; + final int day; Alarm( double time, int day ) { - m_time = time; - m_day = day; + this.time = time; + this.day = day; } @Override public int compareTo( @Nonnull Alarm o ) { - double t = m_day * 24.0 + m_time; - double ot = m_day * 24.0 + m_time; + double t = day * 24.0 + time; + double ot = day * 24.0 + time; return Double.compare( t, ot ); } } @@ -73,38 +73,38 @@ public class OSAPI implements ILuaAPI @Override public void startup() { - m_time = apiEnvironment.getComputerEnvironment().getTimeOfDay(); - m_day = apiEnvironment.getComputerEnvironment().getDay(); - m_clock = 0; + time = apiEnvironment.getComputerEnvironment().getTimeOfDay(); + day = apiEnvironment.getComputerEnvironment().getDay(); + clock = 0; - synchronized( m_alarms ) + synchronized( alarms ) { - m_alarms.clear(); + alarms.clear(); } } @Override public void update() { - m_clock++; + clock++; // Wait for all of our alarms - synchronized( m_alarms ) + synchronized( alarms ) { - double previousTime = m_time; - int previousDay = m_day; + double previousTime = time; + int previousDay = day; double time = apiEnvironment.getComputerEnvironment().getTimeOfDay(); int day = apiEnvironment.getComputerEnvironment().getDay(); if( time > previousTime || day > previousDay ) { - double now = m_day * 24.0 + m_time; - Iterator> it = m_alarms.int2ObjectEntrySet().iterator(); + double now = this.day * 24.0 + this.time; + Iterator> it = alarms.int2ObjectEntrySet().iterator(); while( it.hasNext() ) { Int2ObjectMap.Entry entry = it.next(); Alarm alarm = entry.getValue(); - double t = alarm.m_day * 24.0 + alarm.m_time; + double t = alarm.day * 24.0 + alarm.time; if( now >= t ) { apiEnvironment.queueEvent( "alarm", entry.getIntKey() ); @@ -113,17 +113,17 @@ public class OSAPI implements ILuaAPI } } - m_time = time; - m_day = day; + this.time = time; + this.day = day; } } @Override public void shutdown() { - synchronized( m_alarms ) + synchronized( alarms ) { - m_alarms.clear(); + alarms.clear(); } } @@ -219,11 +219,11 @@ public class OSAPI implements ILuaAPI { checkFinite( 0, time ); if( time < 0.0 || time >= 24.0 ) throw new LuaException( "Number out of range" ); - synchronized( m_alarms ) + synchronized( alarms ) { - int day = time > m_time ? m_day : m_day + 1; - m_alarms.put( m_nextAlarmToken, new Alarm( time, day ) ); - return m_nextAlarmToken++; + int day = time > this.time ? this.day : this.day + 1; + alarms.put( nextAlarmToken, new Alarm( time, day ) ); + return nextAlarmToken++; } } @@ -237,9 +237,9 @@ public class OSAPI implements ILuaAPI @LuaFunction public final void cancelAlarm( int token ) { - synchronized( m_alarms ) + synchronized( alarms ) { - m_alarms.remove( token ); + alarms.remove( token ); } } @@ -304,7 +304,7 @@ public class OSAPI implements ILuaAPI @LuaFunction public final double clock() { - return m_clock * 0.05; + return clock * 0.05; } /** @@ -341,7 +341,7 @@ public class OSAPI implements ILuaAPI case "local": // Get Hour of day (local time) return getTimeForCalendar( Calendar.getInstance() ); case "ingame": // Get in-game hour - return m_time; + return time; default: throw new LuaException( "Unsupported operation" ); } @@ -371,7 +371,7 @@ public class OSAPI implements ILuaAPI case "local": // Get numbers of days since 1970-01-01 (local time) return getDayForCalendar( Calendar.getInstance() ); case "ingame":// Get game day - return m_day; + return day; default: throw new LuaException( "Unsupported operation" ); } @@ -410,9 +410,9 @@ public class OSAPI implements ILuaAPI } case "ingame": // Get in-game epoch - synchronized( m_alarms ) + synchronized( alarms ) { - return m_day * 86400000L + (long) (m_time * 3600000.0); + return day * 86400000L + (long) (time * 3600000.0); } default: throw new LuaException( "Unsupported operation" ); diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index a40e104e6..005625230 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -32,28 +32,28 @@ public class Computer private static final int START_DELAY = 50; // Various properties of the computer - private int m_id; - private String m_label = null; + private int id; + private String label = null; // Read-only fields about the computer - private final IComputerEnvironment m_environment; - private final Terminal m_terminal; + private final IComputerEnvironment environment; + private final Terminal terminal; private final ComputerExecutor executor; private final MainThreadExecutor serverExecutor; // Additional state about the computer and its environment. - private boolean m_blinking = false; + private boolean blinking = false; private final Environment internalEnvironment = new Environment( this ); private final AtomicBoolean externalOutputChanged = new AtomicBoolean(); private boolean startRequested; - private int m_ticksSinceStart = -1; + private int ticksSinceStart = -1; public Computer( IComputerEnvironment environment, Terminal terminal, int id ) { - m_id = id; - m_environment = environment; - m_terminal = terminal; + this.id = id; + this.environment = environment; + this.terminal = terminal; executor = new ComputerExecutor( this ); serverExecutor = new MainThreadExecutor( this ); @@ -61,7 +61,7 @@ public class Computer IComputerEnvironment getComputerEnvironment() { - return m_environment; + return environment; } FileSystem getFileSystem() @@ -71,7 +71,7 @@ public class Computer Terminal getTerminal() { - return m_terminal; + return terminal; } public Environment getEnvironment() @@ -132,33 +132,33 @@ public class Computer public int getID() { - return m_id; + return id; } public int assignID() { - if( m_id < 0 ) + if( id < 0 ) { - m_id = m_environment.assignNewID(); + id = environment.assignNewID(); } - return m_id; + return id; } public void setID( int id ) { - m_id = id; + this.id = id; } public String getLabel() { - return m_label; + return label; } public void setLabel( String label ) { - if( !Objects.equal( label, m_label ) ) + if( !Objects.equal( label, this.label ) ) { - m_label = label; + this.label = label; externalOutputChanged.set( true ); } } @@ -166,14 +166,14 @@ public class Computer public void tick() { // We keep track of the number of ticks since the last start, only - if( m_ticksSinceStart >= 0 && m_ticksSinceStart <= START_DELAY ) m_ticksSinceStart++; + if( ticksSinceStart >= 0 && ticksSinceStart <= START_DELAY ) ticksSinceStart++; - if( startRequested && (m_ticksSinceStart < 0 || m_ticksSinceStart > START_DELAY) ) + if( startRequested && (ticksSinceStart < 0 || ticksSinceStart > START_DELAY) ) { startRequested = false; if( !executor.isOn() ) { - m_ticksSinceStart = 0; + ticksSinceStart = 0; executor.queueStart(); } } @@ -187,12 +187,12 @@ public class Computer if( internalEnvironment.updateOutput() ) externalOutputChanged.set( true ); // Set output changed if the terminal has changed from blinking to not - boolean blinking = m_terminal.getCursorBlink() && - m_terminal.getCursorX() >= 0 && m_terminal.getCursorX() < m_terminal.getWidth() && - m_terminal.getCursorY() >= 0 && m_terminal.getCursorY() < m_terminal.getHeight(); - if( blinking != m_blinking ) + boolean blinking = terminal.getCursorBlink() && + terminal.getCursorX() >= 0 && terminal.getCursorX() < terminal.getWidth() && + terminal.getCursorY() >= 0 && terminal.getCursorY() < terminal.getHeight(); + if( blinking != this.blinking ) { - m_blinking = blinking; + this.blinking = blinking; externalOutputChanged.set( true ); } } @@ -209,7 +209,7 @@ public class Computer public boolean isBlinking() { - return isOn() && m_blinking; + return isOn() && blinking; } public void addApi( ILuaAPI api ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java index 17ad177ed..46e63e9ac 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ComboMount.java @@ -19,11 +19,11 @@ import java.util.Set; public class ComboMount implements IMount { - private IMount[] m_parts; + private final IMount[] parts; public ComboMount( IMount[] parts ) { - m_parts = parts; + this.parts = parts; } // IMount implementation @@ -31,9 +31,9 @@ public class ComboMount implements IMount @Override public boolean exists( @Nonnull String path ) throws IOException { - for( int i = m_parts.length - 1; i >= 0; --i ) + for( int i = parts.length - 1; i >= 0; --i ) { - IMount part = m_parts[i]; + IMount part = parts[i]; if( part.exists( path ) ) { return true; @@ -45,9 +45,9 @@ public class ComboMount implements IMount @Override public boolean isDirectory( @Nonnull String path ) throws IOException { - for( int i = m_parts.length - 1; i >= 0; --i ) + for( int i = parts.length - 1; i >= 0; --i ) { - IMount part = m_parts[i]; + IMount part = parts[i]; if( part.isDirectory( path ) ) { return true; @@ -62,9 +62,9 @@ public class ComboMount implements IMount // Combine the lists from all the mounts List foundFiles = null; int foundDirs = 0; - for( int i = m_parts.length - 1; i >= 0; --i ) + for( int i = parts.length - 1; i >= 0; --i ) { - IMount part = m_parts[i]; + IMount part = parts[i]; if( part.exists( path ) && part.isDirectory( path ) ) { if( foundFiles == null ) @@ -102,9 +102,9 @@ public class ComboMount implements IMount @Override public long getSize( @Nonnull String path ) throws IOException { - for( int i = m_parts.length - 1; i >= 0; --i ) + for( int i = parts.length - 1; i >= 0; --i ) { - IMount part = m_parts[i]; + IMount part = parts[i]; if( part.exists( path ) ) { return part.getSize( path ); @@ -117,9 +117,9 @@ public class ComboMount implements IMount @Override public ReadableByteChannel openForRead( @Nonnull String path ) throws IOException { - for( int i = m_parts.length - 1; i >= 0; --i ) + for( int i = parts.length - 1; i >= 0; --i ) { - IMount part = m_parts[i]; + IMount part = parts[i]; if( part.exists( path ) && !part.isDirectory( path ) ) { return part.openForRead( path ); @@ -132,9 +132,9 @@ public class ComboMount implements IMount @Override public BasicFileAttributes getAttributes( @Nonnull String path ) throws IOException { - for( int i = m_parts.length - 1; i >= 0; --i ) + for( int i = parts.length - 1; i >= 0; --i ) { - IMount part = m_parts[i]; + IMount part = parts[i]; if( part.exists( path ) && !part.isDirectory( path ) ) { return part.getAttributes( path ); diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java index 61a237215..bcd19adbe 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileMount.java @@ -32,57 +32,57 @@ public class FileMount implements IWritableMount private class WritableCountingChannel implements WritableByteChannel { - private final WritableByteChannel m_inner; - long m_ignoredBytesLeft; + private final WritableByteChannel inner; + long ignoredBytesLeft; WritableCountingChannel( WritableByteChannel inner, long bytesToIgnore ) { - m_inner = inner; - m_ignoredBytesLeft = bytesToIgnore; + this.inner = inner; + ignoredBytesLeft = bytesToIgnore; } @Override public int write( @Nonnull ByteBuffer b ) throws IOException { count( b.remaining() ); - return m_inner.write( b ); + return inner.write( b ); } void count( long n ) throws IOException { - m_ignoredBytesLeft -= n; - if( m_ignoredBytesLeft < 0 ) + ignoredBytesLeft -= n; + if( ignoredBytesLeft < 0 ) { - long newBytes = -m_ignoredBytesLeft; - m_ignoredBytesLeft = 0; + long newBytes = -ignoredBytesLeft; + ignoredBytesLeft = 0; - long bytesLeft = m_capacity - m_usedSpace; + long bytesLeft = capacity - usedSpace; if( newBytes > bytesLeft ) throw new IOException( "Out of space" ); - m_usedSpace += newBytes; + usedSpace += newBytes; } } @Override public boolean isOpen() { - return m_inner.isOpen(); + return inner.isOpen(); } @Override public void close() throws IOException { - m_inner.close(); + inner.close(); } } private class SeekableCountingChannel extends WritableCountingChannel implements SeekableByteChannel { - private final SeekableByteChannel m_inner; + private final SeekableByteChannel inner; SeekableCountingChannel( SeekableByteChannel inner, long bytesToIgnore ) { super( inner, bytesToIgnore ); - m_inner = inner; + this.inner = inner; } @Override @@ -94,17 +94,17 @@ public class FileMount implements IWritableMount throw new IllegalArgumentException( "Cannot seek before the beginning of the stream" ); } - long delta = newPosition - m_inner.position(); + long delta = newPosition - inner.position(); if( delta < 0 ) { - m_ignoredBytesLeft -= delta; + ignoredBytesLeft -= delta; } else { count( delta ); } - return m_inner.position( newPosition ); + return inner.position( newPosition ); } @Override @@ -116,32 +116,32 @@ public class FileMount implements IWritableMount @Override public int read( ByteBuffer dst ) throws ClosedChannelException { - if( !m_inner.isOpen() ) throw new ClosedChannelException(); + if( !inner.isOpen() ) throw new ClosedChannelException(); throw new NonReadableChannelException(); } @Override public long position() throws IOException { - return m_inner.position(); + return inner.position(); } @Override public long size() throws IOException { - return m_inner.size(); + return inner.size(); } } - private File m_rootPath; - private long m_capacity; - private long m_usedSpace; + private final File rootPath; + private final long capacity; + private long usedSpace; public FileMount( File rootPath, long capacity ) { - m_rootPath = rootPath; - m_capacity = capacity + MINIMUM_FILE_SIZE; - m_usedSpace = created() ? measureUsedSpace( m_rootPath ) : MINIMUM_FILE_SIZE; + this.rootPath = rootPath; + this.capacity = capacity + MINIMUM_FILE_SIZE; + usedSpace = created() ? measureUsedSpace( this.rootPath ) : MINIMUM_FILE_SIZE; } // IMount implementation @@ -253,7 +253,7 @@ public class FileMount implements IWritableMount if( file.mkdirs() ) { - m_usedSpace += dirsToCreate * MINIMUM_FILE_SIZE; + usedSpace += dirsToCreate * MINIMUM_FILE_SIZE; } else { @@ -290,7 +290,7 @@ public class FileMount implements IWritableMount boolean success = file.delete(); if( success ) { - m_usedSpace -= Math.max( MINIMUM_FILE_SIZE, fileSize ); + usedSpace -= Math.max( MINIMUM_FILE_SIZE, fileSize ); } else { @@ -308,13 +308,13 @@ public class FileMount implements IWritableMount if( file.exists() ) { - m_usedSpace -= Math.max( file.length(), MINIMUM_FILE_SIZE ); + usedSpace -= Math.max( file.length(), MINIMUM_FILE_SIZE ); } else if( getRemainingSpace() < MINIMUM_FILE_SIZE ) { throw new FileOperationException( path, "Out of space" ); } - m_usedSpace += MINIMUM_FILE_SIZE; + usedSpace += MINIMUM_FILE_SIZE; return new SeekableCountingChannel( Files.newByteChannel( file.toPath(), WRITE_OPTIONS ), MINIMUM_FILE_SIZE ); } @@ -342,31 +342,31 @@ public class FileMount implements IWritableMount @Override public long getRemainingSpace() { - return Math.max( m_capacity - m_usedSpace, 0 ); + return Math.max( capacity - usedSpace, 0 ); } @Nonnull @Override public OptionalLong getCapacity() { - return OptionalLong.of( m_capacity - MINIMUM_FILE_SIZE ); + return OptionalLong.of( capacity - MINIMUM_FILE_SIZE ); } private File getRealPath( String path ) { - return new File( m_rootPath, path ); + return new File( rootPath, path ); } private boolean created() { - return m_rootPath.exists(); + return rootPath.exists(); } private void create() throws IOException { - if( !m_rootPath.exists() ) + if( !rootPath.exists() ) { - boolean success = m_rootPath.mkdirs(); + boolean success = rootPath.mkdirs(); if( !success ) { throw new IOException( "Access denied" ); diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 2904f0fb3..cfbc9d92e 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -37,11 +37,11 @@ public class FileSystem */ private static final int MAX_COPY_DEPTH = 128; - private final FileSystemWrapperMount m_wrapper = new FileSystemWrapperMount( this ); + private final FileSystemWrapperMount wrapper = new FileSystemWrapperMount( this ); private final Map mounts = new HashMap<>(); - private final HashMap>, ChannelWrapper> m_openFiles = new HashMap<>(); - private final ReferenceQueue> m_openFileQueue = new ReferenceQueue<>(); + private final HashMap>, ChannelWrapper> openFiles = new HashMap<>(); + private final ReferenceQueue> openFileQueue = new ReferenceQueue<>(); public FileSystem( String rootLabel, IMount rootMount ) throws FileSystemException { @@ -56,11 +56,11 @@ public class FileSystem public void close() { // Close all dangling open files - synchronized( m_openFiles ) + synchronized( openFiles ) { - for( Closeable file : m_openFiles.values() ) IoUtil.closeQuietly( file ); - m_openFiles.clear(); - while( m_openFileQueue.poll() != null ) ; + for( Closeable file : openFiles.values() ) IoUtil.closeQuietly( file ); + openFiles.clear(); + while( openFileQueue.poll() != null ) ; } } @@ -101,11 +101,11 @@ public class FileSystem cleanup(); // Close any files which belong to this mount - don't want people writing to a disk after it's been ejected! - // There's no point storing a Mount -> Wrapper[] map, as m_openFiles is small and unmount isn't called very + // There's no point storing a Mount -> Wrapper[] map, as openFiles is small and unmount isn't called very // often. - synchronized( m_openFiles ) + synchronized( openFiles ) { - for( Iterator>> iterator = m_openFiles.keySet().iterator(); iterator.hasNext(); ) + for( Iterator>> iterator = openFiles.keySet().iterator(); iterator.hasNext(); ) { WeakReference> reference = iterator.next(); FileSystemWrapper wrapper = reference.get(); @@ -383,22 +383,22 @@ public class FileSystem private void cleanup() { - synchronized( m_openFiles ) + synchronized( openFiles ) { Reference ref; - while( (ref = m_openFileQueue.poll()) != null ) + while( (ref = openFileQueue.poll()) != null ) { - IoUtil.closeQuietly( m_openFiles.remove( ref ) ); + IoUtil.closeQuietly( openFiles.remove( ref ) ); } } } private synchronized FileSystemWrapper openFile( @Nonnull MountWrapper mount, @Nonnull Channel channel, @Nonnull T file ) throws FileSystemException { - synchronized( m_openFiles ) + synchronized( openFiles ) { if( ComputerCraft.maximumFilesOpen > 0 && - m_openFiles.size() >= ComputerCraft.maximumFilesOpen ) + openFiles.size() >= ComputerCraft.maximumFilesOpen ) { IoUtil.closeQuietly( file ); IoUtil.closeQuietly( channel ); @@ -406,17 +406,17 @@ public class FileSystem } ChannelWrapper channelWrapper = new ChannelWrapper<>( file, channel ); - FileSystemWrapper fsWrapper = new FileSystemWrapper<>( this, mount, channelWrapper, m_openFileQueue ); - m_openFiles.put( fsWrapper.self, channelWrapper ); + FileSystemWrapper fsWrapper = new FileSystemWrapper<>( this, mount, channelWrapper, openFileQueue ); + openFiles.put( fsWrapper.self, channelWrapper ); return fsWrapper; } } void removeFile( FileSystemWrapper handle ) { - synchronized( m_openFiles ) + synchronized( openFiles ) { - m_openFiles.remove( handle.self ); + openFiles.remove( handle.self ); } } @@ -483,7 +483,7 @@ public class FileSystem public IFileSystem getMountWrapper() { - return m_wrapper; + return wrapper; } private static String sanitizePath( String path ) diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java index ba2d4008d..e0082dcbe 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemWrapperMount.java @@ -17,11 +17,11 @@ import java.util.function.Function; public class FileSystemWrapperMount implements IFileSystem { - private final FileSystem m_filesystem; + private final FileSystem filesystem; public FileSystemWrapperMount( FileSystem filesystem ) { - this.m_filesystem = filesystem; + this.filesystem = filesystem; } @Override @@ -29,7 +29,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - m_filesystem.makeDir( path ); + filesystem.makeDir( path ); } catch( FileSystemException e ) { @@ -42,7 +42,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - m_filesystem.delete( path ); + filesystem.delete( path ); } catch( FileSystemException e ) { @@ -57,7 +57,7 @@ public class FileSystemWrapperMount implements IFileSystem try { // FIXME: Think of a better way of implementing this, so closing this will close on the computer. - return m_filesystem.openForRead( path, Function.identity() ).get(); + return filesystem.openForRead( path, Function.identity() ).get(); } catch( FileSystemException e ) { @@ -71,7 +71,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.openForWrite( path, false, Function.identity() ).get(); + return filesystem.openForWrite( path, false, Function.identity() ).get(); } catch( FileSystemException e ) { @@ -85,7 +85,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.openForWrite( path, true, Function.identity() ).get(); + return filesystem.openForWrite( path, true, Function.identity() ).get(); } catch( FileSystemException e ) { @@ -98,7 +98,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.getFreeSpace( "/" ); + return filesystem.getFreeSpace( "/" ); } catch( FileSystemException e ) { @@ -111,7 +111,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.exists( path ); + return filesystem.exists( path ); } catch( FileSystemException e ) { @@ -124,7 +124,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.isDir( path ); + return filesystem.isDir( path ); } catch( FileSystemException e ) { @@ -137,7 +137,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - Collections.addAll( contents, m_filesystem.list( path ) ); + Collections.addAll( contents, filesystem.list( path ) ); } catch( FileSystemException e ) { @@ -150,7 +150,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - return m_filesystem.getSize( path ); + return filesystem.getSize( path ); } catch( FileSystemException e ) { @@ -161,7 +161,7 @@ public class FileSystemWrapperMount implements IFileSystem @Override public String combine( String path, String child ) { - return m_filesystem.combine( path, child ); + return filesystem.combine( path, child ); } @Override @@ -169,7 +169,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - m_filesystem.copy( from, to ); + filesystem.copy( from, to ); } catch( FileSystemException e ) { @@ -182,7 +182,7 @@ public class FileSystemWrapperMount implements IFileSystem { try { - m_filesystem.move( from, to ); + filesystem.move( from, to ); } catch( FileSystemException e ) { diff --git a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java index bc62e875d..b596896c8 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/SubMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/SubMount.java @@ -15,8 +15,8 @@ import java.util.List; public class SubMount implements IMount { - private IMount parent; - private String subPath; + private final IMount parent; + private final String subPath; public SubMount( IMount parent, String subPath ) { diff --git a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 2721d10bb..d0e58c5a2 100644 --- a/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -50,29 +50,29 @@ public class CobaltLuaMachine implements ILuaMachine private static final LuaMethod FUNCTION_METHOD = ( target, context, args ) -> ((ILuaFunction) target).call( args ); - private final Computer m_computer; + private final Computer computer; private final TimeoutState timeout; private final TimeoutDebugHandler debug; private final ILuaContext context = new CobaltLuaContext(); - private LuaState m_state; - private LuaTable m_globals; + private LuaState state; + private LuaTable globals; - private LuaThread m_mainRoutine = null; - private String m_eventFilter = null; + private LuaThread mainRoutine = null; + private String eventFilter = null; public CobaltLuaMachine( Computer computer, TimeoutState timeout ) { - m_computer = computer; + this.computer = computer; this.timeout = timeout; debug = new TimeoutDebugHandler(); // Create an environment to run in - LuaState state = m_state = LuaState.builder() + LuaState state = this.state = LuaState.builder() .resourceManipulator( new VoidResourceManipulator() ) .debug( debug ) .coroutineExecutor( command -> { - Tracking.addValue( m_computer, TrackingField.COROUTINES_CREATED, 1 ); + Tracking.addValue( this.computer, TrackingField.COROUTINES_CREATED, 1 ); COROUTINES.execute( () -> { try { @@ -80,38 +80,38 @@ public class CobaltLuaMachine implements ILuaMachine } finally { - Tracking.addValue( m_computer, TrackingField.COROUTINES_DISPOSED, 1 ); + Tracking.addValue( this.computer, TrackingField.COROUTINES_DISPOSED, 1 ); } } ); } ) .build(); - m_globals = new LuaTable(); - state.setupThread( m_globals ); + globals = new LuaTable(); + state.setupThread( globals ); // Add basic libraries - m_globals.load( state, new BaseLib() ); - m_globals.load( state, new TableLib() ); - m_globals.load( state, new StringLib() ); - m_globals.load( state, new MathLib() ); - m_globals.load( state, new CoroutineLib() ); - m_globals.load( state, new Bit32Lib() ); - m_globals.load( state, new Utf8Lib() ); - if( ComputerCraft.debugEnable ) m_globals.load( state, new DebugLib() ); + globals.load( state, new BaseLib() ); + globals.load( state, new TableLib() ); + globals.load( state, new StringLib() ); + globals.load( state, new MathLib() ); + globals.load( state, new CoroutineLib() ); + globals.load( state, new Bit32Lib() ); + globals.load( state, new Utf8Lib() ); + if( ComputerCraft.debugEnable ) globals.load( state, new DebugLib() ); // Remove globals we don't want to expose - m_globals.rawset( "collectgarbage", Constants.NIL ); - m_globals.rawset( "dofile", Constants.NIL ); - m_globals.rawset( "loadfile", Constants.NIL ); - m_globals.rawset( "print", Constants.NIL ); + globals.rawset( "collectgarbage", Constants.NIL ); + globals.rawset( "dofile", Constants.NIL ); + globals.rawset( "loadfile", Constants.NIL ); + globals.rawset( "print", Constants.NIL ); // Add version globals - m_globals.rawset( "_VERSION", valueOf( "Lua 5.1" ) ); - m_globals.rawset( "_HOST", valueOf( computer.getAPIEnvironment().getComputerEnvironment().getHostString() ) ); - m_globals.rawset( "_CC_DEFAULT_SETTINGS", valueOf( ComputerCraft.defaultComputerSettings ) ); + globals.rawset( "_VERSION", valueOf( "Lua 5.1" ) ); + globals.rawset( "_HOST", valueOf( computer.getAPIEnvironment().getComputerEnvironment().getHostString() ) ); + globals.rawset( "_CC_DEFAULT_SETTINGS", valueOf( ComputerCraft.defaultComputerSettings ) ); if( ComputerCraft.disableLua51Features ) { - m_globals.rawset( "_CC_DISABLE_LUA51_FEATURES", Constants.TRUE ); + globals.rawset( "_CC_DISABLE_LUA51_FEATURES", Constants.TRUE ); } } @@ -127,19 +127,19 @@ public class CobaltLuaMachine implements ILuaMachine } String[] names = api.getNames(); - for( String name : names ) m_globals.rawset( name, table ); + for( String name : names ) globals.rawset( name, table ); } @Override public MachineResult loadBios( @Nonnull InputStream bios ) { // Begin executing a file (ie, the bios) - if( m_mainRoutine != null ) return MachineResult.OK; + if( mainRoutine != null ) return MachineResult.OK; try { - LuaFunction value = LoadState.load( m_state, bios, "@bios.lua", m_globals ); - m_mainRoutine = new LuaThread( m_state, value, m_globals ); + LuaFunction value = LoadState.load( state, bios, "@bios.lua", globals ); + mainRoutine = new LuaThread( state, value, globals ); return MachineResult.OK; } catch( CompileException e ) @@ -158,9 +158,9 @@ public class CobaltLuaMachine implements ILuaMachine @Override public MachineResult handleEvent( String eventName, Object[] arguments ) { - if( m_mainRoutine == null ) return MachineResult.OK; + if( mainRoutine == null ) return MachineResult.OK; - if( m_eventFilter != null && eventName != null && !eventName.equals( m_eventFilter ) && !eventName.equals( "terminate" ) ) + if( eventFilter != null && eventName != null && !eventName.equals( eventFilter ) && !eventName.equals( "terminate" ) ) { return MachineResult.OK; } @@ -178,17 +178,17 @@ public class CobaltLuaMachine implements ILuaMachine } // Resume the current thread, or the main one when first starting off. - LuaThread thread = m_state.getCurrentThread(); - if( thread == null || thread == m_state.getMainThread() ) thread = m_mainRoutine; + LuaThread thread = state.getCurrentThread(); + if( thread == null || thread == state.getMainThread() ) thread = mainRoutine; Varargs results = LuaThread.run( thread, resumeArgs ); if( timeout.isHardAborted() ) throw HardAbortError.INSTANCE; if( results == null ) return MachineResult.PAUSE; LuaValue filter = results.first(); - m_eventFilter = filter.isString() ? filter.toString() : null; + eventFilter = filter.isString() ? filter.toString() : null; - if( m_mainRoutine.getStatus().equals( "dead" ) ) + if( mainRoutine.getStatus().equals( "dead" ) ) { close(); return MachineResult.GENERIC_ERROR; @@ -214,13 +214,13 @@ public class CobaltLuaMachine implements ILuaMachine @Override public void close() { - LuaState state = m_state; + LuaState state = this.state; if( state == null ) return; state.abandon(); - m_mainRoutine = null; - m_state = null; - m_globals = null; + mainRoutine = null; + this.state = null; + globals = null; } @Nullable @@ -457,7 +457,7 @@ public class CobaltLuaMachine implements ILuaMachine if( (count = (count + 1) & 127) == 0 ) { // If we've been hard aborted or closed then abort. - if( timeout.isHardAborted() || m_state == null ) throw HardAbortError.INSTANCE; + if( timeout.isHardAborted() || state == null ) throw HardAbortError.INSTANCE; timeout.refresh(); if( timeout.isPaused() ) @@ -483,7 +483,7 @@ public class CobaltLuaMachine implements ILuaMachine public void poll() throws LuaError { // If we've been hard aborted or closed then abort. - LuaState state = m_state; + LuaState state = CobaltLuaMachine.this.state; if( timeout.isHardAborted() || state == null ) throw HardAbortError.INSTANCE; timeout.refresh(); @@ -526,26 +526,26 @@ public class CobaltLuaMachine implements ILuaMachine eventArguments[0] = taskID; eventArguments[1] = true; System.arraycopy( results, 0, eventArguments, 2, results.length ); - m_computer.queueEvent( "task_complete", eventArguments ); + computer.queueEvent( "task_complete", eventArguments ); } else { - m_computer.queueEvent( "task_complete", new Object[] { taskID, true } ); + computer.queueEvent( "task_complete", new Object[] { taskID, true } ); } } catch( LuaException e ) { - m_computer.queueEvent( "task_complete", new Object[] { taskID, false, e.getMessage() } ); + computer.queueEvent( "task_complete", new Object[] { taskID, false, e.getMessage() } ); } catch( Throwable t ) { if( ComputerCraft.logComputerErrors ) ComputerCraft.log.error( "Error running task", t ); - m_computer.queueEvent( "task_complete", new Object[] { + computer.queueEvent( "task_complete", new Object[] { taskID, false, "Java Exception Thrown: " + t, } ); } }; - if( m_computer.queueMainThread( iTask ) ) + if( computer.queueMainThread( iTask ) ) { return taskID; } diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index 7b200ef56..61ddb65fd 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -16,20 +16,20 @@ public class Terminal { private static final String base16 = "0123456789abcdef"; - private int m_cursorX = 0; - private int m_cursorY = 0; - private boolean m_cursorBlink = false; - private int m_cursorColour = 0; - private int m_cursorBackgroundColour = 15; + private int cursorX = 0; + private int cursorY = 0; + private boolean cursorBlink = false; + private int cursorColour = 0; + private int cursorBackgroundColour = 15; - private int m_width; - private int m_height; + private int width; + private int height; - private TextBuffer[] m_text; - private TextBuffer[] m_textColour; - private TextBuffer[] m_backgroundColour; + private TextBuffer[] text; + private TextBuffer[] textColour; + private TextBuffer[] backgroundColour; - private final Palette m_palette = new Palette(); + private final Palette palette = new Palette(); private final Runnable onChanged; @@ -40,84 +40,84 @@ public class Terminal public Terminal( int width, int height, Runnable changedCallback ) { - m_width = width; - m_height = height; + this.width = width; + this.height = height; onChanged = changedCallback; - m_text = new TextBuffer[m_height]; - m_textColour = new TextBuffer[m_height]; - m_backgroundColour = new TextBuffer[m_height]; - for( int i = 0; i < m_height; i++ ) + text = new TextBuffer[this.height]; + textColour = new TextBuffer[this.height]; + backgroundColour = new TextBuffer[this.height]; + for( int i = 0; i < this.height; i++ ) { - m_text[i] = new TextBuffer( ' ', m_width ); - m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width ); - m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width ); + text[i] = new TextBuffer( ' ', this.width ); + textColour[i] = new TextBuffer( base16.charAt( cursorColour ), this.width ); + backgroundColour[i] = new TextBuffer( base16.charAt( cursorBackgroundColour ), this.width ); } } public synchronized void reset() { - m_cursorColour = 0; - m_cursorBackgroundColour = 15; - m_cursorX = 0; - m_cursorY = 0; - m_cursorBlink = false; + cursorColour = 0; + cursorBackgroundColour = 15; + cursorX = 0; + cursorY = 0; + cursorBlink = false; clear(); setChanged(); - m_palette.resetColours(); + palette.resetColours(); } public int getWidth() { - return m_width; + return width; } public int getHeight() { - return m_height; + return height; } public synchronized void resize( int width, int height ) { - if( width == m_width && height == m_height ) + if( width == this.width && height == this.height ) { return; } - int oldHeight = m_height; - int oldWidth = m_width; - TextBuffer[] oldText = m_text; - TextBuffer[] oldTextColour = m_textColour; - TextBuffer[] oldBackgroundColour = m_backgroundColour; + int oldHeight = this.height; + int oldWidth = this.width; + TextBuffer[] oldText = text; + TextBuffer[] oldTextColour = textColour; + TextBuffer[] oldBackgroundColour = backgroundColour; - m_width = width; - m_height = height; + this.width = width; + this.height = height; - m_text = new TextBuffer[m_height]; - m_textColour = new TextBuffer[m_height]; - m_backgroundColour = new TextBuffer[m_height]; - for( int i = 0; i < m_height; i++ ) + text = new TextBuffer[this.height]; + textColour = new TextBuffer[this.height]; + backgroundColour = new TextBuffer[this.height]; + for( int i = 0; i < this.height; i++ ) { if( i >= oldHeight ) { - m_text[i] = new TextBuffer( ' ', m_width ); - m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width ); - m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width ); + text[i] = new TextBuffer( ' ', this.width ); + textColour[i] = new TextBuffer( base16.charAt( cursorColour ), this.width ); + backgroundColour[i] = new TextBuffer( base16.charAt( cursorBackgroundColour ), this.width ); } - else if( m_width == oldWidth ) + else if( this.width == oldWidth ) { - m_text[i] = oldText[i]; - m_textColour[i] = oldTextColour[i]; - m_backgroundColour[i] = oldBackgroundColour[i]; + text[i] = oldText[i]; + textColour[i] = oldTextColour[i]; + backgroundColour[i] = oldBackgroundColour[i]; } else { - m_text[i] = new TextBuffer( ' ', m_width ); - m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width ); - m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width ); - m_text[i].write( oldText[i] ); - m_textColour[i].write( oldTextColour[i] ); - m_backgroundColour[i].write( oldBackgroundColour[i] ); + text[i] = new TextBuffer( ' ', this.width ); + textColour[i] = new TextBuffer( base16.charAt( cursorColour ), this.width ); + backgroundColour[i] = new TextBuffer( base16.charAt( cursorBackgroundColour ), this.width ); + text[i].write( oldText[i] ); + textColour[i].write( oldTextColour[i] ); + backgroundColour[i].write( oldBackgroundColour[i] ); } } setChanged(); @@ -125,94 +125,94 @@ public class Terminal public void setCursorPos( int x, int y ) { - if( m_cursorX != x || m_cursorY != y ) + if( cursorX != x || cursorY != y ) { - m_cursorX = x; - m_cursorY = y; + cursorX = x; + cursorY = y; setChanged(); } } public void setCursorBlink( boolean blink ) { - if( m_cursorBlink != blink ) + if( cursorBlink != blink ) { - m_cursorBlink = blink; + cursorBlink = blink; setChanged(); } } public void setTextColour( int colour ) { - if( m_cursorColour != colour ) + if( cursorColour != colour ) { - m_cursorColour = colour; + cursorColour = colour; setChanged(); } } public void setBackgroundColour( int colour ) { - if( m_cursorBackgroundColour != colour ) + if( cursorBackgroundColour != colour ) { - m_cursorBackgroundColour = colour; + cursorBackgroundColour = colour; setChanged(); } } public int getCursorX() { - return m_cursorX; + return cursorX; } public int getCursorY() { - return m_cursorY; + return cursorY; } public boolean getCursorBlink() { - return m_cursorBlink; + return cursorBlink; } public int getTextColour() { - return m_cursorColour; + return cursorColour; } public int getBackgroundColour() { - return m_cursorBackgroundColour; + return cursorBackgroundColour; } @Nonnull public Palette getPalette() { - return m_palette; + return palette; } public synchronized void blit( String text, String textColour, String backgroundColour ) { - int x = m_cursorX; - int y = m_cursorY; - if( y >= 0 && y < m_height ) + int x = cursorX; + int y = cursorY; + if( y >= 0 && y < height ) { - m_text[y].write( text, x ); - m_textColour[y].write( textColour, x ); - m_backgroundColour[y].write( backgroundColour, x ); + this.text[y].write( text, x ); + this.textColour[y].write( textColour, x ); + this.backgroundColour[y].write( backgroundColour, x ); setChanged(); } } public synchronized void write( String text ) { - int x = m_cursorX; - int y = m_cursorY; - if( y >= 0 && y < m_height ) + int x = cursorX; + int y = cursorY; + if( y >= 0 && y < height ) { - m_text[y].write( text, x ); - m_textColour[y].fill( base16.charAt( m_cursorColour ), x, x + text.length() ); - m_backgroundColour[y].fill( base16.charAt( m_cursorBackgroundColour ), x, x + text.length() ); + this.text[y].write( text, x ); + textColour[y].fill( base16.charAt( cursorColour ), x, x + text.length() ); + backgroundColour[y].fill( base16.charAt( cursorBackgroundColour ), x, x + text.length() ); setChanged(); } } @@ -221,86 +221,86 @@ public class Terminal { if( yDiff != 0 ) { - TextBuffer[] newText = new TextBuffer[m_height]; - TextBuffer[] newTextColour = new TextBuffer[m_height]; - TextBuffer[] newBackgroundColour = new TextBuffer[m_height]; - for( int y = 0; y < m_height; y++ ) + TextBuffer[] newText = new TextBuffer[height]; + TextBuffer[] newTextColour = new TextBuffer[height]; + TextBuffer[] newBackgroundColour = new TextBuffer[height]; + for( int y = 0; y < height; y++ ) { int oldY = y + yDiff; - if( oldY >= 0 && oldY < m_height ) + if( oldY >= 0 && oldY < height ) { - newText[y] = m_text[oldY]; - newTextColour[y] = m_textColour[oldY]; - newBackgroundColour[y] = m_backgroundColour[oldY]; + newText[y] = text[oldY]; + newTextColour[y] = textColour[oldY]; + newBackgroundColour[y] = backgroundColour[oldY]; } else { - newText[y] = new TextBuffer( ' ', m_width ); - newTextColour[y] = new TextBuffer( base16.charAt( m_cursorColour ), m_width ); - newBackgroundColour[y] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width ); + newText[y] = new TextBuffer( ' ', width ); + newTextColour[y] = new TextBuffer( base16.charAt( cursorColour ), width ); + newBackgroundColour[y] = new TextBuffer( base16.charAt( cursorBackgroundColour ), width ); } } - m_text = newText; - m_textColour = newTextColour; - m_backgroundColour = newBackgroundColour; + text = newText; + textColour = newTextColour; + backgroundColour = newBackgroundColour; setChanged(); } } public synchronized void clear() { - for( int y = 0; y < m_height; y++ ) + for( int y = 0; y < height; y++ ) { - m_text[y].fill( ' ' ); - m_textColour[y].fill( base16.charAt( m_cursorColour ) ); - m_backgroundColour[y].fill( base16.charAt( m_cursorBackgroundColour ) ); + text[y].fill( ' ' ); + textColour[y].fill( base16.charAt( cursorColour ) ); + backgroundColour[y].fill( base16.charAt( cursorBackgroundColour ) ); } setChanged(); } public synchronized void clearLine() { - int y = m_cursorY; - if( y >= 0 && y < m_height ) + int y = cursorY; + if( y >= 0 && y < height ) { - m_text[y].fill( ' ' ); - m_textColour[y].fill( base16.charAt( m_cursorColour ) ); - m_backgroundColour[y].fill( base16.charAt( m_cursorBackgroundColour ) ); + text[y].fill( ' ' ); + textColour[y].fill( base16.charAt( cursorColour ) ); + backgroundColour[y].fill( base16.charAt( cursorBackgroundColour ) ); setChanged(); } } public synchronized TextBuffer getLine( int y ) { - if( y >= 0 && y < m_height ) + if( y >= 0 && y < height ) { - return m_text[y]; + return text[y]; } return null; } public synchronized void setLine( int y, String text, String textColour, String backgroundColour ) { - m_text[y].write( text ); - m_textColour[y].write( textColour ); - m_backgroundColour[y].write( backgroundColour ); + this.text[y].write( text ); + this.textColour[y].write( textColour ); + this.backgroundColour[y].write( backgroundColour ); setChanged(); } public synchronized TextBuffer getTextColourLine( int y ) { - if( y >= 0 && y < m_height ) + if( y >= 0 && y < height ) { - return m_textColour[y]; + return textColour[y]; } return null; } public synchronized TextBuffer getBackgroundColourLine( int y ) { - if( y >= 0 && y < m_height ) + if( y >= 0 && y < height ) { - return m_backgroundColour[y]; + return backgroundColour[y]; } return null; } @@ -312,18 +312,18 @@ public class Terminal public synchronized void write( PacketBuffer buffer ) { - buffer.writeInt( m_cursorX ); - buffer.writeInt( m_cursorY ); - buffer.writeBoolean( m_cursorBlink ); - buffer.writeByte( m_cursorBackgroundColour << 4 | m_cursorColour ); + buffer.writeInt( cursorX ); + buffer.writeInt( cursorY ); + buffer.writeBoolean( cursorBlink ); + buffer.writeByte( cursorBackgroundColour << 4 | cursorColour ); - for( int y = 0; y < m_height; y++ ) + for( int y = 0; y < height; y++ ) { - TextBuffer text = m_text[y]; - TextBuffer textColour = m_textColour[y]; - TextBuffer backColour = m_backgroundColour[y]; + TextBuffer text = this.text[y]; + TextBuffer textColour = this.textColour[y]; + TextBuffer backColour = backgroundColour[y]; - for( int x = 0; x < m_width; x++ ) + for( int x = 0; x < width; x++ ) { buffer.writeByte( text.charAt( x ) & 0xFF ); buffer.writeByte( getColour( @@ -333,26 +333,26 @@ public class Terminal } } - m_palette.write( buffer ); + palette.write( buffer ); } public synchronized void read( PacketBuffer buffer ) { - m_cursorX = buffer.readInt(); - m_cursorY = buffer.readInt(); - m_cursorBlink = buffer.readBoolean(); + cursorX = buffer.readInt(); + cursorY = buffer.readInt(); + cursorBlink = buffer.readBoolean(); byte cursorColour = buffer.readByte(); - m_cursorBackgroundColour = (cursorColour >> 4) & 0xF; - m_cursorColour = cursorColour & 0xF; + cursorBackgroundColour = (cursorColour >> 4) & 0xF; + this.cursorColour = cursorColour & 0xF; - for( int y = 0; y < m_height; y++ ) + for( int y = 0; y < height; y++ ) { - TextBuffer text = m_text[y]; - TextBuffer textColour = m_textColour[y]; - TextBuffer backColour = m_backgroundColour[y]; + TextBuffer text = this.text[y]; + TextBuffer textColour = this.textColour[y]; + TextBuffer backColour = backgroundColour[y]; - for( int x = 0; x < m_width; x++ ) + for( int x = 0; x < width; x++ ) { text.setChar( x, (char) (buffer.readByte() & 0xFF) ); @@ -362,56 +362,56 @@ public class Terminal } } - m_palette.read( buffer ); + palette.read( buffer ); setChanged(); } public synchronized CompoundNBT writeToNBT( CompoundNBT nbt ) { - nbt.putInt( "term_cursorX", m_cursorX ); - nbt.putInt( "term_cursorY", m_cursorY ); - nbt.putBoolean( "term_cursorBlink", m_cursorBlink ); - nbt.putInt( "term_textColour", m_cursorColour ); - nbt.putInt( "term_bgColour", m_cursorBackgroundColour ); - for( int n = 0; n < m_height; n++ ) + nbt.putInt( "term_cursorX", cursorX ); + nbt.putInt( "term_cursorY", cursorY ); + nbt.putBoolean( "term_cursorBlink", cursorBlink ); + nbt.putInt( "term_textColour", cursorColour ); + nbt.putInt( "term_bgColour", cursorBackgroundColour ); + for( int n = 0; n < height; n++ ) { - nbt.putString( "term_text_" + n, m_text[n].toString() ); - nbt.putString( "term_textColour_" + n, m_textColour[n].toString() ); - nbt.putString( "term_textBgColour_" + n, m_backgroundColour[n].toString() ); + nbt.putString( "term_text_" + n, text[n].toString() ); + nbt.putString( "term_textColour_" + n, textColour[n].toString() ); + nbt.putString( "term_textBgColour_" + n, backgroundColour[n].toString() ); } - m_palette.writeToNBT( nbt ); + palette.writeToNBT( nbt ); return nbt; } public synchronized void readFromNBT( CompoundNBT nbt ) { - m_cursorX = nbt.getInt( "term_cursorX" ); - m_cursorY = nbt.getInt( "term_cursorY" ); - m_cursorBlink = nbt.getBoolean( "term_cursorBlink" ); - m_cursorColour = nbt.getInt( "term_textColour" ); - m_cursorBackgroundColour = nbt.getInt( "term_bgColour" ); + cursorX = nbt.getInt( "term_cursorX" ); + cursorY = nbt.getInt( "term_cursorY" ); + cursorBlink = nbt.getBoolean( "term_cursorBlink" ); + cursorColour = nbt.getInt( "term_textColour" ); + cursorBackgroundColour = nbt.getInt( "term_bgColour" ); - for( int n = 0; n < m_height; n++ ) + for( int n = 0; n < height; n++ ) { - m_text[n].fill( ' ' ); + text[n].fill( ' ' ); if( nbt.contains( "term_text_" + n ) ) { - m_text[n].write( nbt.getString( "term_text_" + n ) ); + text[n].write( nbt.getString( "term_text_" + n ) ); } - m_textColour[n].fill( base16.charAt( m_cursorColour ) ); + textColour[n].fill( base16.charAt( cursorColour ) ); if( nbt.contains( "term_textColour_" + n ) ) { - m_textColour[n].write( nbt.getString( "term_textColour_" + n ) ); + textColour[n].write( nbt.getString( "term_textColour_" + n ) ); } - m_backgroundColour[n].fill( base16.charAt( m_cursorBackgroundColour ) ); + backgroundColour[n].fill( base16.charAt( cursorBackgroundColour ) ); if( nbt.contains( "term_textBgColour_" + n ) ) { - m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) ); + backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) ); } } - m_palette.readFromNBT( nbt ); + palette.readFromNBT( nbt ); setChanged(); } diff --git a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java index 46f1c9656..e855ff5d1 100644 --- a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java +++ b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java @@ -7,14 +7,14 @@ package dan200.computercraft.core.terminal; public class TextBuffer { - private final char[] m_text; + private final char[] text; public TextBuffer( char c, int length ) { - m_text = new char[length]; + text = new char[length]; for( int i = 0; i < length; i++ ) { - m_text[i] = c; + text[i] = c; } } @@ -26,12 +26,12 @@ public class TextBuffer public TextBuffer( String text, int repetitions ) { int textLength = text.length(); - m_text = new char[textLength * repetitions]; + this.text = new char[textLength * repetitions]; for( int i = 0; i < repetitions; i++ ) { for( int j = 0; j < textLength; j++ ) { - m_text[j + i * textLength] = text.charAt( j ); + this.text[j + i * textLength] = text.charAt( j ); } } } @@ -44,37 +44,37 @@ public class TextBuffer public TextBuffer( TextBuffer text, int repetitions ) { int textLength = text.length(); - m_text = new char[textLength * repetitions]; + this.text = new char[textLength * repetitions]; for( int i = 0; i < repetitions; i++ ) { for( int j = 0; j < textLength; j++ ) { - m_text[j + i * textLength] = text.charAt( j ); + this.text[j + i * textLength] = text.charAt( j ); } } } public int length() { - return m_text.length; + return text.length; } public String read() { - return read( 0, m_text.length ); + return read( 0, text.length ); } public String read( int start ) { - return read( start, m_text.length ); + return read( start, text.length ); } public String read( int start, int end ) { start = Math.max( start, 0 ); - end = Math.min( end, m_text.length ); + end = Math.min( end, text.length ); int textLength = Math.max( end - start, 0 ); - return new String( m_text, start, textLength ); + return new String( text, start, textLength ); } public void write( String text ) @@ -92,10 +92,10 @@ public class TextBuffer int pos = start; start = Math.max( start, 0 ); end = Math.min( end, pos + text.length() ); - end = Math.min( end, m_text.length ); + end = Math.min( end, this.text.length ); for( int i = start; i < end; i++ ) { - m_text[i] = text.charAt( i - pos ); + this.text[i] = text.charAt( i - pos ); } } @@ -114,94 +114,94 @@ public class TextBuffer int pos = start; start = Math.max( start, 0 ); end = Math.min( end, pos + text.length() ); - end = Math.min( end, m_text.length ); + end = Math.min( end, this.text.length ); for( int i = start; i < end; i++ ) { - m_text[i] = text.charAt( i - pos ); + this.text[i] = text.charAt( i - pos ); } } public void fill( char c ) { - fill( c, 0, m_text.length ); + fill( c, 0, text.length ); } public void fill( char c, int start ) { - fill( c, start, m_text.length ); + fill( c, start, text.length ); } public void fill( char c, int start, int end ) { start = Math.max( start, 0 ); - end = Math.min( end, m_text.length ); + end = Math.min( end, text.length ); for( int i = start; i < end; i++ ) { - m_text[i] = c; + text[i] = c; } } public void fill( String text ) { - fill( text, 0, m_text.length ); + fill( text, 0, this.text.length ); } public void fill( String text, int start ) { - fill( text, start, m_text.length ); + fill( text, start, this.text.length ); } public void fill( String text, int start, int end ) { int pos = start; start = Math.max( start, 0 ); - end = Math.min( end, m_text.length ); + end = Math.min( end, this.text.length ); int textLength = text.length(); for( int i = start; i < end; i++ ) { - m_text[i] = text.charAt( (i - pos) % textLength ); + this.text[i] = text.charAt( (i - pos) % textLength ); } } public void fill( TextBuffer text ) { - fill( text, 0, m_text.length ); + fill( text, 0, this.text.length ); } public void fill( TextBuffer text, int start ) { - fill( text, start, m_text.length ); + fill( text, start, this.text.length ); } public void fill( TextBuffer text, int start, int end ) { int pos = start; start = Math.max( start, 0 ); - end = Math.min( end, m_text.length ); + end = Math.min( end, this.text.length ); int textLength = text.length(); for( int i = start; i < end; i++ ) { - m_text[i] = text.charAt( (i - pos) % textLength ); + this.text[i] = text.charAt( (i - pos) % textLength ); } } public char charAt( int i ) { - return m_text[i]; + return text[i]; } public void setChar( int i, char c ) { - if( i >= 0 && i < m_text.length ) + if( i >= 0 && i < text.length ) { - m_text[i] = c; + text[i] = c; } } public String toString() { - return new String( m_text ); + return new String( text ); } } diff --git a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java index 20e55f936..ac7a99aae 100644 --- a/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java +++ b/src/main/java/dan200/computercraft/shared/command/builder/CommandBuilder.java @@ -31,7 +31,7 @@ import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder */ public class CommandBuilder implements CommandNodeBuilder> { - private List> args = new ArrayList<>(); + private final List> args = new ArrayList<>(); private Predicate requires; public static CommandBuilder args() diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 389d8b4d7..1aca87cc6 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -10,21 +10,21 @@ import dan200.computercraft.shared.network.client.TerminalState; public class ClientTerminal implements ITerminal { - private boolean m_colour; - private Terminal m_terminal; - private boolean m_terminalChanged; + private boolean colour; + private Terminal terminal; + private boolean terminalChanged; public ClientTerminal( boolean colour ) { - m_colour = colour; - m_terminal = null; - m_terminalChanged = false; + this.colour = colour; + terminal = null; + terminalChanged = false; } public boolean pollTerminalChanged() { - boolean changed = m_terminalChanged; - m_terminalChanged = false; + boolean changed = terminalChanged; + terminalChanged = false; return changed; } @@ -33,22 +33,22 @@ public class ClientTerminal implements ITerminal @Override public Terminal getTerminal() { - return m_terminal; + return terminal; } @Override public boolean isColour() { - return m_colour; + return colour; } public void read( TerminalState state ) { - m_colour = state.colour; + colour = state.colour; if( state.hasTerminal() ) { resizeTerminal( state.width, state.height ); - state.apply( m_terminal ); + state.apply( terminal ); } else { @@ -58,23 +58,23 @@ public class ClientTerminal implements ITerminal private void resizeTerminal( int width, int height ) { - if( m_terminal == null ) + if( terminal == null ) { - m_terminal = new Terminal( width, height, () -> m_terminalChanged = true ); - m_terminalChanged = true; + terminal = new Terminal( width, height, () -> terminalChanged = true ); + terminalChanged = true; } else { - m_terminal.resize( width, height ); + terminal.resize( width, height ); } } private void deleteTerminal() { - if( m_terminal != null ) + if( terminal != null ) { - m_terminal = null; - m_terminalChanged = true; + terminal = null; + terminalChanged = true; } } } diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 13bb7bc8a..760a13152 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -12,74 +12,74 @@ import java.util.concurrent.atomic.AtomicBoolean; public class ServerTerminal implements ITerminal { - private final boolean m_colour; - private Terminal m_terminal; - private final AtomicBoolean m_terminalChanged = new AtomicBoolean( false ); - private boolean m_terminalChangedLastFrame = false; + private final boolean colour; + private Terminal terminal; + private final AtomicBoolean terminalChanged = new AtomicBoolean( false ); + private boolean terminalChangedLastFrame = false; public ServerTerminal( boolean colour ) { - m_colour = colour; - m_terminal = null; + this.colour = colour; + terminal = null; } public ServerTerminal( boolean colour, int terminalWidth, int terminalHeight ) { - m_colour = colour; - m_terminal = new Terminal( terminalWidth, terminalHeight, this::markTerminalChanged ); + this.colour = colour; + terminal = new Terminal( terminalWidth, terminalHeight, this::markTerminalChanged ); } protected void resize( int width, int height ) { - if( m_terminal == null ) + if( terminal == null ) { - m_terminal = new Terminal( width, height, this::markTerminalChanged ); + terminal = new Terminal( width, height, this::markTerminalChanged ); markTerminalChanged(); } else { - m_terminal.resize( width, height ); + terminal.resize( width, height ); } } public void delete() { - if( m_terminal != null ) + if( terminal != null ) { - m_terminal = null; + terminal = null; markTerminalChanged(); } } protected void markTerminalChanged() { - m_terminalChanged.set( true ); + terminalChanged.set( true ); } public void update() { - m_terminalChangedLastFrame = m_terminalChanged.getAndSet( false ); + terminalChangedLastFrame = terminalChanged.getAndSet( false ); } public boolean hasTerminalChanged() { - return m_terminalChangedLastFrame; + return terminalChangedLastFrame; } @Override public Terminal getTerminal() { - return m_terminal; + return terminal; } @Override public boolean isColour() { - return m_colour; + return colour; } public TerminalState write() { - return new TerminalState( m_colour, m_terminal ); + return new TerminalState( colour, terminal ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java index 60ca49169..b877387db 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java @@ -33,7 +33,7 @@ public final class ComputerProxy ServerComputer computer = tile.getServerComputer(); if( computer == null ) { - tile.m_startOn = true; + tile.startOn = true; } else { @@ -47,7 +47,7 @@ public final class ComputerProxy ServerComputer computer = tile.getServerComputer(); if( computer == null ) { - tile.m_startOn = false; + tile.startOn = false; } else { @@ -61,7 +61,7 @@ public final class ComputerProxy ServerComputer computer = tile.getServerComputer(); if( computer == null ) { - tile.m_startOn = true; + tile.startOn = true; } else { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 44b41d796..fa40d3aab 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -52,12 +52,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT private static final String NBT_LABEL = "Label"; private static final String NBT_ON = "On"; - private int m_instanceID = -1; - private int m_computerID = -1; + private int instanceID = -1; + private int computerID = -1; protected String label = null; - private boolean m_on = false; - boolean m_startOn = false; - private boolean m_fresh = false; + private boolean on = false; + boolean startOn = false; + private boolean fresh = false; private final NonNullConsumer>[] invalidate; private final ComputerFamily family; @@ -78,10 +78,10 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT protected void unload() { - if( m_instanceID >= 0 ) + if( instanceID >= 0 ) { - if( !getLevel().isClientSide ) ComputerCraft.serverComputerRegistry.remove( m_instanceID ); - m_instanceID = -1; + if( !getLevel().isClientSide ) ComputerCraft.serverComputerRegistry.remove( instanceID ); + instanceID = -1; } } @@ -162,18 +162,18 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( computer == null ) return; // If the computer isn't on and should be, then turn it on - if( m_startOn || (m_fresh && m_on) ) + if( startOn || (fresh && on) ) { computer.turnOn(); - m_startOn = false; + startOn = false; } computer.keepAlive(); - m_fresh = false; - m_computerID = computer.getID(); + fresh = false; + computerID = computer.getID(); label = computer.getLabel(); - m_on = computer.isOn(); + on = computer.isOn(); if( computer.hasOutputChanged() ) updateOutput(); @@ -192,9 +192,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT public CompoundNBT save( @Nonnull CompoundNBT nbt ) { // Save ID, label and power state - if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); + if( computerID >= 0 ) nbt.putInt( NBT_ID, computerID ); if( label != null ) nbt.putString( NBT_LABEL, label ); - nbt.putBoolean( NBT_ON, m_on ); + nbt.putBoolean( NBT_ON, on ); return super.save( nbt ); } @@ -205,9 +205,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT super.load( nbt ); // Load ID, label and power state - m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; + computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null; - m_on = m_startOn = nbt.getBoolean( NBT_ON ); + on = startOn = nbt.getBoolean( NBT_ON ); } protected boolean isPeripheralBlockedOnSide( ComputerSide localSide ) @@ -322,7 +322,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public final int getComputerID() { - return m_computerID; + return computerID; } @Override @@ -334,11 +334,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Override public final void setComputerID( int id ) { - if( getLevel().isClientSide || m_computerID == id ) return; + if( getLevel().isClientSide || computerID == id ) return; - m_computerID = id; + computerID = id; ServerComputer computer = getServerComputer(); - if( computer != null ) computer.setID( m_computerID ); + if( computer != null ) computer.setID( computerID ); setChanged(); } @@ -364,16 +364,16 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( getLevel().isClientSide ) return null; boolean changed = false; - if( m_instanceID < 0 ) + if( instanceID < 0 ) { - m_instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID(); + instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID(); changed = true; } - if( !ComputerCraft.serverComputerRegistry.contains( m_instanceID ) ) + if( !ComputerCraft.serverComputerRegistry.contains( instanceID ) ) { - ServerComputer computer = createComputer( m_instanceID, m_computerID ); - ComputerCraft.serverComputerRegistry.add( m_instanceID, computer ); - m_fresh = true; + ServerComputer computer = createComputer( instanceID, computerID ); + ComputerCraft.serverComputerRegistry.add( instanceID, computer ); + fresh = true; changed = true; } if( changed ) @@ -381,12 +381,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT updateBlock(); updateInput(); } - return ComputerCraft.serverComputerRegistry.get( m_instanceID ); + return ComputerCraft.serverComputerRegistry.get( instanceID ); } public ServerComputer getServerComputer() { - return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( m_instanceID ); + return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID ); } // Networking stuff @@ -396,7 +396,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { super.writeDescription( nbt ); if( label != null ) nbt.putString( NBT_LABEL, label ); - if( m_computerID >= 0 ) nbt.putInt( NBT_ID, m_computerID ); + if( computerID >= 0 ) nbt.putInt( NBT_ID, computerID ); } @Override @@ -404,22 +404,22 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT { super.readDescription( nbt ); label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null; - m_computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; + computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1; } protected void transferStateFrom( TileComputerBase copy ) { - if( copy.m_computerID != m_computerID || copy.m_instanceID != m_instanceID ) + if( copy.computerID != computerID || copy.instanceID != instanceID ) { unload(); - m_instanceID = copy.m_instanceID; - m_computerID = copy.m_computerID; + instanceID = copy.instanceID; + computerID = copy.computerID; label = copy.label; - m_on = copy.m_on; - m_startOn = copy.m_startOn; + on = copy.on; + startOn = copy.startOn; updateBlock(); } - copy.m_instanceID = -1; + copy.instanceID = -1; } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java index 92fc32a4d..8ea986711 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java @@ -12,22 +12,21 @@ import net.minecraft.nbt.CompoundNBT; public class ClientComputer extends ClientTerminal implements IComputer { - private final int m_instanceID; - - private boolean m_on = false; - private boolean m_blinking = false; - private CompoundNBT m_userData = null; + private final int instanceID; + private boolean on = false; + private boolean blinking = false; + private CompoundNBT userData = null; public ClientComputer( int instanceID ) { super( false ); - m_instanceID = instanceID; + this.instanceID = instanceID; } public CompoundNBT getUserData() { - return m_userData; + return userData; } public void requestState() @@ -41,89 +40,89 @@ public class ClientComputer extends ClientTerminal implements IComputer @Override public int getInstanceID() { - return m_instanceID; + return instanceID; } @Override public boolean isOn() { - return m_on; + return on; } @Override public boolean isCursorDisplayed() { - return m_on && m_blinking; + return on && blinking; } @Override public void turnOn() { // Send turnOn to server - NetworkHandler.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.TURN_ON ) ); + NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.TURN_ON ) ); } @Override public void shutdown() { // Send shutdown to server - NetworkHandler.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) ); + NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) ); } @Override public void reboot() { // Send reboot to server - NetworkHandler.sendToServer( new ComputerActionServerMessage( m_instanceID, ComputerActionServerMessage.Action.REBOOT ) ); + NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.REBOOT ) ); } @Override public void queueEvent( String event, Object[] arguments ) { // Send event to server - NetworkHandler.sendToServer( new QueueEventServerMessage( m_instanceID, event, arguments ) ); + NetworkHandler.sendToServer( new QueueEventServerMessage( instanceID, event, arguments ) ); } @Override public void keyDown( int key, boolean repeat ) { - NetworkHandler.sendToServer( new KeyEventServerMessage( m_instanceID, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key ) ); + NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key ) ); } @Override public void keyUp( int key ) { - NetworkHandler.sendToServer( new KeyEventServerMessage( m_instanceID, KeyEventServerMessage.TYPE_UP, key ) ); + NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, KeyEventServerMessage.TYPE_UP, key ) ); } @Override public void mouseClick( int button, int x, int y ) { - NetworkHandler.sendToServer( new MouseEventServerMessage( m_instanceID, MouseEventServerMessage.TYPE_CLICK, button, x, y ) ); + NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_CLICK, button, x, y ) ); } @Override public void mouseUp( int button, int x, int y ) { - NetworkHandler.sendToServer( new MouseEventServerMessage( m_instanceID, MouseEventServerMessage.TYPE_UP, button, x, y ) ); + NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_UP, button, x, y ) ); } @Override public void mouseDrag( int button, int x, int y ) { - NetworkHandler.sendToServer( new MouseEventServerMessage( m_instanceID, MouseEventServerMessage.TYPE_DRAG, button, x, y ) ); + NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_DRAG, button, x, y ) ); } @Override public void mouseScroll( int direction, int x, int y ) { - NetworkHandler.sendToServer( new MouseEventServerMessage( m_instanceID, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) ); + NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) ); } public void setState( ComputerState state, CompoundNBT userData ) { - m_on = state != ComputerState.OFF; - m_blinking = state == ComputerState.BLINKING; - m_userData = userData; + on = state != ComputerState.OFF; + blinking = state == ComputerState.BLINKING; + this.userData = userData; } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java index fc7d0ed4a..24120048d 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java @@ -12,38 +12,37 @@ import java.util.Random; public class ComputerRegistry { - private Map m_computers; - private int m_nextUnusedInstanceID; - private int m_sessionID; + private final Map computers = new HashMap<>(); + private int nextUnusedInstanceID; + private int sessionID; protected ComputerRegistry() { - m_computers = new HashMap<>(); reset(); } public int getSessionID() { - return m_sessionID; + return sessionID; } public int getUnusedInstanceID() { - return m_nextUnusedInstanceID++; + return nextUnusedInstanceID++; } public Collection getComputers() { - return m_computers.values(); + return computers.values(); } public T get( int instanceID ) { if( instanceID >= 0 ) { - if( m_computers.containsKey( instanceID ) ) + if( computers.containsKey( instanceID ) ) { - return m_computers.get( instanceID ); + return computers.get( instanceID ); } } return null; @@ -51,28 +50,28 @@ public class ComputerRegistry public boolean contains( int instanceID ) { - return m_computers.containsKey( instanceID ); + return computers.containsKey( instanceID ); } public void add( int instanceID, T computer ) { - if( m_computers.containsKey( instanceID ) ) + if( computers.containsKey( instanceID ) ) { remove( instanceID ); } - m_computers.put( instanceID, computer ); - m_nextUnusedInstanceID = Math.max( m_nextUnusedInstanceID, instanceID + 1 ); + computers.put( instanceID, computer ); + nextUnusedInstanceID = Math.max( nextUnusedInstanceID, instanceID + 1 ); } public void remove( int instanceID ) { - m_computers.remove( instanceID ); + computers.remove( instanceID ); } public void reset() { - m_computers.clear(); - m_nextUnusedInstanceID = 0; - m_sessionID = new Random().nextInt(); + computers.clear(); + nextUnusedInstanceID = 0; + sessionID = new Random().nextInt(); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index a54893384..b4cf22061 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -37,116 +37,109 @@ import java.io.InputStream; public class ServerComputer extends ServerTerminal implements IComputer, IComputerEnvironment { - private final int m_instanceID; + private final int instanceID; - private World m_world; - private BlockPos m_position; + private World world; + private BlockPos position; - private final ComputerFamily m_family; - private final Computer m_computer; - private CompoundNBT m_userData; - private boolean m_changed; + private final ComputerFamily family; + private final Computer computer; + private CompoundNBT userData; + private boolean changed; - private boolean m_changedLastFrame; - private int m_ticksSincePing; + private boolean changedLastFrame; + private int ticksSincePing; public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) { super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight ); - m_instanceID = instanceID; + this.instanceID = instanceID; - m_world = world; - m_position = null; - - m_family = family; - m_computer = new Computer( this, getTerminal(), computerID ); - m_computer.setLabel( label ); - m_userData = null; - m_changed = false; - - m_changedLastFrame = false; - m_ticksSincePing = 0; + this.world = world; + this.family = family; + computer = new Computer( this, getTerminal(), computerID ); + computer.setLabel( label ); } public ComputerFamily getFamily() { - return m_family; + return family; } public World getWorld() { - return m_world; + return world; } public void setWorld( World world ) { - m_world = world; + this.world = world; } public BlockPos getPosition() { - return m_position; + return position; } public void setPosition( BlockPos pos ) { - m_position = new BlockPos( pos ); + position = new BlockPos( pos ); } public IAPIEnvironment getAPIEnvironment() { - return m_computer.getAPIEnvironment(); + return computer.getAPIEnvironment(); } public Computer getComputer() { - return m_computer; + return computer; } @Override public void update() { super.update(); - m_computer.tick(); + computer.tick(); - m_changedLastFrame = m_computer.pollAndResetChanged() || m_changed; - m_changed = false; + changedLastFrame = computer.pollAndResetChanged() || changed; + changed = false; - m_ticksSincePing++; + ticksSincePing++; } public void keepAlive() { - m_ticksSincePing = 0; + ticksSincePing = 0; } public boolean hasTimedOut() { - return m_ticksSincePing > 100; + return ticksSincePing > 100; } public boolean hasOutputChanged() { - return m_changedLastFrame; + return changedLastFrame; } public void unload() { - m_computer.unload(); + computer.unload(); } public CompoundNBT getUserData() { - if( m_userData == null ) + if( userData == null ) { - m_userData = new CompoundNBT(); + userData = new CompoundNBT(); } - return m_userData; + return userData; } public void updateUserData() { - m_changed = true; + changed = true; } private NetworkMessage createComputerPacket() @@ -204,7 +197,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput public void setID( int id ) { - m_computer.setID( id ); + computer.setID( id ); } // IComputer @@ -212,97 +205,97 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput @Override public int getInstanceID() { - return m_instanceID; + return instanceID; } public int getID() { - return m_computer.getID(); + return computer.getID(); } public String getLabel() { - return m_computer.getLabel(); + return computer.getLabel(); } @Override public boolean isOn() { - return m_computer.isOn(); + return computer.isOn(); } @Override public boolean isCursorDisplayed() { - return m_computer.isOn() && m_computer.isBlinking(); + return computer.isOn() && computer.isBlinking(); } @Override public void turnOn() { // Turn on - m_computer.turnOn(); + computer.turnOn(); } @Override public void shutdown() { // Shutdown - m_computer.shutdown(); + computer.shutdown(); } @Override public void reboot() { // Reboot - m_computer.reboot(); + computer.reboot(); } @Override public void queueEvent( String event, Object[] arguments ) { // Queue event - m_computer.queueEvent( event, arguments ); + computer.queueEvent( event, arguments ); } public int getRedstoneOutput( ComputerSide side ) { - return m_computer.getEnvironment().getExternalRedstoneOutput( side ); + return computer.getEnvironment().getExternalRedstoneOutput( side ); } public void setRedstoneInput( ComputerSide side, int level ) { - m_computer.getEnvironment().setRedstoneInput( side, level ); + computer.getEnvironment().setRedstoneInput( side, level ); } public int getBundledRedstoneOutput( ComputerSide side ) { - return m_computer.getEnvironment().getExternalBundledRedstoneOutput( side ); + return computer.getEnvironment().getExternalBundledRedstoneOutput( side ); } public void setBundledRedstoneInput( ComputerSide side, int combination ) { - m_computer.getEnvironment().setBundledRedstoneInput( side, combination ); + computer.getEnvironment().setBundledRedstoneInput( side, combination ); } public void addAPI( ILuaAPI api ) { - m_computer.addApi( api ); + computer.addApi( api ); } public void setPeripheral( ComputerSide side, IPeripheral peripheral ) { - m_computer.getEnvironment().setPeripheral( side, peripheral ); + computer.getEnvironment().setPeripheral( side, peripheral ); } public IPeripheral getPeripheral( ComputerSide side ) { - return m_computer.getEnvironment().getPeripheral( side ); + return computer.getEnvironment().getPeripheral( side ); } public void setLabel( String label ) { - m_computer.setLabel( label ); + computer.setLabel( label ); } // IComputerEnvironment implementation @@ -310,19 +303,19 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput @Override public double getTimeOfDay() { - return (m_world.getDayTime() + 6000) % 24000 / 1000.0; + return (world.getDayTime() + 6000) % 24000 / 1000.0; } @Override public int getDay() { - return (int) ((m_world.getDayTime() + 6000) / 24000) + 1; + return (int) ((world.getDayTime() + 6000) / 24000) + 1; } @Override public IWritableMount createSaveDirMount( String subPath, long capacity ) { - return ComputerCraftAPI.createSaveDirMount( m_world, subPath, capacity ); + return ComputerCraftAPI.createSaveDirMount( world, subPath, capacity ); } @Override @@ -360,7 +353,7 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput @Override public int assignNewID() { - return ComputerCraftAPI.createUniqueNumberedSaveDir( m_world, "computer" ); + return ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" ); } @Nullable diff --git a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java index 0e48dad40..b3baff2c6 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ChatTableClientMessage.java @@ -10,8 +10,6 @@ import dan200.computercraft.shared.command.text.TableBuilder; import dan200.computercraft.shared.network.NetworkMessage; import net.minecraft.network.PacketBuffer; import net.minecraft.util.text.ITextComponent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -80,7 +78,6 @@ public class ChatTableClientMessage implements NetworkMessage } @Override - @OnlyIn( Dist.CLIENT ) public void handle( NetworkEvent.Context context ) { ClientTableFormatter.INSTANCE.display( table ); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index f2136367c..3f97e224a 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -59,18 +59,18 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory ITextComponent customName; - private final Map m_computers = new HashMap<>(); + private final Map computers = new HashMap<>(); @Nonnull - private ItemStack m_diskStack = ItemStack.EMPTY; + private ItemStack diskStack = ItemStack.EMPTY; private LazyOptional itemHandlerCap; private LazyOptional peripheralCap; - private IMount m_diskMount = null; + private IMount diskMount = null; - private boolean m_recordQueued = false; - private boolean m_recordPlaying = false; - private boolean m_restartRecord = false; - private boolean m_ejectQueued; + private boolean recordQueued = false; + private boolean recordPlaying = false; + private boolean restartRecord = false; + private boolean ejectQueued; public TileDiskDrive( TileEntityType type ) { @@ -81,7 +81,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory public void destroy() { ejectContents( true ); - if( m_recordPlaying ) stopRecord(); + if( recordPlaying ) stopRecord(); } @Override @@ -129,8 +129,8 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory if( nbt.contains( NBT_ITEM ) ) { CompoundNBT item = nbt.getCompound( NBT_ITEM ); - m_diskStack = ItemStack.of( item ); - m_diskMount = null; + diskStack = ItemStack.of( item ); + diskMount = null; } } @@ -140,10 +140,10 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); - if( !m_diskStack.isEmpty() ) + if( !diskStack.isEmpty() ) { CompoundNBT item = new CompoundNBT(); - m_diskStack.save( item ); + diskStack.save( item ); nbt.put( NBT_ITEM, item ); } return super.save( nbt ); @@ -153,36 +153,36 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory public void tick() { // Ejection - if( m_ejectQueued ) + if( ejectQueued ) { ejectContents( false ); - m_ejectQueued = false; + ejectQueued = false; } // Music synchronized( this ) { - if( !level.isClientSide && m_recordPlaying != m_recordQueued || m_restartRecord ) + if( !level.isClientSide && recordPlaying != recordQueued || restartRecord ) { - m_restartRecord = false; - if( m_recordQueued ) + restartRecord = false; + if( recordQueued ) { IMedia contents = getDiskMedia(); - SoundEvent record = contents != null ? contents.getAudio( m_diskStack ) : null; + SoundEvent record = contents != null ? contents.getAudio( diskStack ) : null; if( record != null ) { - m_recordPlaying = true; + recordPlaying = true; playRecord(); } else { - m_recordQueued = false; + recordQueued = false; } } else { stopRecord(); - m_recordPlaying = false; + recordPlaying = false; } } } @@ -199,23 +199,23 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Override public boolean isEmpty() { - return m_diskStack.isEmpty(); + return diskStack.isEmpty(); } @Nonnull @Override public ItemStack getItem( int slot ) { - return m_diskStack; + return diskStack; } @Nonnull @Override public ItemStack removeItemNoUpdate( int slot ) { - ItemStack result = m_diskStack; - m_diskStack = ItemStack.EMPTY; - m_diskMount = null; + ItemStack result = diskStack; + diskStack = ItemStack.EMPTY; + diskMount = null; return result; } @@ -224,17 +224,17 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory @Override public ItemStack removeItem( int slot, int count ) { - if( m_diskStack.isEmpty() ) return ItemStack.EMPTY; + if( diskStack.isEmpty() ) return ItemStack.EMPTY; - if( m_diskStack.getCount() <= count ) + if( diskStack.getCount() <= count ) { - ItemStack disk = m_diskStack; + ItemStack disk = diskStack; setItem( slot, ItemStack.EMPTY ); return disk; } - ItemStack part = m_diskStack.split( count ); - setItem( slot, m_diskStack.isEmpty() ? ItemStack.EMPTY : m_diskStack ); + ItemStack part = diskStack.split( count ); + setItem( slot, diskStack.isEmpty() ? ItemStack.EMPTY : diskStack ); return part; } @@ -243,45 +243,45 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { if( getLevel().isClientSide ) { - m_diskStack = stack; - m_diskMount = null; + diskStack = stack; + diskMount = null; setChanged(); return; } synchronized( this ) { - if( InventoryUtil.areItemsStackable( stack, m_diskStack ) ) + if( InventoryUtil.areItemsStackable( stack, diskStack ) ) { - m_diskStack = stack; + diskStack = stack; return; } // Unmount old disk - if( !m_diskStack.isEmpty() ) + if( !diskStack.isEmpty() ) { // TODO: Is this iteration thread safe? - Set computers = m_computers.keySet(); + Set computers = this.computers.keySet(); for( IComputerAccess computer : computers ) unmountDisk( computer ); } // Stop music - if( m_recordPlaying ) + if( recordPlaying ) { stopRecord(); - m_recordPlaying = false; - m_recordQueued = false; + recordPlaying = false; + recordQueued = false; } // Swap disk over - m_diskStack = stack; - m_diskMount = null; + diskStack = stack; + diskMount = null; setChanged(); // Mount new disk - if( !m_diskStack.isEmpty() ) + if( !diskStack.isEmpty() ) { - Set computers = m_computers.keySet(); + Set computers = this.computers.keySet(); for( IComputerAccess computer : computers ) mountDisk( computer ); } } @@ -326,7 +326,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { synchronized( this ) { - MountInfo info = m_computers.get( computer ); + MountInfo info = computers.get( computer ); return info != null ? info.mountPath : null; } } @@ -335,7 +335,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { synchronized( this ) { - m_computers.put( computer, new MountInfo() ); + computers.put( computer, new MountInfo() ); mountDisk( computer ); } } @@ -345,7 +345,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory synchronized( this ) { unmountDisk( computer ); - m_computers.remove( computer ); + computers.remove( computer ); } } @@ -354,10 +354,10 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory synchronized( this ) { IMedia media = getDiskMedia(); - if( media != null && media.getAudioTitle( m_diskStack ) != null ) + if( media != null && media.getAudioTitle( diskStack ) != null ) { - m_recordQueued = true; - m_restartRecord = m_recordPlaying; + recordQueued = true; + restartRecord = recordPlaying; } } } @@ -366,8 +366,8 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { synchronized( this ) { - m_recordQueued = false; - m_restartRecord = false; + recordQueued = false; + restartRecord = false; } } @@ -375,7 +375,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { synchronized( this ) { - m_ejectQueued = true; + ejectQueued = true; } } @@ -383,25 +383,25 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private synchronized void mountDisk( IComputerAccess computer ) { - if( !m_diskStack.isEmpty() ) + if( !diskStack.isEmpty() ) { - MountInfo info = m_computers.get( computer ); + MountInfo info = computers.get( computer ); IMedia contents = getDiskMedia(); if( contents != null ) { - if( m_diskMount == null ) + if( diskMount == null ) { - m_diskMount = contents.createDataMount( m_diskStack, getLevel() ); + diskMount = contents.createDataMount( diskStack, getLevel() ); } - if( m_diskMount != null ) + if( diskMount != null ) { - if( m_diskMount instanceof IWritableMount ) + if( diskMount instanceof IWritableMount ) { // Try mounting at the lowest numbered "disk" name we can int n = 1; while( info.mountPath == null ) { - info.mountPath = computer.mountWritable( n == 1 ? "disk" : "disk" + n, (IWritableMount) m_diskMount ); + info.mountPath = computer.mountWritable( n == 1 ? "disk" : "disk" + n, (IWritableMount) diskMount ); n++; } } @@ -411,7 +411,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory int n = 1; while( info.mountPath == null ) { - info.mountPath = computer.mount( n == 1 ? "disk" : "disk" + n, m_diskMount ); + info.mountPath = computer.mount( n == 1 ? "disk" : "disk" + n, diskMount ); n++; } } @@ -427,9 +427,9 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private synchronized void unmountDisk( IComputerAccess computer ) { - if( !m_diskStack.isEmpty() ) + if( !diskStack.isEmpty() ) { - MountInfo info = m_computers.get( computer ); + MountInfo info = computers.get( computer ); assert info != null; if( info.mountPath != null ) { @@ -444,7 +444,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory { if( remove ) return; - if( !m_diskStack.isEmpty() ) + if( !diskStack.isEmpty() ) { IMedia contents = getDiskMedia(); updateBlockState( contents != null ? DiskDriveState.FULL : DiskDriveState.INVALID ); @@ -465,10 +465,10 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private synchronized void ejectContents( boolean destroyed ) { - if( getLevel().isClientSide || m_diskStack.isEmpty() ) return; + if( getLevel().isClientSide || diskStack.isEmpty() ) return; // Remove the disks from the inventory - ItemStack disks = m_diskStack; + ItemStack disks = diskStack; setDiskStack( ItemStack.EMPTY ); // Spawn the item in the world @@ -497,10 +497,10 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory private void playRecord() { IMedia contents = getDiskMedia(); - SoundEvent record = contents != null ? contents.getAudio( m_diskStack ) : null; + SoundEvent record = contents != null ? contents.getAudio( diskStack ) : null; if( record != null ) { - RecordUtil.playRecord( record, contents.getAudioTitle( m_diskStack ), getLevel(), getBlockPos() ); + RecordUtil.playRecord( record, contents.getAudioTitle( diskStack ), getLevel(), getBlockPos() ); } else { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java index 8ef54a91f..5989f3000 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -27,32 +27,32 @@ import java.util.Set; */ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver { - private IPacketNetwork m_network; - private final Set m_computers = new HashSet<>( 1 ); - private final ModemState m_state; + private IPacketNetwork network; + private final Set computers = new HashSet<>( 1 ); + private final ModemState state; protected ModemPeripheral( ModemState state ) { - m_state = state; + this.state = state; } public ModemState getModemState() { - return m_state; + return state; } private synchronized void setNetwork( IPacketNetwork network ) { - if( m_network == network ) return; + if( this.network == network ) return; // Leave old network - if( m_network != null ) m_network.removeReceiver( this ); + if( this.network != null ) this.network.removeReceiver( this ); // Set new network - m_network = network; + this.network = network; // Join new network - if( m_network != null ) m_network.addReceiver( this ); + if( this.network != null ) this.network.addReceiver( this ); } public void destroy() @@ -63,11 +63,11 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public void receiveSameDimension( @Nonnull Packet packet, double distance ) { - if( packet.getSender() == this || !m_state.isOpen( packet.getChannel() ) ) return; + if( packet.getSender() == this || !state.isOpen( packet.getChannel() ) ) return; - synchronized( m_computers ) + synchronized( computers ) { - for( IComputerAccess computer : m_computers ) + for( IComputerAccess computer : computers ) { computer.queueEvent( "modem_message", computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance ); @@ -78,11 +78,11 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public void receiveDifferentDimension( @Nonnull Packet packet ) { - if( packet.getSender() == this || !m_state.isOpen( packet.getChannel() ) ) return; + if( packet.getSender() == this || !state.isOpen( packet.getChannel() ) ) return; - synchronized( m_computers ) + synchronized( computers ) { - for( IComputerAccess computer : m_computers ) + for( IComputerAccess computer : computers ) { computer.queueEvent( "modem_message", computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload() ); @@ -116,7 +116,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @LuaFunction public final void open( int channel ) throws LuaException { - m_state.open( parseChannel( channel ) ); + state.open( parseChannel( channel ) ); } /** @@ -129,7 +129,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @LuaFunction public final boolean isOpen( int channel ) throws LuaException { - return m_state.isOpen( parseChannel( channel ) ); + return state.isOpen( parseChannel( channel ) ); } /** @@ -141,7 +141,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @LuaFunction public final void close( int channel ) throws LuaException { - m_state.close( parseChannel( channel ) ); + state.close( parseChannel( channel ) ); } /** @@ -150,7 +150,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @LuaFunction public final void closeAll() { - m_state.closeAll(); + state.closeAll(); } /** @@ -172,7 +172,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa World world = getWorld(); Vec3d position = getPosition(); - IPacketNetwork network = m_network; + IPacketNetwork network = this.network; if( world == null || position == null || network == null ) return; @@ -198,16 +198,16 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @LuaFunction public final boolean isWireless() { - IPacketNetwork network = m_network; + IPacketNetwork network = this.network; return network != null && network.isWireless(); } @Override public synchronized void attach( @Nonnull IComputerAccess computer ) { - synchronized( m_computers ) + synchronized( computers ) { - m_computers.add( computer ); + computers.add( computer ); } setNetwork( getNetwork() ); @@ -217,10 +217,10 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa public synchronized void detach( @Nonnull IComputerAccess computer ) { boolean empty; - synchronized( m_computers ) + synchronized( computers ) { - m_computers.remove( computer ); - empty = m_computers.isEmpty(); + computers.remove( computer ); + empty = computers.isEmpty(); } if( empty ) setNetwork( null ); @@ -230,15 +230,15 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public String getSenderID() { - synchronized( m_computers ) + synchronized( computers ) { - if( m_computers.size() != 1 ) + if( computers.size() != 1 ) { return "unknown"; } else { - IComputerAccess computer = m_computers.iterator().next(); + IComputerAccess computer = computers.iterator().next(); return computer.getID() + "_" + computer.getAttachmentName(); } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 7c587f7bb..449444664 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -67,38 +67,38 @@ public class TileCable extends TileGeneric @Override protected void attachPeripheral( String name, IPeripheral peripheral ) { - m_modem.attachPeripheral( name, peripheral ); + modem.attachPeripheral( name, peripheral ); } @Override protected void detachPeripheral( String name ) { - m_modem.detachPeripheral( name ); + modem.detachPeripheral( name ); } } - private boolean m_peripheralAccessAllowed; - private final WiredModemLocalPeripheral m_peripheral = new WiredModemLocalPeripheral( this::refreshPeripheral ); + private boolean peripheralAccessAllowed; + private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral( this::refreshPeripheral ); - private boolean m_destroyed = false; + private boolean destroyed = false; private Direction modemDirection = Direction.NORTH; private boolean hasModemDirection = false; - private boolean m_connectionsFormed = false; + private boolean connectionsFormed = false; - private final WiredModemElement m_cable = new CableElement(); + private final WiredModemElement cable = new CableElement(); private LazyOptional elementCap; - private final IWiredNode m_node = m_cable.getNode(); - private final WiredModemPeripheral m_modem = new WiredModemPeripheral( + private final IWiredNode node = cable.getNode(); + private final WiredModemPeripheral modem = new WiredModemPeripheral( new ModemState( () -> TickScheduler.schedule( this ) ), - m_cable + cable ) { @Nonnull @Override protected WiredModemLocalPeripheral getLocalPeripheral() { - return m_peripheral; + return peripheral; } @Nonnull @@ -129,18 +129,18 @@ public class TileCable extends TileGeneric { if( level == null || !level.isClientSide ) { - m_node.remove(); - m_connectionsFormed = false; + node.remove(); + connectionsFormed = false; } } @Override public void destroy() { - if( !m_destroyed ) + if( !destroyed ) { - m_destroyed = true; - m_modem.destroy(); + destroyed = true; + modem.destroy(); onRemove(); } } @@ -236,7 +236,7 @@ public class TileCable extends TileGeneric public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { super.onNeighbourTileEntityChange( neighbour ); - if( !level.isClientSide && m_peripheralAccessAllowed ) + if( !level.isClientSide && peripheralAccessAllowed ) { Direction facing = getDirection(); if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral(); @@ -245,7 +245,7 @@ public class TileCable extends TileGeneric private void refreshPeripheral() { - if( level != null && !isRemoved() && m_peripheral.attach( level, getBlockPos(), getDirection() ) ) + if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), getDirection() ) ) { updateConnectedPeripherals(); } @@ -260,9 +260,9 @@ public class TileCable extends TileGeneric if( getLevel().isClientSide ) return ActionResultType.SUCCESS; - String oldName = m_peripheral.getConnectedName(); + String oldName = peripheral.getConnectedName(); togglePeripheralAccess(); - String newName = m_peripheral.getConnectedName(); + String newName = peripheral.getConnectedName(); if( !Objects.equal( newName, oldName ) ) { if( oldName != null ) @@ -284,16 +284,16 @@ public class TileCable extends TileGeneric public void load( @Nonnull CompoundNBT nbt ) { super.load( nbt ); - m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); - m_peripheral.read( nbt, "" ); + peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); + peripheral.read( nbt, "" ); } @Nonnull @Override public CompoundNBT save( CompoundNBT nbt ) { - nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed ); - m_peripheral.write( nbt, "" ); + nbt.putBoolean( NBT_PERIPHERAL_ENABLED, peripheralAccessAllowed ); + peripheral.write( nbt, "" ); return super.save( nbt ); } @@ -302,7 +302,7 @@ public class TileCable extends TileGeneric BlockState state = getBlockState(); CableModemVariant oldVariant = state.getValue( BlockCable.MODEM ); CableModemVariant newVariant = CableModemVariant - .from( oldVariant.getFacing(), m_modem.getModemState().isOpen(), m_peripheralAccessAllowed ); + .from( oldVariant.getFacing(), modem.getModemState().isOpen(), peripheralAccessAllowed ); if( oldVariant != newVariant ) { @@ -324,16 +324,16 @@ public class TileCable extends TileGeneric elementCap = CapabilityUtil.invalidate( elementCap ); } - if( m_modem.getModemState().pollChanged() ) updateBlockState(); + if( modem.getModemState().pollChanged() ) updateBlockState(); - if( !m_connectionsFormed ) + if( !connectionsFormed ) { - m_connectionsFormed = true; + connectionsFormed = true; connectionsChanged(); - if( m_peripheralAccessAllowed ) + if( peripheralAccessAllowed ) { - m_peripheral.attach( level, worldPosition, modemDirection ); + peripheral.attach( level, worldPosition, modemDirection ); updateConnectedPeripherals(); } } @@ -359,12 +359,12 @@ public class TileCable extends TileGeneric if( BlockCable.canConnectIn( state, facing ) ) { // If we can connect to it then do so - m_node.connectTo( node ); + this.node.connectTo( node ); } - else if( m_node.getNetwork() == node.getNetwork() ) + else if( this.node.getNetwork() == node.getNetwork() ) { // Otherwise if we're on the same network then attempt to void it. - m_node.disconnectFrom( node ); + this.node.disconnectFrom( node ); } } } @@ -378,11 +378,11 @@ public class TileCable extends TileGeneric // If we can no longer attach peripherals, then detach any // which may have existed - if( !canAttachPeripheral() && m_peripheralAccessAllowed ) + if( !canAttachPeripheral() && peripheralAccessAllowed ) { - m_peripheralAccessAllowed = false; - m_peripheral.detach(); - m_node.updatePeripherals( Collections.emptyMap() ); + peripheralAccessAllowed = false; + peripheral.detach(); + node.updatePeripherals( Collections.emptyMap() ); setChanged(); updateBlockState(); } @@ -390,20 +390,20 @@ public class TileCable extends TileGeneric private void togglePeripheralAccess() { - if( !m_peripheralAccessAllowed ) + if( !peripheralAccessAllowed ) { - m_peripheral.attach( level, getBlockPos(), getDirection() ); - if( !m_peripheral.hasPeripheral() ) return; + peripheral.attach( level, getBlockPos(), getDirection() ); + if( !peripheral.hasPeripheral() ) return; - m_peripheralAccessAllowed = true; - m_node.updatePeripherals( m_peripheral.toMap() ); + peripheralAccessAllowed = true; + node.updatePeripherals( peripheral.toMap() ); } else { - m_peripheral.detach(); + peripheral.detach(); - m_peripheralAccessAllowed = false; - m_node.updatePeripherals( Collections.emptyMap() ); + peripheralAccessAllowed = false; + node.updatePeripherals( Collections.emptyMap() ); } updateBlockState(); @@ -411,15 +411,15 @@ public class TileCable extends TileGeneric private void updateConnectedPeripherals() { - Map peripherals = m_peripheral.toMap(); + Map peripherals = peripheral.toMap(); if( peripherals.isEmpty() ) { // If there are no peripherals then disable access and update the display state. - m_peripheralAccessAllowed = false; + peripheralAccessAllowed = false; updateBlockState(); } - m_node.updatePeripherals( peripherals ); + node.updatePeripherals( peripherals ); } @Override @@ -434,8 +434,8 @@ public class TileCable extends TileGeneric { if( capability == CAPABILITY_WIRED_ELEMENT ) { - if( m_destroyed || !BlockCable.canConnectIn( getBlockState(), side ) ) return LazyOptional.empty(); - if( elementCap == null ) elementCap = LazyOptional.of( () -> m_cable ); + if( destroyed || !BlockCable.canConnectIn( getBlockState(), side ) ) return LazyOptional.empty(); + if( elementCap == null ) elementCap = LazyOptional.of( () -> cable ); return elementCap.cast(); } @@ -443,7 +443,7 @@ public class TileCable extends TileGeneric { refreshDirection(); if( side != null && getMaybeDirection() != side ) return LazyOptional.empty(); - if( modemCap == null ) modemCap = LazyOptional.of( () -> m_modem ); + if( modemCap == null ) modemCap = LazyOptional.of( () -> modem ); return modemCap.cast(); } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index 98e63377f..74696d132 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -49,11 +49,11 @@ public class TileWiredModemFull extends TileGeneric private static final class FullElement extends WiredModemElement { - private final TileWiredModemFull m_entity; + private final TileWiredModemFull entity; private FullElement( TileWiredModemFull entity ) { - m_entity = entity; + this.entity = entity; } @Override @@ -61,7 +61,7 @@ public class TileWiredModemFull extends TileGeneric { for( int i = 0; i < 6; i++ ) { - WiredModemPeripheral modem = m_entity.modems[i]; + WiredModemPeripheral modem = entity.modems[i]; if( modem != null ) modem.attachPeripheral( name, peripheral ); } } @@ -71,7 +71,7 @@ public class TileWiredModemFull extends TileGeneric { for( int i = 0; i < 6; i++ ) { - WiredModemPeripheral modem = m_entity.modems[i]; + WiredModemPeripheral modem = entity.modems[i]; if( modem != null ) modem.detachPeripheral( name ); } } @@ -80,14 +80,14 @@ public class TileWiredModemFull extends TileGeneric @Override public World getWorld() { - return m_entity.getLevel(); + return entity.getLevel(); } @Nonnull @Override public Vec3d getPosition() { - BlockPos pos = m_entity.getBlockPos(); + BlockPos pos = entity.getBlockPos(); return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); } } @@ -95,26 +95,26 @@ public class TileWiredModemFull extends TileGeneric private final WiredModemPeripheral[] modems = new WiredModemPeripheral[6]; private final SidedCaps modemCaps = SidedCaps.ofNonNull( this::getPeripheral ); - private boolean m_peripheralAccessAllowed = false; - private final WiredModemLocalPeripheral[] m_peripherals = new WiredModemLocalPeripheral[6]; + private boolean peripheralAccessAllowed = false; + private final WiredModemLocalPeripheral[] peripherals = new WiredModemLocalPeripheral[6]; - private boolean m_destroyed = false; - private boolean m_connectionsFormed = false; + private boolean destroyed = false; + private boolean connectionsFormed = false; - private final ModemState m_modemState = new ModemState( () -> TickScheduler.schedule( this ) ); - private final WiredModemElement m_element = new FullElement( this ); + private final ModemState modemState = new ModemState( () -> TickScheduler.schedule( this ) ); + private final WiredModemElement element = new FullElement( this ); private LazyOptional elementCap; - private final IWiredNode m_node = m_element.getNode(); + private final IWiredNode node = element.getNode(); private final NonNullConsumer> connectedNodeChanged = x -> connectionsChanged(); public TileWiredModemFull( TileEntityType type ) { super( type ); - for( int i = 0; i < m_peripherals.length; i++ ) + for( int i = 0; i < peripherals.length; i++ ) { Direction facing = Direction.from3DDataValue( i ); - m_peripherals[i] = new WiredModemLocalPeripheral( () -> refreshPeripheral( facing ) ); + peripherals[i] = new WiredModemLocalPeripheral( () -> refreshPeripheral( facing ) ); } } @@ -122,17 +122,17 @@ public class TileWiredModemFull extends TileGeneric { if( level == null || !level.isClientSide ) { - m_node.remove(); - m_connectionsFormed = false; + node.remove(); + connectionsFormed = false; } } @Override public void destroy() { - if( !m_destroyed ) + if( !destroyed ) { - m_destroyed = true; + destroyed = true; doRemove(); } super.destroy(); @@ -169,7 +169,7 @@ public class TileWiredModemFull extends TileGeneric @Override public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { - if( !level.isClientSide && m_peripheralAccessAllowed ) + if( !level.isClientSide && peripheralAccessAllowed ) { for( Direction facing : DirectionUtil.FACINGS ) { @@ -180,7 +180,7 @@ public class TileWiredModemFull extends TileGeneric private void refreshPeripheral( @Nonnull Direction facing ) { - WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()]; + WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()]; if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), facing ) ) { updateConnectedPeripherals(); @@ -228,23 +228,23 @@ public class TileWiredModemFull extends TileGeneric public void load( @Nonnull CompoundNBT nbt ) { super.load( nbt ); - m_peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); - for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].read( nbt, Integer.toString( i ) ); + peripheralAccessAllowed = nbt.getBoolean( NBT_PERIPHERAL_ENABLED ); + for( int i = 0; i < peripherals.length; i++ ) peripherals[i].read( nbt, Integer.toString( i ) ); } @Nonnull @Override public CompoundNBT save( CompoundNBT nbt ) { - nbt.putBoolean( NBT_PERIPHERAL_ENABLED, m_peripheralAccessAllowed ); - for( int i = 0; i < m_peripherals.length; i++ ) m_peripherals[i].write( nbt, Integer.toString( i ) ); + nbt.putBoolean( NBT_PERIPHERAL_ENABLED, peripheralAccessAllowed ); + for( int i = 0; i < peripherals.length; i++ ) peripherals[i].write( nbt, Integer.toString( i ) ); return super.save( nbt ); } private void updateBlockState() { BlockState state = getBlockState(); - boolean modemOn = m_modemState.isOpen(), peripheralOn = m_peripheralAccessAllowed; + boolean modemOn = modemState.isOpen(), peripheralOn = peripheralAccessAllowed; if( state.getValue( MODEM_ON ) == modemOn && state.getValue( PERIPHERAL_ON ) == peripheralOn ) return; getLevel().setBlockAndUpdate( getBlockPos(), state.setValue( MODEM_ON, modemOn ).setValue( PERIPHERAL_ON, peripheralOn ) ); @@ -262,18 +262,18 @@ public class TileWiredModemFull extends TileGeneric { if( getLevel().isClientSide ) return; - if( m_modemState.pollChanged() ) updateBlockState(); + if( modemState.pollChanged() ) updateBlockState(); - if( !m_connectionsFormed ) + if( !connectionsFormed ) { - m_connectionsFormed = true; + connectionsFormed = true; connectionsChanged(); - if( m_peripheralAccessAllowed ) + if( peripheralAccessAllowed ) { for( Direction facing : DirectionUtil.FACINGS ) { - m_peripherals[facing.ordinal()].attach( level, getBlockPos(), facing ); + peripherals[facing.ordinal()].attach( level, getBlockPos(), facing ); } updateConnectedPeripherals(); } @@ -295,33 +295,33 @@ public class TileWiredModemFull extends TileGeneric if( !element.isPresent() ) continue; element.addListener( connectedNodeChanged ); - m_node.connectTo( element.orElseThrow( NullPointerException::new ).getNode() ); + node.connectTo( element.orElseThrow( NullPointerException::new ).getNode() ); } } private void togglePeripheralAccess() { - if( !m_peripheralAccessAllowed ) + if( !peripheralAccessAllowed ) { boolean hasAny = false; for( Direction facing : DirectionUtil.FACINGS ) { - WiredModemLocalPeripheral peripheral = m_peripherals[facing.ordinal()]; + WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()]; peripheral.attach( level, getBlockPos(), facing ); hasAny |= peripheral.hasPeripheral(); } if( !hasAny ) return; - m_peripheralAccessAllowed = true; - m_node.updatePeripherals( getConnectedPeripherals() ); + peripheralAccessAllowed = true; + node.updatePeripherals( getConnectedPeripherals() ); } else { - m_peripheralAccessAllowed = false; + peripheralAccessAllowed = false; - for( WiredModemLocalPeripheral peripheral : m_peripherals ) peripheral.detach(); - m_node.updatePeripherals( Collections.emptyMap() ); + for( WiredModemLocalPeripheral peripheral : peripherals ) peripheral.detach(); + node.updatePeripherals( Collections.emptyMap() ); } updateBlockState(); @@ -329,10 +329,10 @@ public class TileWiredModemFull extends TileGeneric private Set getConnectedPeripheralNames() { - if( !m_peripheralAccessAllowed ) return Collections.emptySet(); + if( !peripheralAccessAllowed ) return Collections.emptySet(); Set peripherals = new HashSet<>( 6 ); - for( WiredModemLocalPeripheral peripheral : m_peripherals ) + for( WiredModemLocalPeripheral peripheral : this.peripherals ) { String name = peripheral.getConnectedName(); if( name != null ) peripherals.add( name ); @@ -342,10 +342,10 @@ public class TileWiredModemFull extends TileGeneric private Map getConnectedPeripherals() { - if( !m_peripheralAccessAllowed ) return Collections.emptyMap(); + if( !peripheralAccessAllowed ) return Collections.emptyMap(); Map peripherals = new HashMap<>( 6 ); - for( WiredModemLocalPeripheral peripheral : m_peripherals ) peripheral.extendMap( peripherals ); + for( WiredModemLocalPeripheral peripheral : this.peripherals ) peripheral.extendMap( peripherals ); return peripherals; } @@ -355,11 +355,11 @@ public class TileWiredModemFull extends TileGeneric if( peripherals.isEmpty() ) { // If there are no peripherals then disable access and update the display state. - m_peripheralAccessAllowed = false; + peripheralAccessAllowed = false; updateBlockState(); } - m_node.updatePeripherals( peripherals ); + node.updatePeripherals( peripherals ); } @Nonnull @@ -368,7 +368,7 @@ public class TileWiredModemFull extends TileGeneric { if( capability == CAPABILITY_WIRED_ELEMENT ) { - if( elementCap == null ) elementCap = LazyOptional.of( () -> m_element ); + if( elementCap == null ) elementCap = LazyOptional.of( () -> element ); return elementCap.cast(); } @@ -379,7 +379,7 @@ public class TileWiredModemFull extends TileGeneric public IWiredElement getElement() { - return m_element; + return element; } private WiredModemPeripheral getPeripheral( @Nonnull Direction side ) @@ -387,8 +387,8 @@ public class TileWiredModemFull extends TileGeneric WiredModemPeripheral peripheral = modems[side.ordinal()]; if( peripheral != null ) return peripheral; - WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()]; - return modems[side.ordinal()] = new WiredModemPeripheral( m_modemState, m_element ) + WiredModemLocalPeripheral localPeripheral = peripherals[side.ordinal()]; + return modems[side.ordinal()] = new WiredModemPeripheral( modemState, element ) { @Nonnull @Override diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java index dc2296e8c..32db96cbe 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessModemPeripheral.java @@ -14,24 +14,24 @@ import net.minecraft.world.World; public abstract class WirelessModemPeripheral extends ModemPeripheral { - private final boolean m_advanced; + private final boolean advanced; public WirelessModemPeripheral( ModemState state, boolean advanced ) { super( state ); - m_advanced = advanced; + this.advanced = advanced; } @Override public boolean isInterdimensional() { - return m_advanced; + return advanced; } @Override public double getRange() { - if( m_advanced ) + if( advanced ) { return Integer.MAX_VALUE; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java index 72adfb42e..a7f4e95da 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/WirelessNetwork.java @@ -18,50 +18,47 @@ import java.util.concurrent.ConcurrentHashMap; public class WirelessNetwork implements IPacketNetwork { - private static WirelessNetwork s_universalNetwork = null; + private static WirelessNetwork universalNetwork = null; public static WirelessNetwork getUniversal() { - if( s_universalNetwork == null ) - { - s_universalNetwork = new WirelessNetwork(); - } - return s_universalNetwork; + if( universalNetwork == null ) universalNetwork = new WirelessNetwork(); + return universalNetwork; } public static void resetNetworks() { - s_universalNetwork = null; + universalNetwork = null; } - private final Set m_receivers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); + private final Set receivers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); @Override public void addReceiver( @Nonnull IPacketReceiver receiver ) { Objects.requireNonNull( receiver, "device cannot be null" ); - m_receivers.add( receiver ); + receivers.add( receiver ); } @Override public void removeReceiver( @Nonnull IPacketReceiver receiver ) { Objects.requireNonNull( receiver, "device cannot be null" ); - m_receivers.remove( receiver ); + receivers.remove( receiver ); } @Override public void transmitSameDimension( @Nonnull Packet packet, double range ) { Objects.requireNonNull( packet, "packet cannot be null" ); - for( IPacketReceiver device : m_receivers ) tryTransmit( device, packet, range, false ); + for( IPacketReceiver device : receivers ) tryTransmit( device, packet, range, false ); } @Override public void transmitInterdimensional( @Nonnull Packet packet ) { Objects.requireNonNull( packet, "packet cannot be null" ); - for( IPacketReceiver device : m_receivers ) tryTransmit( device, packet, 0, true ); + for( IPacketReceiver device : receivers ) tryTransmit( device, packet, 0, true ); } private static void tryTransmit( IPacketReceiver receiver, Packet packet, double range, boolean interdimensional ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 7456c7ba0..dabb2feee 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -49,23 +49,23 @@ public class TileMonitor extends TileGeneric private final boolean advanced; - private ServerMonitor m_serverMonitor; - private ClientMonitor m_clientMonitor; + private ServerMonitor serverMonitor; + private ClientMonitor clientMonitor; private MonitorPeripheral peripheral; private LazyOptional peripheralCap; - private final Set m_computers = new HashSet<>(); + private final Set computers = new HashSet<>(); - private boolean m_destroyed = false; + private boolean destroyed = false; private boolean visiting = false; // MonitorWatcher state. boolean enqueued; TerminalState cached; - private int m_width = 1; - private int m_height = 1; - private int m_xIndex = 0; - private int m_yIndex = 0; + private int width = 1; + private int height = 1; + private int xIndex = 0; + private int yIndex = 0; public TileMonitor( TileEntityType type, boolean advanced ) { @@ -84,8 +84,8 @@ public class TileMonitor extends TileGeneric public void destroy() { // TODO: Call this before using the block - if( m_destroyed ) return; - m_destroyed = true; + if( destroyed ) return; + destroyed = true; if( !getLevel().isClientSide ) contractNeighbours(); } @@ -93,14 +93,14 @@ public class TileMonitor extends TileGeneric public void setRemoved() { super.setRemoved(); - if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy(); + if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) clientMonitor.destroy(); } @Override public void onChunkUnloaded() { super.onChunkUnloaded(); - if( m_clientMonitor != null && m_xIndex == 0 && m_yIndex == 0 ) m_clientMonitor.destroy(); + if( clientMonitor != null && xIndex == 0 && yIndex == 0 ) clientMonitor.destroy(); } @Nonnull @@ -127,10 +127,10 @@ public class TileMonitor extends TileGeneric @Override public CompoundNBT save( CompoundNBT tag ) { - tag.putInt( NBT_X, m_xIndex ); - tag.putInt( NBT_Y, m_yIndex ); - tag.putInt( NBT_WIDTH, m_width ); - tag.putInt( NBT_HEIGHT, m_height ); + tag.putInt( NBT_X, xIndex ); + tag.putInt( NBT_Y, yIndex ); + tag.putInt( NBT_WIDTH, width ); + tag.putInt( NBT_HEIGHT, height ); return super.save( tag ); } @@ -138,29 +138,29 @@ public class TileMonitor extends TileGeneric public void load( @Nonnull CompoundNBT tag ) { super.load( tag ); - m_xIndex = tag.getInt( NBT_X ); - m_yIndex = tag.getInt( NBT_Y ); - m_width = tag.getInt( NBT_WIDTH ); - m_height = tag.getInt( NBT_HEIGHT ); + xIndex = tag.getInt( NBT_X ); + yIndex = tag.getInt( NBT_Y ); + width = tag.getInt( NBT_WIDTH ); + height = tag.getInt( NBT_HEIGHT ); } @Override public void blockTick() { - if( m_xIndex != 0 || m_yIndex != 0 || m_serverMonitor == null ) return; + if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return; - m_serverMonitor.clearChanged(); + serverMonitor.clearChanged(); - if( m_serverMonitor.pollResized() ) + if( serverMonitor.pollResized() ) { - for( int x = 0; x < m_width; x++ ) + for( int x = 0; x < width; x++ ) { - for( int y = 0; y < m_height; y++ ) + for( int y = 0; y < height; y++ ) { TileMonitor monitor = getNeighbour( x, y ); if( monitor == null ) continue; - for( IComputerAccess computer : monitor.m_computers ) + for( IComputerAccess computer : monitor.computers ) { computer.queueEvent( "monitor_resize", computer.getAttachmentName() ); } @@ -168,7 +168,7 @@ public class TileMonitor extends TileGeneric } } - if( m_serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this ); + if( serverMonitor.pollTerminalChanged() ) MonitorWatcher.enqueue( this ); } @Override @@ -194,62 +194,62 @@ public class TileMonitor extends TileGeneric public ServerMonitor getCachedServerMonitor() { - return m_serverMonitor; + return serverMonitor; } private ServerMonitor getServerMonitor() { - if( m_serverMonitor != null ) return m_serverMonitor; + if( serverMonitor != null ) return serverMonitor; TileMonitor origin = getOrigin(); if( origin == null ) return null; - return m_serverMonitor = origin.m_serverMonitor; + return serverMonitor = origin.serverMonitor; } private ServerMonitor createServerMonitor() { - if( m_serverMonitor != null ) return m_serverMonitor; + if( serverMonitor != null ) return serverMonitor; - if( m_xIndex == 0 && m_yIndex == 0 ) + if( xIndex == 0 && yIndex == 0 ) { // If we're the origin, set up the new monitor - m_serverMonitor = new ServerMonitor( advanced, this ); - m_serverMonitor.rebuild(); + serverMonitor = new ServerMonitor( advanced, this ); + serverMonitor.rebuild(); // And propagate it to child monitors - for( int x = 0; x < m_width; x++ ) + for( int x = 0; x < width; x++ ) { - for( int y = 0; y < m_height; y++ ) + for( int y = 0; y < height; y++ ) { TileMonitor monitor = getNeighbour( x, y ); - if( monitor != null ) monitor.m_serverMonitor = m_serverMonitor; + if( monitor != null ) monitor.serverMonitor = serverMonitor; } } - return m_serverMonitor; + return serverMonitor; } else { // Otherwise fetch the origin and attempt to get its monitor // Note this may load chunks, but we don't really have a choice here. BlockPos pos = getBlockPos(); - TileEntity te = level.getBlockEntity( pos.relative( getRight(), -m_xIndex ).relative( getDown(), -m_yIndex ) ); + TileEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ).relative( getDown(), -yIndex ) ); if( !(te instanceof TileMonitor) ) return null; - return m_serverMonitor = ((TileMonitor) te).createServerMonitor(); + return serverMonitor = ((TileMonitor) te).createServerMonitor(); } } public ClientMonitor getClientMonitor() { - if( m_clientMonitor != null ) return m_clientMonitor; + if( clientMonitor != null ) return clientMonitor; BlockPos pos = getBlockPos(); - TileEntity te = level.getBlockEntity( pos.relative( getRight(), -m_xIndex ).relative( getDown(), -m_yIndex ) ); + TileEntity te = level.getBlockEntity( pos.relative( getRight(), -xIndex ).relative( getDown(), -yIndex ) ); if( !(te instanceof TileMonitor) ) return null; - return m_clientMonitor = ((TileMonitor) te).m_clientMonitor; + return clientMonitor = ((TileMonitor) te).clientMonitor; } // Networking stuff @@ -258,10 +258,10 @@ public class TileMonitor extends TileGeneric protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); - nbt.putInt( NBT_X, m_xIndex ); - nbt.putInt( NBT_Y, m_yIndex ); - nbt.putInt( NBT_WIDTH, m_width ); - nbt.putInt( NBT_HEIGHT, m_height ); + nbt.putInt( NBT_X, xIndex ); + nbt.putInt( NBT_Y, yIndex ); + nbt.putInt( NBT_WIDTH, width ); + nbt.putInt( NBT_HEIGHT, height ); } @Override @@ -269,32 +269,32 @@ public class TileMonitor extends TileGeneric { super.readDescription( nbt ); - int oldXIndex = m_xIndex; - int oldYIndex = m_yIndex; - int oldWidth = m_width; - int oldHeight = m_height; + int oldXIndex = xIndex; + int oldYIndex = yIndex; + int oldWidth = width; + int oldHeight = height; - m_xIndex = nbt.getInt( NBT_X ); - m_yIndex = nbt.getInt( NBT_Y ); - m_width = nbt.getInt( NBT_WIDTH ); - m_height = nbt.getInt( NBT_HEIGHT ); + xIndex = nbt.getInt( NBT_X ); + yIndex = nbt.getInt( NBT_Y ); + width = nbt.getInt( NBT_WIDTH ); + height = nbt.getInt( NBT_HEIGHT ); - if( oldXIndex != m_xIndex || oldYIndex != m_yIndex ) + if( oldXIndex != xIndex || oldYIndex != yIndex ) { // If our index has changed then it's possible the origin monitor has changed. Thus // we'll clear our cache. If we're the origin then we'll need to remove the glList as well. - if( oldXIndex == 0 && oldYIndex == 0 && m_clientMonitor != null ) m_clientMonitor.destroy(); - m_clientMonitor = null; + if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null ) clientMonitor.destroy(); + clientMonitor = null; } - if( m_xIndex == 0 && m_yIndex == 0 ) + if( xIndex == 0 && yIndex == 0 ) { // If we're the origin terminal then create it. - if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( advanced, this ); + if( clientMonitor == null ) clientMonitor = new ClientMonitor( advanced, this ); } - if( oldXIndex != m_xIndex || oldYIndex != m_yIndex || - oldWidth != m_width || oldHeight != m_height ) + if( oldXIndex != xIndex || oldYIndex != yIndex || + oldWidth != width || oldHeight != height ) { // One of our properties has changed, so ensure we redraw the block updateBlock(); @@ -303,14 +303,14 @@ public class TileMonitor extends TileGeneric public final void read( TerminalState state ) { - if( m_xIndex != 0 || m_yIndex != 0 ) + if( xIndex != 0 || yIndex != 0 ) { ComputerCraft.log.warn( "Receiving monitor state for non-origin terminal at {}", getBlockPos() ); return; } - if( m_clientMonitor == null ) m_clientMonitor = new ClientMonitor( advanced, this ); - m_clientMonitor.read( state ); + if( clientMonitor == null ) clientMonitor = new ClientMonitor( advanced, this ); + clientMonitor.read( state ); } // Sizing and placement stuff @@ -319,8 +319,8 @@ public class TileMonitor extends TileGeneric { getLevel().setBlock( getBlockPos(), getBlockState() .setValue( BlockMonitor.STATE, MonitorEdgeState.fromConnections( - m_yIndex < m_height - 1, m_yIndex > 0, - m_xIndex > 0, m_xIndex < m_width - 1 ) ), 2 ); + yIndex < height - 1, yIndex > 0, + xIndex > 0, xIndex < width - 1 ) ), 2 ); } // region Sizing and placement stuff @@ -358,22 +358,22 @@ public class TileMonitor extends TileGeneric public int getWidth() { - return m_width; + return width; } public int getHeight() { - return m_height; + return height; } public int getXIndex() { - return m_xIndex; + return xIndex; } public int getYIndex() { - return m_yIndex; + return yIndex; } private TileMonitor getSimilarMonitorAt( BlockPos pos ) @@ -388,7 +388,7 @@ public class TileMonitor extends TileGeneric if( !(tile instanceof TileMonitor) ) return null; TileMonitor monitor = (TileMonitor) tile; - return !monitor.visiting && !monitor.m_destroyed && advanced == monitor.advanced + return !monitor.visiting && !monitor.destroyed && advanced == monitor.advanced && getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation() ? monitor : null; } @@ -398,8 +398,8 @@ public class TileMonitor extends TileGeneric BlockPos pos = getBlockPos(); Direction right = getRight(); Direction down = getDown(); - int xOffset = -m_xIndex + x; - int yOffset = -m_yIndex + y; + int xOffset = -xIndex + x; + int yOffset = -yIndex + y; return getSimilarMonitorAt( pos.relative( right, xOffset ).relative( down, yOffset ) ); } @@ -411,12 +411,12 @@ public class TileMonitor extends TileGeneric private void resize( int width, int height ) { // If we're not already the origin then we'll need to generate a new terminal. - if( m_xIndex != 0 || m_yIndex != 0 ) m_serverMonitor = null; + if( xIndex != 0 || yIndex != 0 ) serverMonitor = null; - m_xIndex = 0; - m_yIndex = 0; - m_width = width; - m_height = height; + xIndex = 0; + yIndex = 0; + this.width = width; + this.height = height; // Determine if we actually need a monitor. In order to do this, simply check if // any component monitor been wrapped as a peripheral. Whilst this flag may be @@ -439,16 +439,16 @@ public class TileMonitor extends TileGeneric // Either delete the current monitor or sync a new one. if( needsTerminal ) { - if( m_serverMonitor == null ) m_serverMonitor = new ServerMonitor( advanced, this ); + if( serverMonitor == null ) serverMonitor = new ServerMonitor( advanced, this ); } else { - m_serverMonitor = null; + serverMonitor = null; } // Update the terminal's width and height and rebuild it. This ensures the monitor // is consistent when syncing it to other monitors. - if( m_serverMonitor != null ) m_serverMonitor.rebuild(); + if( serverMonitor != null ) serverMonitor.rebuild(); // Update the other monitors, setting coordinates, dimensions and the server terminal for( int x = 0; x < width; x++ ) @@ -458,11 +458,11 @@ public class TileMonitor extends TileGeneric TileMonitor monitor = getNeighbour( x, y ); if( monitor == null ) continue; - monitor.m_xIndex = x; - monitor.m_yIndex = y; - monitor.m_width = width; - monitor.m_height = height; - monitor.m_serverMonitor = m_serverMonitor; + monitor.xIndex = x; + monitor.yIndex = y; + monitor.width = width; + monitor.height = height; + monitor.serverMonitor = serverMonitor; monitor.updateBlockState(); monitor.updateBlock(); } @@ -472,41 +472,41 @@ public class TileMonitor extends TileGeneric private boolean mergeLeft() { TileMonitor left = getNeighbour( -1, 0 ); - if( left == null || left.m_yIndex != 0 || left.m_height != m_height ) return false; + if( left == null || left.yIndex != 0 || left.height != height ) return false; - int width = left.m_width + m_width; + int width = left.width + this.width; if( width > ComputerCraft.monitorWidth ) return false; TileMonitor origin = left.getOrigin(); - if( origin != null ) origin.resize( width, m_height ); + if( origin != null ) origin.resize( width, height ); left.expand(); return true; } private boolean mergeRight() { - TileMonitor right = getNeighbour( m_width, 0 ); - if( right == null || right.m_yIndex != 0 || right.m_height != m_height ) return false; + TileMonitor right = getNeighbour( width, 0 ); + if( right == null || right.yIndex != 0 || right.height != height ) return false; - int width = m_width + right.m_width; + int width = this.width + right.width; if( width > ComputerCraft.monitorWidth ) return false; TileMonitor origin = getOrigin(); - if( origin != null ) origin.resize( width, m_height ); + if( origin != null ) origin.resize( width, height ); expand(); return true; } private boolean mergeUp() { - TileMonitor above = getNeighbour( 0, m_height ); - if( above == null || above.m_xIndex != 0 || above.m_width != m_width ) return false; + TileMonitor above = getNeighbour( 0, height ); + if( above == null || above.xIndex != 0 || above.width != width ) return false; - int height = above.m_height + m_height; + int height = above.height + this.height; if( height > ComputerCraft.monitorHeight ) return false; TileMonitor origin = getOrigin(); - if( origin != null ) origin.resize( m_width, height ); + if( origin != null ) origin.resize( width, height ); expand(); return true; } @@ -514,13 +514,13 @@ public class TileMonitor extends TileGeneric private boolean mergeDown() { TileMonitor below = getNeighbour( 0, -1 ); - if( below == null || below.m_xIndex != 0 || below.m_width != m_width ) return false; + if( below == null || below.xIndex != 0 || below.width != width ) return false; - int height = m_height + below.m_height; + int height = this.height + below.height; if( height > ComputerCraft.monitorHeight ) return false; TileMonitor origin = below.getOrigin(); - if( origin != null ) origin.resize( m_width, height ); + if( origin != null ) origin.resize( width, height ); below.expand(); return true; } @@ -534,24 +534,24 @@ public class TileMonitor extends TileGeneric void contractNeighbours() { visiting = true; - if( m_xIndex > 0 ) + if( xIndex > 0 ) { - TileMonitor left = getNeighbour( m_xIndex - 1, m_yIndex ); + TileMonitor left = getNeighbour( xIndex - 1, yIndex ); if( left != null ) left.contract(); } - if( m_xIndex + 1 < m_width ) + if( xIndex + 1 < width ) { - TileMonitor right = getNeighbour( m_xIndex + 1, m_yIndex ); + TileMonitor right = getNeighbour( xIndex + 1, yIndex ); if( right != null ) right.contract(); } - if( m_yIndex > 0 ) + if( yIndex > 0 ) { - TileMonitor below = getNeighbour( m_xIndex, m_yIndex - 1 ); + TileMonitor below = getNeighbour( xIndex, yIndex - 1 ); if( below != null ) below.contract(); } - if( m_yIndex + 1 < m_height ) + if( yIndex + 1 < height ) { - TileMonitor above = getNeighbour( m_xIndex, m_yIndex + 1 ); + TileMonitor above = getNeighbour( xIndex, yIndex + 1 ); if( above != null ) above.contract(); } visiting = false; @@ -559,8 +559,8 @@ public class TileMonitor extends TileGeneric void contract() { - int height = m_height; - int width = m_width; + int height = this.height; + int width = this.width; TileMonitor origin = getOrigin(); if( origin == null ) @@ -624,9 +624,9 @@ public class TileMonitor extends TileGeneric { XYPair pair = XYPair .of( xPos, yPos, zPos, getDirection(), getOrientation() ) - .add( m_xIndex, m_height - m_yIndex - 1 ); + .add( xIndex, height - yIndex - 1 ); - if( pair.x > m_width - RENDER_BORDER || pair.y > m_height - RENDER_BORDER || pair.x < RENDER_BORDER || pair.y < RENDER_BORDER ) + if( pair.x > width - RENDER_BORDER || pair.y > height - RENDER_BORDER || pair.x < RENDER_BORDER || pair.y < RENDER_BORDER ) { return; } @@ -637,20 +637,20 @@ public class TileMonitor extends TileGeneric Terminal originTerminal = serverTerminal.getTerminal(); if( originTerminal == null ) return; - double xCharWidth = (m_width - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getWidth(); - double yCharHeight = (m_height - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getHeight(); + double xCharWidth = (width - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getWidth(); + double yCharHeight = (height - (RENDER_BORDER + RENDER_MARGIN) * 2.0) / originTerminal.getHeight(); int xCharPos = (int) Math.min( originTerminal.getWidth(), Math.max( (pair.x - RENDER_BORDER - RENDER_MARGIN) / xCharWidth + 1.0, 1.0 ) ); int yCharPos = (int) Math.min( originTerminal.getHeight(), Math.max( (pair.y - RENDER_BORDER - RENDER_MARGIN) / yCharHeight + 1.0, 1.0 ) ); - for( int y = 0; y < m_height; y++ ) + for( int y = 0; y < height; y++ ) { - for( int x = 0; x < m_width; x++ ) + for( int x = 0; x < width; x++ ) { TileMonitor monitor = getNeighbour( x, y ); if( monitor == null ) continue; - for( IComputerAccess computer : monitor.m_computers ) + for( IComputerAccess computer : monitor.computers ) { computer.queueEvent( "monitor_touch", computer.getAttachmentName(), xCharPos, yCharPos ); } @@ -661,12 +661,12 @@ public class TileMonitor extends TileGeneric void addComputer( IComputerAccess computer ) { - m_computers.add( computer ); + computers.add( computer ); } void removeComputer( IComputerAccess computer ) { - m_computers.remove( computer ); + computers.remove( computer ); } @Nonnull @@ -674,7 +674,7 @@ public class TileMonitor extends TileGeneric public AxisAlignedBB getRenderBoundingBox() { TileMonitor start = getNeighbour( 0, 0 ); - TileMonitor end = getNeighbour( m_width - 1, m_height - 1 ); + TileMonitor end = getNeighbour( width - 1, height - 1 ); if( start != null && end != null ) { BlockPos startPos = start.getBlockPos(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index 6320a13ff..02d0693c2 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -55,14 +55,14 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent ITextComponent customName; - private final NonNullList m_inventory = NonNullList.withSize( SLOTS, ItemStack.EMPTY ); + private final NonNullList inventory = NonNullList.withSize( SLOTS, ItemStack.EMPTY ); private final SidedCaps itemHandlerCaps = SidedCaps.ofNullable( facing -> facing == null ? new InvWrapper( this ) : new SidedInvWrapper( this, facing ) ); private LazyOptional peripheralCap; - private final Terminal m_page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE ); - private String m_pageTitle = ""; - private boolean m_printing = false; + private final Terminal page = new Terminal( ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE ); + private String pageTitle = ""; + private boolean printing = false; public TilePrinter( TileEntityType type ) { @@ -101,15 +101,15 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent customName = nbt.contains( NBT_NAME ) ? ITextComponent.Serializer.fromJson( nbt.getString( NBT_NAME ) ) : null; // Read page - synchronized( m_page ) + synchronized( page ) { - m_printing = nbt.getBoolean( NBT_PRINTING ); - m_pageTitle = nbt.getString( NBT_PAGE_TITLE ); - m_page.readFromNBT( nbt ); + printing = nbt.getBoolean( NBT_PRINTING ); + pageTitle = nbt.getString( NBT_PAGE_TITLE ); + page.readFromNBT( nbt ); } // Read inventory - ItemStackHelper.loadAllItems( nbt, m_inventory ); + ItemStackHelper.loadAllItems( nbt, inventory ); } @Nonnull @@ -119,35 +119,35 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent if( customName != null ) nbt.putString( NBT_NAME, ITextComponent.Serializer.toJson( customName ) ); // Write page - synchronized( m_page ) + synchronized( page ) { - nbt.putBoolean( NBT_PRINTING, m_printing ); - nbt.putString( NBT_PAGE_TITLE, m_pageTitle ); - m_page.writeToNBT( nbt ); + nbt.putBoolean( NBT_PRINTING, printing ); + nbt.putString( NBT_PAGE_TITLE, pageTitle ); + page.writeToNBT( nbt ); } // Write inventory - ItemStackHelper.saveAllItems( nbt, m_inventory ); + ItemStackHelper.saveAllItems( nbt, inventory ); return super.save( nbt ); } boolean isPrinting() { - return m_printing; + return printing; } // IInventory implementation @Override public int getContainerSize() { - return m_inventory.size(); + return inventory.size(); } @Override public boolean isEmpty() { - for( ItemStack stack : m_inventory ) + for( ItemStack stack : inventory ) { if( !stack.isEmpty() ) return false; } @@ -158,15 +158,15 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Override public ItemStack getItem( int slot ) { - return m_inventory.get( slot ); + return inventory.get( slot ); } @Nonnull @Override public ItemStack removeItemNoUpdate( int slot ) { - ItemStack result = m_inventory.get( slot ); - m_inventory.set( slot, ItemStack.EMPTY ); + ItemStack result = inventory.get( slot ); + inventory.set( slot, ItemStack.EMPTY ); setChanged(); updateBlockState(); return result; @@ -176,7 +176,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Override public ItemStack removeItem( int slot, int count ) { - ItemStack stack = m_inventory.get( slot ); + ItemStack stack = inventory.get( slot ); if( stack.isEmpty() ) return ItemStack.EMPTY; if( stack.getCount() <= count ) @@ -186,9 +186,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } ItemStack part = stack.split( count ); - if( m_inventory.get( slot ).isEmpty() ) + if( inventory.get( slot ).isEmpty() ) { - m_inventory.set( slot, ItemStack.EMPTY ); + inventory.set( slot, ItemStack.EMPTY ); updateBlockState(); } setChanged(); @@ -198,7 +198,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Override public void setItem( int slot, @Nonnull ItemStack stack ) { - m_inventory.set( slot, stack ); + inventory.set( slot, stack ); setChanged(); updateBlockState(); } @@ -206,7 +206,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Override public void clearContent() { - for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY ); + for( int i = 0; i < inventory.size(); i++ ) inventory.set( i, ItemStack.EMPTY ); setChanged(); updateBlockState(); } @@ -254,33 +254,33 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent @Nullable Terminal getCurrentPage() { - synchronized( m_page ) + synchronized( page ) { - return m_printing ? m_page : null; + return printing ? page : null; } } boolean startNewPage() { - synchronized( m_page ) + synchronized( page ) { if( !canInputPage() ) return false; - if( m_printing && !outputPage() ) return false; + if( printing && !outputPage() ) return false; return inputPage(); } } boolean endCurrentPage() { - synchronized( m_page ) + synchronized( page ) { - return m_printing && outputPage(); + return printing && outputPage(); } } int getInkLevel() { - ItemStack inkStack = m_inventory.get( 0 ); + ItemStack inkStack = inventory.get( 0 ); return isInk( inkStack ) ? inkStack.getCount() : 0; } @@ -289,7 +289,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent int count = 0; for( int i = 1; i < 7; i++ ) { - ItemStack paperStack = m_inventory.get( i ); + ItemStack paperStack = inventory.get( i ); if( isPaper( paperStack ) ) count += paperStack.getCount(); } return count; @@ -297,9 +297,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent void setPageTitle( String title ) { - synchronized( m_page ) + synchronized( page ) { - if( m_printing ) m_pageTitle = title; + if( printing ) pageTitle = title; } } @@ -317,55 +317,55 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private boolean canInputPage() { - ItemStack inkStack = m_inventory.get( 0 ); + ItemStack inkStack = inventory.get( 0 ); return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0; } private boolean inputPage() { - ItemStack inkStack = m_inventory.get( 0 ); + ItemStack inkStack = inventory.get( 0 ); DyeColor dye = ColourUtils.getStackColour( inkStack ); if( dye == null ) return false; for( int i = 1; i < 7; i++ ) { - ItemStack paperStack = m_inventory.get( i ); + ItemStack paperStack = inventory.get( i ); if( paperStack.isEmpty() || !isPaper( paperStack ) ) continue; // Setup the new page - m_page.setTextColour( dye.getId() ); + page.setTextColour( dye.getId() ); - m_page.clear(); + page.clear(); if( paperStack.getItem() instanceof ItemPrintout ) { - m_pageTitle = ItemPrintout.getTitle( paperStack ); + pageTitle = ItemPrintout.getTitle( paperStack ); String[] text = ItemPrintout.getText( paperStack ); String[] textColour = ItemPrintout.getColours( paperStack ); - for( int y = 0; y < m_page.getHeight(); y++ ) + for( int y = 0; y < page.getHeight(); y++ ) { - m_page.setLine( y, text[y], textColour[y], "" ); + page.setLine( y, text[y], textColour[y], "" ); } } else { - m_pageTitle = ""; + pageTitle = ""; } - m_page.setCursorPos( 0, 0 ); + page.setCursorPos( 0, 0 ); // Decrement ink inkStack.shrink( 1 ); - if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY ); + if( inkStack.isEmpty() ) inventory.set( 0, ItemStack.EMPTY ); // Decrement paper paperStack.shrink( 1 ); if( paperStack.isEmpty() ) { - m_inventory.set( i, ItemStack.EMPTY ); + inventory.set( i, ItemStack.EMPTY ); updateBlockState(); } setChanged(); - m_printing = true; + printing = true; return true; } return false; @@ -373,22 +373,22 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent private boolean outputPage() { - int height = m_page.getHeight(); + int height = page.getHeight(); String[] lines = new String[height]; String[] colours = new String[height]; for( int i = 0; i < height; i++ ) { - lines[i] = m_page.getLine( i ).toString(); - colours[i] = m_page.getTextColourLine( i ).toString(); + lines[i] = page.getLine( i ).toString(); + colours[i] = page.getTextColourLine( i ).toString(); } - ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours ); + ItemStack stack = ItemPrintout.createSingleFromTitleAndText( pageTitle, lines, colours ); for( int slot : BOTTOM_SLOTS ) { - if( m_inventory.get( slot ).isEmpty() ) + if( inventory.get( slot ).isEmpty() ) { setItem( slot, stack ); - m_printing = false; + printing = false; return true; } } @@ -399,7 +399,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent { for( int i = 0; i < 13; i++ ) { - ItemStack stack = m_inventory.get( i ); + ItemStack stack = inventory.get( i ); if( !stack.isEmpty() ) { // Remove the stack from the inventory @@ -416,7 +416,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent boolean top = false, bottom = false; for( int i = 1; i < 7; i++ ) { - ItemStack stack = m_inventory.get( i ); + ItemStack stack = inventory.get( i ); if( !stack.isEmpty() && isPaper( stack ) ) { top = true; @@ -425,7 +425,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } for( int i = 7; i < 13; i++ ) { - ItemStack stack = m_inventory.get( i ); + ItemStack stack = inventory.get( i ); if( !stack.isEmpty() && isPaper( stack ) ) { bottom = true; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 00492d4e9..ce7a3710f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -32,14 +32,14 @@ import static dan200.computercraft.api.lua.LuaValues.checkFinite; */ public abstract class SpeakerPeripheral implements IPeripheral { - private long m_clock = 0; - private long m_lastPlayTime = 0; - private final AtomicInteger m_notesThisTick = new AtomicInteger(); + private long clock = 0; + private long lastPlayTime = 0; + private final AtomicInteger notesThisTick = new AtomicInteger(); public void update() { - m_clock++; - m_notesThisTick.set( 0 ); + clock++; + notesThisTick.set( 0 ); } public abstract World getWorld(); @@ -48,7 +48,7 @@ public abstract class SpeakerPeripheral implements IPeripheral public boolean madeSound( long ticks ) { - return m_clock - m_lastPlayTime <= ticks; + return clock - lastPlayTime <= ticks; } @Nonnull @@ -129,14 +129,14 @@ public abstract class SpeakerPeripheral implements IPeripheral // If the resource location for note block notes changes, this method call will need to be updated boolean success = playSound( context, instrument.getSoundEvent().getRegistryName(), volume, (float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true ); - if( success ) m_notesThisTick.incrementAndGet(); + if( success ) notesThisTick.incrementAndGet(); return success; } private synchronized boolean playSound( ILuaContext context, ResourceLocation name, float volume, float pitch, boolean isNote ) throws LuaException { - if( m_clock - m_lastPlayTime < TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS && - (!isNote || m_clock - m_lastPlayTime != 0 || m_notesThisTick.get() >= ComputerCraft.maxNotesPerTick) ) + if( clock - lastPlayTime < TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS && + (!isNote || clock - lastPlayTime != 0 || notesThisTick.get() >= ComputerCraft.maxNotesPerTick) ) { // Rate limiting occurs when we've already played a sound within the last tick, or we've // played more notes than allowable within the current tick. @@ -158,7 +158,7 @@ public abstract class SpeakerPeripheral implements IPeripheral return null; } ); - m_lastPlayTime = m_clock; + lastPlayTime = clock; return true; } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index c098c0cd9..45df5ce0e 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -35,9 +35,9 @@ import static dan200.computercraft.shared.pocket.items.ItemPocketComputer.NBT_LI public class PocketServerComputer extends ServerComputer implements IPocketAccess { - private IPocketUpgrade m_upgrade; - private Entity m_entity; - private ItemStack m_stack; + private IPocketUpgrade upgrade; + private Entity entity; + private ItemStack stack; public PocketServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family ) { @@ -48,18 +48,18 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public Entity getEntity() { - Entity entity = m_entity; - if( entity == null || m_stack == null || !entity.isAlive() ) return null; + Entity entity = this.entity; + if( entity == null || stack == null || !entity.isAlive() ) return null; if( entity instanceof PlayerEntity ) { PlayerInventory inventory = ((PlayerEntity) entity).inventory; - return inventory.items.contains( m_stack ) || inventory.offhand.contains( m_stack ) ? entity : null; + return inventory.items.contains( stack ) || inventory.offhand.contains( stack ) ? entity : null; } else if( entity instanceof LivingEntity ) { LivingEntity living = (LivingEntity) entity; - return living.getMainHandItem() == m_stack || living.getOffhandItem() == m_stack ? entity : null; + return living.getMainHandItem() == stack || living.getOffhandItem() == stack ? entity : null; } else { @@ -70,13 +70,13 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public int getColour() { - return IColouredItem.getColourBasic( m_stack ); + return IColouredItem.getColourBasic( stack ); } @Override public void setColour( int colour ) { - IColouredItem.setColourBasic( m_stack, colour ); + IColouredItem.setColourBasic( stack, colour ); updateUpgradeNBTData(); } @@ -110,19 +110,19 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public CompoundNBT getUpgradeNBTData() { - return ItemPocketComputer.getUpgradeInfo( m_stack ); + return ItemPocketComputer.getUpgradeInfo( stack ); } @Override public void updateUpgradeNBTData() { - if( m_entity instanceof PlayerEntity ) ((PlayerEntity) m_entity).inventory.setChanged(); + if( entity instanceof PlayerEntity ) ((PlayerEntity) entity).inventory.setChanged(); } @Override public void invalidatePeripheral() { - IPeripheral peripheral = m_upgrade == null ? null : m_upgrade.createPeripheral( this ); + IPeripheral peripheral = upgrade == null ? null : upgrade.createPeripheral( this ); setPeripheral( ComputerSide.BACK, peripheral ); } @@ -130,12 +130,12 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public Map getUpgrades() { - return m_upgrade == null ? Collections.emptyMap() : Collections.singletonMap( m_upgrade.getUpgradeID(), getPeripheral( ComputerSide.BACK ) ); + return upgrade == null ? Collections.emptyMap() : Collections.singletonMap( upgrade.getUpgradeID(), getPeripheral( ComputerSide.BACK ) ); } public IPocketUpgrade getUpgrade() { - return m_upgrade; + return upgrade; } /** @@ -147,13 +147,13 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces */ public void setUpgrade( IPocketUpgrade upgrade ) { - if( m_upgrade == upgrade ) return; + if( this.upgrade == upgrade ) return; synchronized( this ) { - ItemPocketComputer.setUpgrade( m_stack, upgrade ); + ItemPocketComputer.setUpgrade( stack, upgrade ); updateUpgradeNBTData(); - m_upgrade = upgrade; + this.upgrade = upgrade; invalidatePeripheral(); } } @@ -167,14 +167,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces } // If a new entity has picked it up then rebroadcast the terminal to them - if( entity != m_entity && entity instanceof ServerPlayerEntity ) markTerminalChanged(); + if( entity != this.entity && entity instanceof ServerPlayerEntity ) markTerminalChanged(); - m_entity = entity; - m_stack = stack; + this.entity = entity; + this.stack = stack; - if( m_upgrade != upgrade ) + if( this.upgrade != upgrade ) { - m_upgrade = upgrade; + this.upgrade = upgrade; invalidatePeripheral(); } } @@ -184,10 +184,10 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces { super.broadcastState( force ); - if( (hasTerminalChanged() || force) && m_entity instanceof ServerPlayerEntity ) + if( (hasTerminalChanged() || force) && entity instanceof ServerPlayerEntity ) { // Broadcast the state to the current entity if they're not already interacting with it. - ServerPlayerEntity player = (ServerPlayerEntity) m_entity; + ServerPlayerEntity player = (ServerPlayerEntity) entity; if( player.connection != null && !isInteracting( player ) ) { NetworkHandler.sendToPlayer( player, createTerminalPacket() ); diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 561743557..f3c47e573 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -38,8 +38,6 @@ import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -361,14 +359,12 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I stack.getOrCreateTag().putInt( NBT_SESSION, sessionID ); } - @OnlyIn( Dist.CLIENT ) public static ComputerState getState( @Nonnull ItemStack stack ) { ClientComputer computer = getClientComputer( stack ); return computer == null ? ComputerState.OFF : computer.getState(); } - @OnlyIn( Dist.CLIENT ) public static int getLightState( @Nonnull ItemStack stack ) { ClientComputer computer = getClientComputer( stack ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 46b5fef4c..5b6ed3ec8 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -63,13 +63,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default MOVED } - private final NonNullList m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); - private final NonNullList m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); - private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this ); + private final NonNullList inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + private final NonNullList previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY ); + private final IItemHandlerModifiable itemHandler = new InvWrapper( this ); private LazyOptional itemHandlerCap; - private boolean m_inventoryChanged = false; - private TurtleBrain m_brain = new TurtleBrain( this ); - private MoveState m_moveState = MoveState.NOT_MOVED; + private boolean inventoryChanged = false; + private TurtleBrain brain = new TurtleBrain( this ); + private MoveState moveState = MoveState.NOT_MOVED; private LazyOptional peripheral; public TileTurtle( TileEntityType type, ComputerFamily family ) @@ -79,7 +79,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default private boolean hasMoved() { - return m_moveState == MoveState.MOVED; + return moveState == MoveState.MOVED; } @Override @@ -91,13 +91,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default ); computer.setPosition( getBlockPos() ); computer.addAPI( new TurtleAPI( computer.getAPIEnvironment(), getAccess() ) ); - m_brain.setupComputer( computer ); + brain.setupComputer( computer ); return computer; } public ComputerProxy createProxy() { - return m_brain.getProxy(); + return brain.getProxy(); } @Override @@ -163,9 +163,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default if( !getLevel().isClientSide ) { DyeColor dye = ((DyeItem) currentItem.getItem()).getDyeColor(); - if( m_brain.getDyeColour() != dye ) + if( brain.getDyeColour() != dye ) { - m_brain.setDyeColour( dye ); + brain.setDyeColour( dye ); if( !player.isCreative() ) { currentItem.shrink( 1 ); @@ -174,14 +174,14 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } return ActionResultType.SUCCESS; } - else if( currentItem.getItem() == Items.WATER_BUCKET && m_brain.getColour() != -1 ) + else if( currentItem.getItem() == Items.WATER_BUCKET && brain.getColour() != -1 ) { // Water to remove turtle colour if( !getLevel().isClientSide ) { - if( m_brain.getColour() != -1 ) + if( brain.getColour() != -1 ) { - m_brain.setColour( -1 ); + brain.setColour( -1 ); if( !player.isCreative() ) { player.setItemInHand( hand, new ItemStack( Items.BUCKET ) ); @@ -213,16 +213,16 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public void tick() { super.tick(); - m_brain.update(); - if( !getLevel().isClientSide && m_inventoryChanged ) + brain.update(); + if( !getLevel().isClientSide && inventoryChanged ) { ServerComputer computer = getServerComputer(); if( computer != null ) computer.queueEvent( "turtle_inventory" ); - m_inventoryChanged = false; + inventoryChanged = false; for( int n = 0; n < getContainerSize(); n++ ) { - m_previousInventory.set( n, getItem( n ).copy() ); + previousInventory.set( n, getItem( n ).copy() ); } } } @@ -235,24 +235,24 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public void onNeighbourChange( @Nonnull BlockPos neighbour ) { - if( m_moveState == MoveState.NOT_MOVED ) super.onNeighbourChange( neighbour ); + if( moveState == MoveState.NOT_MOVED ) super.onNeighbourChange( neighbour ); } @Override public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) { - if( m_moveState == MoveState.NOT_MOVED ) super.onNeighbourTileEntityChange( neighbour ); + if( moveState == MoveState.NOT_MOVED ) super.onNeighbourTileEntityChange( neighbour ); } public void notifyMoveStart() { - if( m_moveState == MoveState.NOT_MOVED ) m_moveState = MoveState.IN_PROGRESS; + if( moveState == MoveState.NOT_MOVED ) moveState = MoveState.IN_PROGRESS; } public void notifyMoveEnd() { // MoveState.MOVED is final - if( m_moveState == MoveState.IN_PROGRESS ) m_moveState = MoveState.NOT_MOVED; + if( moveState == MoveState.IN_PROGRESS ) moveState = MoveState.NOT_MOVED; } @Override @@ -262,21 +262,21 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default // Read inventory ListNBT nbttaglist = nbt.getList( "Items", Constants.NBT.TAG_COMPOUND ); - m_inventory.clear(); - m_previousInventory.clear(); + inventory.clear(); + previousInventory.clear(); for( int i = 0; i < nbttaglist.size(); i++ ) { CompoundNBT tag = nbttaglist.getCompound( i ); int slot = tag.getByte( "Slot" ) & 0xff; if( slot < getContainerSize() ) { - m_inventory.set( slot, ItemStack.of( tag ) ); - m_previousInventory.set( slot, m_inventory.get( slot ).copy() ); + inventory.set( slot, ItemStack.of( tag ) ); + previousInventory.set( slot, inventory.get( slot ).copy() ); } } // Read state - m_brain.readFromNBT( nbt ); + brain.readFromNBT( nbt ); } @Nonnull @@ -287,18 +287,18 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default ListNBT nbttaglist = new ListNBT(); for( int i = 0; i < INVENTORY_SIZE; i++ ) { - if( !m_inventory.get( i ).isEmpty() ) + if( !inventory.get( i ).isEmpty() ) { CompoundNBT tag = new CompoundNBT(); tag.putByte( "Slot", (byte) i ); - m_inventory.get( i ).save( tag ); + inventory.get( i ).save( tag ); nbttaglist.add( tag ); } } nbt.put( "Items", nbttaglist ); // Write brain - nbt = m_brain.writeToNBT( nbt ); + nbt = brain.writeToNBT( nbt ); return super.save( nbt ); } @@ -331,48 +331,48 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public ITurtleUpgrade getUpgrade( TurtleSide side ) { - return m_brain.getUpgrade( side ); + return brain.getUpgrade( side ); } @Override public int getColour() { - return m_brain.getColour(); + return brain.getColour(); } @Override public ResourceLocation getOverlay() { - return m_brain.getOverlay(); + return brain.getOverlay(); } @Override public ITurtleAccess getAccess() { - return m_brain; + return brain; } @Override public Vec3d getRenderOffset( float f ) { - return m_brain.getRenderOffset( f ); + return brain.getRenderOffset( f ); } @Override public float getRenderYaw( float f ) { - return m_brain.getVisualYaw( f ); + return brain.getVisualYaw( f ); } @Override public float getToolRenderAngle( TurtleSide side, float f ) { - return m_brain.getToolRenderAngle( side, f ); + return brain.getToolRenderAngle( side, f ); } void setOwningPlayer( GameProfile player ) { - m_brain.setOwningPlayer( player ); + brain.setOwningPlayer( player ); setChanged(); } @@ -387,7 +387,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public boolean isEmpty() { - for( ItemStack stack : m_inventory ) + for( ItemStack stack : inventory ) { if( !stack.isEmpty() ) return false; } @@ -398,7 +398,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public ItemStack getItem( int slot ) { - return slot >= 0 && slot < INVENTORY_SIZE ? m_inventory.get( slot ) : ItemStack.EMPTY; + return slot >= 0 && slot < INVENTORY_SIZE ? inventory.get( slot ) : ItemStack.EMPTY; } @Nonnull @@ -433,9 +433,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public void setItem( int i, @Nonnull ItemStack stack ) { - if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, m_inventory.get( i ) ) ) + if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, inventory.get( i ) ) ) { - m_inventory.set( i, stack ); + inventory.set( i, stack ); onInventoryDefinitelyChanged(); } } @@ -446,9 +446,9 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default boolean changed = false; for( int i = 0; i < INVENTORY_SIZE; i++ ) { - if( !m_inventory.get( i ).isEmpty() ) + if( !inventory.get( i ).isEmpty() ) { - m_inventory.set( i, ItemStack.EMPTY ); + inventory.set( i, ItemStack.EMPTY ); changed = true; } } @@ -460,13 +460,13 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public void setChanged() { super.setChanged(); - if( !m_inventoryChanged ) + if( !inventoryChanged ) { for( int n = 0; n < getContainerSize(); n++ ) { - if( !ItemStack.matches( getItem( n ), m_previousInventory.get( n ) ) ) + if( !ItemStack.matches( getItem( n ), previousInventory.get( n ) ) ) { - m_inventoryChanged = true; + inventoryChanged = true; break; } } @@ -482,7 +482,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default private void onInventoryDefinitelyChanged() { super.setChanged(); - m_inventoryChanged = true; + inventoryChanged = true; } public void onTileEntityChange() @@ -496,14 +496,14 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default protected void writeDescription( @Nonnull CompoundNBT nbt ) { super.writeDescription( nbt ); - m_brain.writeDescription( nbt ); + brain.writeDescription( nbt ); } @Override protected void readDescription( @Nonnull CompoundNBT nbt ) { super.readDescription( nbt ); - m_brain.readDescription( nbt ); + brain.readDescription( nbt ); } // Privates @@ -528,20 +528,20 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default public void transferStateFrom( TileTurtle copy ) { super.transferStateFrom( copy ); - Collections.copy( m_inventory, copy.m_inventory ); - Collections.copy( m_previousInventory, copy.m_previousInventory ); - m_inventoryChanged = copy.m_inventoryChanged; - m_brain = copy.m_brain; - m_brain.setOwner( this ); + Collections.copy( inventory, copy.inventory ); + Collections.copy( previousInventory, copy.previousInventory ); + inventoryChanged = copy.inventoryChanged; + brain = copy.brain; + brain.setOwner( this ); // Mark the other turtle as having moved, and so its peripheral is dead. - copy.m_moveState = MoveState.MOVED; + copy.moveState = MoveState.MOVED; copy.peripheral = CapabilityUtil.invalidate( copy.peripheral ); } public IItemHandlerModifiable getItemHandler() { - return m_itemHandler; + return itemHandler; } @Nonnull @@ -571,6 +571,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) { - return new ContainerTurtle( id, inventory, m_brain ); + return new ContainerTurtle( id, inventory, brain ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index 9ba2d1456..5efd001ea 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -65,55 +65,55 @@ public class TurtleBrain implements ITurtleAccess private static final int ANIM_DURATION = 8; - private TileTurtle m_owner; - private ComputerProxy m_proxy; - private GameProfile m_owningPlayer; + private TileTurtle owner; + private ComputerProxy proxy; + private GameProfile owningPlayer; - private final IInventory m_inventory = (InventoryDelegate) () -> m_owner; - private final IItemHandlerModifiable m_inventoryWrapper = new InvWrapper( m_inventory ); + private final IInventory inventory = (InventoryDelegate) () -> owner; + private final IItemHandlerModifiable inventoryWrapper = new InvWrapper( inventory ); - private final Queue m_commandQueue = new ArrayDeque<>(); - private int m_commandsIssued = 0; + private final Queue commandQueue = new ArrayDeque<>(); + private int commandsIssued = 0; - private final Map m_upgrades = new EnumMap<>( TurtleSide.class ); + private final Map upgrades = new EnumMap<>( TurtleSide.class ); private final Map peripherals = new EnumMap<>( TurtleSide.class ); - private final Map m_upgradeNBTData = new EnumMap<>( TurtleSide.class ); + private final Map upgradeNBTData = new EnumMap<>( TurtleSide.class ); - private int m_selectedSlot = 0; - private int m_fuelLevel = 0; - private int m_colourHex = -1; - private ResourceLocation m_overlay = null; + private int selectedSlot = 0; + private int fuelLevel = 0; + private int colourHex = -1; + private ResourceLocation overlay = null; - private TurtleAnimation m_animation = TurtleAnimation.NONE; - private int m_animationProgress = 0; - private int m_lastAnimationProgress = 0; + private TurtleAnimation animation = TurtleAnimation.NONE; + private int animationProgress = 0; + private int lastAnimationProgress = 0; - TurtlePlayer m_cachedPlayer; + TurtlePlayer cachedPlayer; public TurtleBrain( TileTurtle turtle ) { - m_owner = turtle; + owner = turtle; } public void setOwner( TileTurtle owner ) { - m_owner = owner; + this.owner = owner; } public TileTurtle getOwner() { - return m_owner; + return owner; } public ComputerProxy getProxy() { - if( m_proxy == null ) m_proxy = new ComputerProxy( () -> m_owner ); - return m_proxy; + if( proxy == null ) proxy = new ComputerProxy( () -> owner ); + return proxy; } public ComputerFamily getFamily() { - return m_owner.getFamily(); + return owner.getFamily(); } public void setupComputer( ServerComputer computer ) @@ -131,16 +131,16 @@ public class TurtleBrain implements ITurtleAccess // The block may have been broken while the command was executing (for instance, if a block explodes // when being mined). If so, abort. - if( m_owner.isRemoved() ) return; + if( owner.isRemoved() ) return; } // Advance animation updateAnimation(); // Advance upgrades - if( !m_upgrades.isEmpty() ) + if( !upgrades.isEmpty() ) { - for( Map.Entry entry : m_upgrades.entrySet() ) + for( Map.Entry entry : upgrades.entrySet() ) { entry.getValue().update( this, entry.getKey() ); } @@ -155,31 +155,31 @@ public class TurtleBrain implements ITurtleAccess private void readCommon( CompoundNBT nbt ) { // Read fields - m_colourHex = nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : -1; - m_fuelLevel = nbt.contains( NBT_FUEL ) ? nbt.getInt( NBT_FUEL ) : 0; - m_overlay = nbt.contains( NBT_OVERLAY ) ? new ResourceLocation( nbt.getString( NBT_OVERLAY ) ) : null; + colourHex = nbt.contains( NBT_COLOUR ) ? nbt.getInt( NBT_COLOUR ) : -1; + fuelLevel = nbt.contains( NBT_FUEL ) ? nbt.getInt( NBT_FUEL ) : 0; + overlay = nbt.contains( NBT_OVERLAY ) ? new ResourceLocation( nbt.getString( NBT_OVERLAY ) ) : null; // Read upgrades setUpgrade( TurtleSide.LEFT, nbt.contains( NBT_LEFT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_LEFT_UPGRADE ) ) : null ); setUpgrade( TurtleSide.RIGHT, nbt.contains( NBT_RIGHT_UPGRADE ) ? TurtleUpgrades.get( nbt.getString( NBT_RIGHT_UPGRADE ) ) : null ); // NBT - m_upgradeNBTData.clear(); + upgradeNBTData.clear(); if( nbt.contains( NBT_LEFT_UPGRADE_DATA ) ) { - m_upgradeNBTData.put( TurtleSide.LEFT, nbt.getCompound( NBT_LEFT_UPGRADE_DATA ).copy() ); + upgradeNBTData.put( TurtleSide.LEFT, nbt.getCompound( NBT_LEFT_UPGRADE_DATA ).copy() ); } if( nbt.contains( NBT_RIGHT_UPGRADE_DATA ) ) { - m_upgradeNBTData.put( TurtleSide.RIGHT, nbt.getCompound( NBT_RIGHT_UPGRADE_DATA ).copy() ); + upgradeNBTData.put( TurtleSide.RIGHT, nbt.getCompound( NBT_RIGHT_UPGRADE_DATA ).copy() ); } } private void writeCommon( CompoundNBT nbt ) { - nbt.putInt( NBT_FUEL, m_fuelLevel ); - if( m_colourHex != -1 ) nbt.putInt( NBT_COLOUR, m_colourHex ); - if( m_overlay != null ) nbt.putString( NBT_OVERLAY, m_overlay.toString() ); + nbt.putInt( NBT_FUEL, fuelLevel ); + if( colourHex != -1 ) nbt.putInt( NBT_COLOUR, colourHex ); + if( overlay != null ) nbt.putString( NBT_OVERLAY, overlay.toString() ); // Write upgrades String leftUpgradeId = getUpgradeId( getUpgrade( TurtleSide.LEFT ) ); @@ -188,11 +188,11 @@ public class TurtleBrain implements ITurtleAccess if( rightUpgradeId != null ) nbt.putString( NBT_RIGHT_UPGRADE, rightUpgradeId ); // Write upgrade NBT - if( m_upgradeNBTData.containsKey( TurtleSide.LEFT ) ) + if( upgradeNBTData.containsKey( TurtleSide.LEFT ) ) { nbt.put( NBT_LEFT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.LEFT ).copy() ); } - if( m_upgradeNBTData.containsKey( TurtleSide.RIGHT ) ) + if( upgradeNBTData.containsKey( TurtleSide.RIGHT ) ) { nbt.put( NBT_RIGHT_UPGRADE_DATA, getUpgradeNBTData( TurtleSide.RIGHT ).copy() ); } @@ -203,20 +203,20 @@ public class TurtleBrain implements ITurtleAccess readCommon( nbt ); // Read state - m_selectedSlot = nbt.getInt( NBT_SLOT ); + selectedSlot = nbt.getInt( NBT_SLOT ); // Read owner if( nbt.contains( "Owner", Constants.NBT.TAG_COMPOUND ) ) { CompoundNBT owner = nbt.getCompound( "Owner" ); - m_owningPlayer = new GameProfile( + owningPlayer = new GameProfile( new UUID( owner.getLong( "UpperId" ), owner.getLong( "LowerId" ) ), owner.getString( "Name" ) ); } else { - m_owningPlayer = null; + owningPlayer = null; } } @@ -225,17 +225,17 @@ public class TurtleBrain implements ITurtleAccess writeCommon( nbt ); // Write state - nbt.putInt( NBT_SLOT, m_selectedSlot ); + nbt.putInt( NBT_SLOT, selectedSlot ); // Write owner - if( m_owningPlayer != null ) + if( owningPlayer != null ) { CompoundNBT owner = new CompoundNBT(); nbt.put( "Owner", owner ); - owner.putLong( "UpperId", m_owningPlayer.getId().getMostSignificantBits() ); - owner.putLong( "LowerId", m_owningPlayer.getId().getLeastSignificantBits() ); - owner.putString( "Name", m_owningPlayer.getName() ); + owner.putLong( "UpperId", owningPlayer.getId().getMostSignificantBits() ); + owner.putLong( "LowerId", owningPlayer.getId().getLeastSignificantBits() ); + owner.putString( "Name", owningPlayer.getName() ); } return nbt; @@ -252,35 +252,35 @@ public class TurtleBrain implements ITurtleAccess // Animation TurtleAnimation anim = TurtleAnimation.values()[nbt.getInt( "Animation" )]; - if( anim != m_animation && + if( anim != animation && anim != TurtleAnimation.WAIT && anim != TurtleAnimation.SHORT_WAIT && anim != TurtleAnimation.NONE ) { - m_animation = anim; - m_animationProgress = 0; - m_lastAnimationProgress = 0; + animation = anim; + animationProgress = 0; + lastAnimationProgress = 0; } } public void writeDescription( CompoundNBT nbt ) { writeCommon( nbt ); - nbt.putInt( "Animation", m_animation.ordinal() ); + nbt.putInt( "Animation", animation.ordinal() ); } @Nonnull @Override public World getWorld() { - return m_owner.getLevel(); + return owner.getLevel(); } @Nonnull @Override public BlockPos getPosition() { - return m_owner.getBlockPos(); + return owner.getBlockPos(); } @Override @@ -293,9 +293,9 @@ public class TurtleBrain implements ITurtleAccess // Cache info about the old turtle (so we don't access this after we delete ourselves) World oldWorld = getWorld(); - TileTurtle oldOwner = m_owner; - BlockPos oldPos = m_owner.getBlockPos(); - BlockState oldBlock = m_owner.getBlockState(); + TileTurtle oldOwner = owner; + BlockPos oldPos = owner.getBlockPos(); + BlockState oldBlock = owner.getBlockState(); if( oldWorld == world && oldPos.equals( pos ) ) { @@ -365,7 +365,7 @@ public class TurtleBrain implements ITurtleAccess public Vec3d getVisualPosition( float f ) { Vec3d offset = getRenderOffset( f ); - BlockPos pos = m_owner.getBlockPos(); + BlockPos pos = owner.getBlockPos(); return new Vec3d( pos.getX() + 0.5 + offset.x, pos.getY() + 0.5 + offset.y, @@ -377,7 +377,7 @@ public class TurtleBrain implements ITurtleAccess public float getVisualYaw( float f ) { float yaw = getDirection().toYRot(); - switch( m_animation ) + switch( animation ) { case TURN_LEFT: { @@ -405,19 +405,19 @@ public class TurtleBrain implements ITurtleAccess @Override public Direction getDirection() { - return m_owner.getDirection(); + return owner.getDirection(); } @Override public void setDirection( @Nonnull Direction dir ) { - m_owner.setDirection( dir ); + owner.setDirection( dir ); } @Override public int getSelectedSlot() { - return m_selectedSlot; + return selectedSlot; } @Override @@ -425,10 +425,10 @@ public class TurtleBrain implements ITurtleAccess { if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot set the slot on the client" ); - if( slot >= 0 && slot < m_owner.getContainerSize() ) + if( slot >= 0 && slot < owner.getContainerSize() ) { - m_selectedSlot = slot; - m_owner.onTileEntityChange(); + selectedSlot = slot; + owner.onTileEntityChange(); } } @@ -436,14 +436,14 @@ public class TurtleBrain implements ITurtleAccess @Override public IInventory getInventory() { - return m_inventory; + return inventory; } @Nonnull @Override public IItemHandlerModifiable getItemHandler() { - return m_inventoryWrapper; + return inventoryWrapper; } @Override @@ -455,20 +455,20 @@ public class TurtleBrain implements ITurtleAccess @Override public int getFuelLevel() { - return Math.min( m_fuelLevel, getFuelLimit() ); + return Math.min( fuelLevel, getFuelLimit() ); } @Override public void setFuelLevel( int level ) { - m_fuelLevel = Math.min( level, getFuelLimit() ); - m_owner.onTileEntityChange(); + fuelLevel = Math.min( level, getFuelLimit() ); + owner.onTileEntityChange(); } @Override public int getFuelLimit() { - if( m_owner.getFamily() == ComputerFamily.ADVANCED ) + if( owner.getFamily() == ComputerFamily.ADVANCED ) { return ComputerCraft.advancedTurtleFuelLimit; } @@ -505,8 +505,8 @@ public class TurtleBrain implements ITurtleAccess private int issueCommand( ITurtleCommand command ) { - m_commandQueue.offer( new TurtleCommandQueueEntry( ++m_commandsIssued, command ) ); - return m_commandsIssued; + commandQueue.offer( new TurtleCommandQueueEntry( ++commandsIssued, command ) ); + return commandsIssued; } @Nonnull @@ -525,38 +525,38 @@ public class TurtleBrain implements ITurtleAccess { if( getWorld().isClientSide ) throw new UnsupportedOperationException( "Cannot play animations on the client" ); - m_animation = animation; - if( m_animation == TurtleAnimation.SHORT_WAIT ) + this.animation = animation; + if( this.animation == TurtleAnimation.SHORT_WAIT ) { - m_animationProgress = ANIM_DURATION / 2; - m_lastAnimationProgress = ANIM_DURATION / 2; + animationProgress = ANIM_DURATION / 2; + lastAnimationProgress = ANIM_DURATION / 2; } else { - m_animationProgress = 0; - m_lastAnimationProgress = 0; + animationProgress = 0; + lastAnimationProgress = 0; } - m_owner.updateBlock(); + owner.updateBlock(); } public ResourceLocation getOverlay() { - return m_overlay; + return overlay; } public void setOverlay( ResourceLocation overlay ) { - if( !Objects.equal( m_overlay, overlay ) ) + if( !Objects.equal( this.overlay, overlay ) ) { - m_overlay = overlay; - m_owner.updateBlock(); + this.overlay = overlay; + owner.updateBlock(); } } public DyeColor getDyeColour() { - if( m_colourHex == -1 ) return null; - Colour colour = Colour.fromHex( m_colourHex ); + if( colourHex == -1 ) return null; + Colour colour = Colour.fromHex( colourHex ); return colour == null ? null : DyeColor.byId( 15 - colour.ordinal() ); } @@ -567,10 +567,10 @@ public class TurtleBrain implements ITurtleAccess { newColour = Colour.values()[15 - dyeColour.getId()].getHex(); } - if( m_colourHex != newColour ) + if( colourHex != newColour ) { - m_colourHex = newColour; - m_owner.updateBlock(); + colourHex = newColour; + owner.updateBlock(); } } @@ -579,67 +579,67 @@ public class TurtleBrain implements ITurtleAccess { if( colour >= 0 && colour <= 0xFFFFFF ) { - if( m_colourHex != colour ) + if( colourHex != colour ) { - m_colourHex = colour; - m_owner.updateBlock(); + colourHex = colour; + owner.updateBlock(); } } - else if( m_colourHex != -1 ) + else if( colourHex != -1 ) { - m_colourHex = -1; - m_owner.updateBlock(); + colourHex = -1; + owner.updateBlock(); } } @Override public int getColour() { - return m_colourHex; + return colourHex; } public void setOwningPlayer( GameProfile profile ) { - m_owningPlayer = profile; + owningPlayer = profile; } @Nullable @Override public GameProfile getOwningPlayer() { - return m_owningPlayer; + return owningPlayer; } @Override public ITurtleUpgrade getUpgrade( @Nonnull TurtleSide side ) { - return m_upgrades.get( side ); + return upgrades.get( side ); } @Override public void setUpgrade( @Nonnull TurtleSide side, ITurtleUpgrade upgrade ) { // Remove old upgrade - if( m_upgrades.containsKey( side ) ) + if( upgrades.containsKey( side ) ) { - if( m_upgrades.get( side ) == upgrade ) return; - m_upgrades.remove( side ); + if( upgrades.get( side ) == upgrade ) return; + upgrades.remove( side ); } else { if( upgrade == null ) return; } - m_upgradeNBTData.remove( side ); + upgradeNBTData.remove( side ); // Set new upgrade - if( upgrade != null ) m_upgrades.put( side, upgrade ); + if( upgrade != null ) upgrades.put( side, upgrade ); // Notify clients and create peripherals - if( m_owner.getLevel() != null ) + if( owner.getLevel() != null ) { - updatePeripherals( m_owner.createServerComputer() ); - m_owner.updateBlock(); + updatePeripherals( owner.createServerComputer() ); + owner.updateBlock(); } } @@ -653,20 +653,20 @@ public class TurtleBrain implements ITurtleAccess @Override public CompoundNBT getUpgradeNBTData( TurtleSide side ) { - CompoundNBT nbt = m_upgradeNBTData.get( side ); - if( nbt == null ) m_upgradeNBTData.put( side, nbt = new CompoundNBT() ); + CompoundNBT nbt = upgradeNBTData.get( side ); + if( nbt == null ) upgradeNBTData.put( side, nbt = new CompoundNBT() ); return nbt; } @Override public void updateUpgradeNBTData( @Nonnull TurtleSide side ) { - m_owner.updateBlock(); + owner.updateBlock(); } public Vec3d getRenderOffset( float f ) { - switch( m_animation ) + switch( animation ) { case MOVE_FORWARD: case MOVE_BACK: @@ -675,7 +675,7 @@ public class TurtleBrain implements ITurtleAccess { // Get direction Direction dir; - switch( m_animation ) + switch( animation ) { case MOVE_FORWARD: default: @@ -708,8 +708,8 @@ public class TurtleBrain implements ITurtleAccess public float getToolRenderAngle( TurtleSide side, float f ) { - return (side == TurtleSide.LEFT && m_animation == TurtleAnimation.SWING_LEFT_TOOL) || - (side == TurtleSide.RIGHT && m_animation == TurtleAnimation.SWING_RIGHT_TOOL) + return (side == TurtleSide.LEFT && animation == TurtleAnimation.SWING_LEFT_TOOL) || + (side == TurtleSide.RIGHT && animation == TurtleAnimation.SWING_RIGHT_TOOL) ? 45.0f * (float) Math.sin( getAnimationFraction( f ) * Math.PI ) : 0.0f; } @@ -759,14 +759,14 @@ public class TurtleBrain implements ITurtleAccess private void updateCommands() { - if( m_animation != TurtleAnimation.NONE || m_commandQueue.isEmpty() ) return; + if( animation != TurtleAnimation.NONE || commandQueue.isEmpty() ) return; // If we've got a computer, ensure that we're allowed to perform work. - ServerComputer computer = m_owner.getServerComputer(); + ServerComputer computer = owner.getServerComputer(); if( computer != null && !computer.getComputer().getMainThreadMonitor().canWork() ) return; // Pull a new command - TurtleCommandQueueEntry nextCommand = m_commandQueue.poll(); + TurtleCommandQueueEntry nextCommand = commandQueue.poll(); if( nextCommand == null ) return; // Execute the command @@ -808,21 +808,21 @@ public class TurtleBrain implements ITurtleAccess private void updateAnimation() { - if( m_animation != TurtleAnimation.NONE ) + if( animation != TurtleAnimation.NONE ) { World world = getWorld(); if( ComputerCraft.turtlesCanPush ) { // Advance entity pushing - if( m_animation == TurtleAnimation.MOVE_FORWARD || - m_animation == TurtleAnimation.MOVE_BACK || - m_animation == TurtleAnimation.MOVE_UP || - m_animation == TurtleAnimation.MOVE_DOWN ) + if( animation == TurtleAnimation.MOVE_FORWARD || + animation == TurtleAnimation.MOVE_BACK || + animation == TurtleAnimation.MOVE_UP || + animation == TurtleAnimation.MOVE_DOWN ) { BlockPos pos = getPosition(); Direction moveDir; - switch( m_animation ) + switch( animation ) { case MOVE_FORWARD: default: @@ -846,7 +846,7 @@ public class TurtleBrain implements ITurtleAccess double maxY = minY + 1.0; double maxZ = minZ + 1.0; - float pushFrac = 1.0f - (float) (m_animationProgress + 1) / ANIM_DURATION; + float pushFrac = 1.0f - (float) (animationProgress + 1) / ANIM_DURATION; float push = Math.max( pushFrac + 0.0125f, 0.0f ); if( moveDir.getStepX() < 0 ) { @@ -892,7 +892,7 @@ public class TurtleBrain implements ITurtleAccess } // Advance valentines day easter egg - if( world.isClientSide && m_animation == TurtleAnimation.MOVE_FORWARD && m_animationProgress == 4 ) + if( world.isClientSide && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4 ) { // Spawn love pfx if valentines day Holiday currentHoliday = HolidayUtil.getCurrentHoliday(); @@ -915,20 +915,20 @@ public class TurtleBrain implements ITurtleAccess } // Wait for anim completion - m_lastAnimationProgress = m_animationProgress; - if( ++m_animationProgress >= ANIM_DURATION ) + lastAnimationProgress = animationProgress; + if( ++animationProgress >= ANIM_DURATION ) { - m_animation = TurtleAnimation.NONE; - m_animationProgress = 0; - m_lastAnimationProgress = 0; + animation = TurtleAnimation.NONE; + animationProgress = 0; + lastAnimationProgress = 0; } } } private float getAnimationFraction( float f ) { - float next = (float) m_animationProgress / ANIM_DURATION; - float previous = (float) m_lastAnimationProgress / ANIM_DURATION; + float next = (float) animationProgress / ANIM_DURATION; + float previous = (float) lastAnimationProgress / ANIM_DURATION; return previous + (next - previous) * f; } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index 9c018ce25..ab5f895ef 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -23,11 +23,11 @@ import java.util.List; public class TurtleCompareCommand implements ITurtleCommand { - private final InteractDirection m_direction; + private final InteractDirection direction; public TurtleCompareCommand( InteractDirection direction ) { - m_direction = direction; + this.direction = direction; } @Nonnull @@ -35,7 +35,7 @@ public class TurtleCompareCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - Direction direction = m_direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); // Get currently selected stack ItemStack selectedStack = turtle.getInventory().getItem( turtle.getSelectedSlot() ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java index 74cc04b1e..494370efe 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareToCommand.java @@ -15,11 +15,11 @@ import javax.annotation.Nonnull; public class TurtleCompareToCommand implements ITurtleCommand { - private final int m_slot; + private final int slot; public TurtleCompareToCommand( int slot ) { - m_slot = slot; + this.slot = slot; } @Nonnull @@ -27,14 +27,9 @@ public class TurtleCompareToCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { ItemStack selectedStack = turtle.getInventory().getItem( turtle.getSelectedSlot() ); - ItemStack stack = turtle.getInventory().getItem( m_slot ); - if( InventoryUtil.areItemsStackable( selectedStack, stack ) ) - { - return TurtleCommandResult.success(); - } - else - { - return TurtleCommandResult.failure(); - } + ItemStack stack = turtle.getInventory().getItem( slot ); + return InventoryUtil.areItemsStackable( selectedStack, stack ) + ? TurtleCommandResult.success() + : TurtleCommandResult.failure(); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java index df3c79dc7..9600b8591 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -17,11 +17,11 @@ import javax.annotation.Nonnull; public class TurtleDetectCommand implements ITurtleCommand { - private final InteractDirection m_direction; + private final InteractDirection direction; public TurtleDetectCommand( InteractDirection direction ) { - m_direction = direction; + this.direction = direction; } @Nonnull @@ -29,7 +29,7 @@ public class TurtleDetectCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - Direction direction = m_direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not World world = turtle.getWorld(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java index 21d5f2a4d..3283108f1 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -23,13 +23,13 @@ import javax.annotation.Nonnull; public class TurtleDropCommand implements ITurtleCommand { - private final InteractDirection m_direction; - private final int m_quantity; + private final InteractDirection direction; + private final int quantity; public TurtleDropCommand( InteractDirection direction, int quantity ) { - m_direction = direction; - m_quantity = quantity; + this.direction = direction; + this.quantity = quantity; } @Nonnull @@ -37,17 +37,17 @@ public class TurtleDropCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Dropping nothing is easy - if( m_quantity == 0 ) + if( quantity == 0 ) { turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } // Get world direction from direction - Direction direction = m_direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); // Get things to drop - ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); + ItemStack stack = InventoryUtil.takeItems( quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); if( stack.isEmpty() ) { return TurtleCommandResult.failure( "No items to drop" ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java index b11ee4ff2..302be5a31 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -20,11 +20,11 @@ import javax.annotation.Nonnull; public class TurtleEquipCommand implements ITurtleCommand { - private final TurtleSide m_side; + private final TurtleSide side; public TurtleEquipCommand( TurtleSide side ) { - m_side = side; + this.side = side; } @Nonnull @@ -53,7 +53,7 @@ public class TurtleEquipCommand implements ITurtleCommand // Determine the upgrade to replace ItemStack oldUpgradeStack; - ITurtleUpgrade oldUpgrade = turtle.getUpgrade( m_side ); + ITurtleUpgrade oldUpgrade = turtle.getUpgrade( side ); if( oldUpgrade != null ) { ItemStack craftingItem = oldUpgrade.getCraftingItem(); @@ -87,7 +87,7 @@ public class TurtleEquipCommand implements ITurtleCommand WorldUtil.dropItemStack( remainder, turtle.getWorld(), position, turtle.getDirection() ); } } - turtle.setUpgrade( m_side, newUpgrade ); + turtle.setUpgrade( side, newUpgrade ); // Animate if( newUpgrade != null || oldUpgrade != null ) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java index 4f4c37585..d90fe2cd4 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -28,11 +28,11 @@ import java.util.List; public class TurtleMoveCommand implements ITurtleCommand { - private final MoveDirection m_direction; + private final MoveDirection direction; public TurtleMoveCommand( MoveDirection direction ) { - m_direction = direction; + this.direction = direction; } @Nonnull @@ -40,7 +40,7 @@ public class TurtleMoveCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Get world direction from direction - Direction direction = m_direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); // Check if we can move World oldWorld = turtle.getWorld(); @@ -72,7 +72,7 @@ public class TurtleMoveCommand implements ITurtleCommand if( !oldWorld.isUnobstructed( null, collision ) ) { - if( !ComputerCraft.turtlesCanPush || m_direction == MoveDirection.UP || m_direction == MoveDirection.DOWN ) + if( !ComputerCraft.turtlesCanPush || this.direction == MoveDirection.UP || this.direction == MoveDirection.DOWN ) { return TurtleCommandResult.failure( "Movement obstructed" ); } @@ -112,7 +112,7 @@ public class TurtleMoveCommand implements ITurtleCommand turtle.consumeFuel( 1 ); // Animate - switch( m_direction ) + switch( this.direction ) { case FORWARD: default: diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index cbdc4991f..f669b1a0f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -42,13 +42,13 @@ import java.util.List; public class TurtlePlaceCommand implements ITurtleCommand { - private final InteractDirection m_direction; - private final Object[] m_extraArguments; + private final InteractDirection direction; + private final Object[] extraArguments; public TurtlePlaceCommand( InteractDirection direction, Object[] arguments ) { - m_direction = direction; - m_extraArguments = arguments; + this.direction = direction; + extraArguments = arguments; } @Nonnull @@ -63,7 +63,7 @@ public class TurtlePlaceCommand implements ITurtleCommand } // Remember old block - Direction direction = m_direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); BlockPos coordinates = turtle.getPosition().relative( direction ); // Create a fake player, and orient it appropriately @@ -78,7 +78,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // Do the deploying String[] errorMessage = new String[1]; - ItemStack remainder = deploy( stack, turtle, turtlePlayer, direction, m_extraArguments, errorMessage ); + ItemStack remainder = deploy( stack, turtle, turtlePlayer, direction, extraArguments, errorMessage ); if( remainder != stack ) { // Put the remaining items back diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java index 5da920cf8..a7a167048 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -95,11 +95,11 @@ public final class TurtlePlayer extends FakePlayer if( !(access instanceof TurtleBrain) ) return create( access ); TurtleBrain brain = (TurtleBrain) access; - TurtlePlayer player = brain.m_cachedPlayer; + TurtlePlayer player = brain.cachedPlayer; if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getCommandSenderWorld() != access.getWorld() ) { - player = brain.m_cachedPlayer = create( brain ); + player = brain.cachedPlayer = create( brain ); } else { diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java index 776394792..1dc5bb475 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -26,13 +26,13 @@ import java.util.List; public class TurtleSuckCommand implements ITurtleCommand { - private final InteractDirection m_direction; - private final int m_quantity; + private final InteractDirection direction; + private final int quantity; public TurtleSuckCommand( InteractDirection direction, int quantity ) { - m_direction = direction; - m_quantity = quantity; + this.direction = direction; + this.quantity = quantity; } @Nonnull @@ -40,14 +40,14 @@ public class TurtleSuckCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Sucking nothing is easy - if( m_quantity == 0 ) + if( quantity == 0 ) { turtle.playAnimation( TurtleAnimation.WAIT ); return TurtleCommandResult.success(); } // Get world direction from direction - Direction direction = m_direction.toWorldDir( turtle ); + Direction direction = this.direction.toWorldDir( turtle ); // Get inventory for thing in front World world = turtle.getWorld(); @@ -68,7 +68,7 @@ public class TurtleSuckCommand implements ITurtleCommand if( inventory != null ) { // Take from inventory of thing in front - ItemStack stack = InventoryUtil.takeItems( m_quantity, inventory ); + ItemStack stack = InventoryUtil.takeItems( quantity, inventory ); if( stack.isEmpty() ) return TurtleCommandResult.failure( "No items to take" ); // Try to place into the turtle @@ -107,9 +107,9 @@ public class TurtleSuckCommand implements ITurtleCommand ItemStack storeStack; ItemStack leaveStack; - if( stack.getCount() > m_quantity ) + if( stack.getCount() > quantity ) { - storeStack = stack.split( m_quantity ); + storeStack = stack.split( quantity ); leaveStack = stack; } else diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java index 82b2417be..d024e6e91 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTransferToCommand.java @@ -16,13 +16,13 @@ import javax.annotation.Nonnull; public class TurtleTransferToCommand implements ITurtleCommand { - private final int m_slot; - private final int m_quantity; + private final int slot; + private final int quantity; public TurtleTransferToCommand( int slot, int limit ) { - m_slot = slot; - m_quantity = limit; + this.slot = slot; + quantity = limit; } @Nonnull @@ -30,7 +30,7 @@ public class TurtleTransferToCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { // Take stack - ItemStack stack = InventoryUtil.takeItems( m_quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); + ItemStack stack = InventoryUtil.takeItems( quantity, turtle.getItemHandler(), turtle.getSelectedSlot(), 1, turtle.getSelectedSlot() ); if( stack.isEmpty() ) { turtle.playAnimation( TurtleAnimation.WAIT ); @@ -38,7 +38,7 @@ public class TurtleTransferToCommand implements ITurtleCommand } // Store stack - ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), m_slot, 1, m_slot ); + ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), slot, 1, slot ); if( !remainder.isEmpty() ) { // Put the remainder back diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java index 63a3375b2..4011a0f7c 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -17,11 +17,11 @@ import javax.annotation.Nonnull; public class TurtleTurnCommand implements ITurtleCommand { - private final TurnDirection m_direction; + private final TurnDirection direction; public TurtleTurnCommand( TurnDirection direction ) { - m_direction = direction; + this.direction = direction; } @Nonnull @@ -34,7 +34,7 @@ public class TurtleTurnCommand implements ITurtleCommand return TurtleCommandResult.failure( event.getFailureMessage() ); } - switch( m_direction ) + switch( direction ) { case LEFT: { diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java index 6ef00ad4b..9c82040b2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleCraftingTable.java @@ -21,11 +21,8 @@ import javax.annotation.Nonnull; public class TurtleCraftingTable extends AbstractTurtleUpgrade { - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_leftModel; - - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_rightModel; + private static final ModelResourceLocation leftModel = new ModelResourceLocation( "computercraft:turtle_crafting_table_left", "inventory" ); + private static final ModelResourceLocation rightModel = new ModelResourceLocation( "computercraft:turtle_crafting_table_right", "inventory" ); public TurtleCraftingTable( ResourceLocation id ) { @@ -38,22 +35,11 @@ public class TurtleCraftingTable extends AbstractTurtleUpgrade return new CraftingTablePeripheral( turtle ); } - @OnlyIn( Dist.CLIENT ) - private void loadModelLocations() - { - if( m_leftModel == null ) - { - m_leftModel = new ModelResourceLocation( "computercraft:turtle_crafting_table_left", "inventory" ); - m_rightModel = new ModelResourceLocation( "computercraft:turtle_crafting_table_right", "inventory" ); - } - } - @Nonnull @Override @OnlyIn( Dist.CLIENT ) public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { - loadModelLocations(); - return TransformedModel.of( side == TurtleSide.LEFT ? m_leftModel : m_rightModel ); + return TransformedModel.of( side == TurtleSide.LEFT ? leftModel : rightModel ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java index bba1393c9..bb361c260 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -27,9 +27,9 @@ import java.util.List; public class TurtleInventoryCrafting extends CraftingInventory { - private ITurtleAccess m_turtle; - private int m_xStart; - private int m_yStart; + private final ITurtleAccess turtle; + private int xStart = 0; + private int yStart = 0; @SuppressWarnings( "ConstantConditions" ) public TurtleInventoryCrafting( ITurtleAccess turtle ) @@ -37,26 +37,24 @@ public class TurtleInventoryCrafting extends CraftingInventory // Passing null in here is evil, but we don't have a container present. We override most methods in order to // avoid throwing any NPEs. super( null, 0, 0 ); - m_turtle = turtle; - m_xStart = 0; - m_yStart = 0; + this.turtle = turtle; } @Nullable private IRecipe tryCrafting( int xStart, int yStart ) { - m_xStart = xStart; - m_yStart = yStart; + this.xStart = xStart; + this.yStart = yStart; // Check the non-relevant parts of the inventory are empty for( int x = 0; x < TileTurtle.INVENTORY_WIDTH; x++ ) { for( int y = 0; y < TileTurtle.INVENTORY_HEIGHT; y++ ) { - if( x < m_xStart || x >= m_xStart + 3 || - y < m_yStart || y >= m_yStart + 3 ) + if( x < this.xStart || x >= this.xStart + 3 || + y < this.yStart || y >= this.yStart + 3 ) { - if( !m_turtle.getInventory().getItem( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() ) + if( !turtle.getInventory().getItem( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() ) { return null; } @@ -65,7 +63,7 @@ public class TurtleInventoryCrafting extends CraftingInventory } // Check the actual crafting - return m_turtle.getWorld().getRecipeManager().getRecipeFor( IRecipeType.CRAFTING, this, m_turtle.getWorld() ).orElse( null ); + return turtle.getWorld().getRecipeManager().getRecipeFor( IRecipeType.CRAFTING, this, turtle.getWorld() ).orElse( null ); } @Nullable @@ -83,7 +81,7 @@ public class TurtleInventoryCrafting extends CraftingInventory // Special case: craft(0) just returns an empty list if crafting was possible if( maxCount == 0 ) return Collections.emptyList(); - TurtlePlayer player = TurtlePlayer.get( m_turtle ); + TurtlePlayer player = TurtlePlayer.get( turtle ); ArrayList results = new ArrayList<>(); for( int i = 0; i < maxCount && recipe.matches( this, world ); i++ ) @@ -147,8 +145,8 @@ public class TurtleInventoryCrafting extends CraftingInventory private int modifyIndex( int index ) { - int x = m_xStart + index % getWidth(); - int y = m_yStart + index / getHeight(); + int x = xStart + index % getWidth(); + int y = yStart + index / getHeight(); return x >= 0 && x < TileTurtle.INVENTORY_WIDTH && y >= 0 && y < TileTurtle.INVENTORY_HEIGHT ? x + y * TileTurtle.INVENTORY_WIDTH : -1; @@ -167,7 +165,7 @@ public class TurtleInventoryCrafting extends CraftingInventory public ItemStack getItem( int i ) { i = modifyIndex( i ); - return m_turtle.getInventory().getItem( i ); + return turtle.getInventory().getItem( i ); } @Nonnull @@ -175,7 +173,7 @@ public class TurtleInventoryCrafting extends CraftingInventory public ItemStack removeItemNoUpdate( int i ) { i = modifyIndex( i ); - return m_turtle.getInventory().removeItemNoUpdate( i ); + return turtle.getInventory().removeItemNoUpdate( i ); } @Nonnull @@ -183,26 +181,26 @@ public class TurtleInventoryCrafting extends CraftingInventory public ItemStack removeItem( int i, int size ) { i = modifyIndex( i ); - return m_turtle.getInventory().removeItem( i, size ); + return turtle.getInventory().removeItem( i, size ); } @Override public void setItem( int i, @Nonnull ItemStack stack ) { i = modifyIndex( i ); - m_turtle.getInventory().setItem( i, stack ); + turtle.getInventory().setItem( i, stack ); } @Override public int getMaxStackSize() { - return m_turtle.getInventory().getMaxStackSize(); + return turtle.getInventory().getMaxStackSize(); } @Override public void setChanged() { - m_turtle.getInventory().setChanged(); + turtle.getInventory().setChanged(); } @Override @@ -215,7 +213,7 @@ public class TurtleInventoryCrafting extends CraftingInventory public boolean canPlaceItem( int i, @Nonnull ItemStack stack ) { i = modifyIndex( i ); - return m_turtle.getInventory().canPlaceItem( i, stack ); + return turtle.getInventory().canPlaceItem( i, stack ); } @Override @@ -224,7 +222,7 @@ public class TurtleInventoryCrafting extends CraftingInventory for( int i = 0; i < getContainerSize(); i++ ) { int j = modifyIndex( i ); - m_turtle.getInventory().setItem( j, ItemStack.EMPTY ); + turtle.getInventory().setItem( j, ItemStack.EMPTY ); } } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java index 4fe11b97b..5ff686042 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -63,17 +63,10 @@ public class TurtleModem extends AbstractTurtleUpgrade private final boolean advanced; - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_leftOffModel; - - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_rightOffModel; - - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_leftOnModel; - - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_rightOnModel; + private final ModelResourceLocation leftOffModel; + private final ModelResourceLocation rightOffModel; + private final ModelResourceLocation leftOnModel; + private final ModelResourceLocation rightOnModel; public TurtleModem( boolean advanced, ResourceLocation id ) { @@ -84,6 +77,21 @@ public class TurtleModem extends AbstractTurtleUpgrade : Registry.ModBlocks.WIRELESS_MODEM_NORMAL ); this.advanced = advanced; + + if( advanced ) + { + leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_left", "inventory" ); + rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_right", "inventory" ); + leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_left", "inventory" ); + rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_right", "inventory" ); + } + else + { + leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_left", "inventory" ); + rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_right", "inventory" ); + leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_left", "inventory" ); + rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_right", "inventory" ); + } } @Override @@ -99,35 +107,11 @@ public class TurtleModem extends AbstractTurtleUpgrade return TurtleCommandResult.failure(); } - @OnlyIn( Dist.CLIENT ) - private void loadModelLocations() - { - if( m_leftOffModel == null ) - { - if( advanced ) - { - m_leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_left", "inventory" ); - m_rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_off_right", "inventory" ); - m_leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_left", "inventory" ); - m_rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_advanced_on_right", "inventory" ); - } - else - { - m_leftOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_left", "inventory" ); - m_rightOffModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_off_right", "inventory" ); - m_leftOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_left", "inventory" ); - m_rightOnModel = new ModelResourceLocation( "computercraft:turtle_modem_normal_on_right", "inventory" ); - } - } - } - @Nonnull @Override @OnlyIn( Dist.CLIENT ) public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { - loadModelLocations(); - boolean active = false; if( turtle != null ) { @@ -136,8 +120,8 @@ public class TurtleModem extends AbstractTurtleUpgrade } return side == TurtleSide.LEFT - ? TransformedModel.of( active ? m_leftOnModel : m_leftOffModel ) - : TransformedModel.of( active ? m_rightOnModel : m_rightOffModel ); + ? TransformedModel.of( active ? leftOnModel : leftOffModel ) + : TransformedModel.of( active ? rightOnModel : rightOffModel ); } @Override diff --git a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java index d11d5b4e4..d4f682766 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -25,6 +25,9 @@ import javax.annotation.Nonnull; public class TurtleSpeaker extends AbstractTurtleUpgrade { + private static final ModelResourceLocation leftModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" ); + private static final ModelResourceLocation rightModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" ); + private static class Peripheral extends SpeakerPeripheral { ITurtleAccess turtle; @@ -54,12 +57,6 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade } } - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_leftModel; - - @OnlyIn( Dist.CLIENT ) - private ModelResourceLocation m_rightModel; - public TurtleSpeaker( ResourceLocation id ) { super( id, TurtleUpgradeType.PERIPHERAL, Registry.ModBlocks.SPEAKER ); @@ -71,33 +68,18 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade return new TurtleSpeaker.Peripheral( turtle ); } - @OnlyIn( Dist.CLIENT ) - private void loadModelLocations() - { - if( m_leftModel == null ) - { - m_leftModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" ); - m_rightModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" ); - } - } - @Nonnull @Override @OnlyIn( Dist.CLIENT ) public TransformedModel getModel( ITurtleAccess turtle, @Nonnull TurtleSide side ) { - loadModelLocations(); - return TransformedModel.of( side == TurtleSide.LEFT ? m_leftModel : m_rightModel ); + return TransformedModel.of( side == TurtleSide.LEFT ? leftModel : rightModel ); } @Override public void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide turtleSide ) { IPeripheral turtlePeripheral = turtle.getPeripheral( turtleSide ); - if( turtlePeripheral instanceof Peripheral ) - { - Peripheral peripheral = (Peripheral) turtlePeripheral; - peripheral.update(); - } + if( turtlePeripheral instanceof Peripheral ) ((Peripheral) turtlePeripheral).update(); } } diff --git a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java index d446d5782..3694cf791 100644 --- a/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java +++ b/src/main/java/dan200/computercraft/shared/util/CreativeTabMain.java @@ -9,8 +9,6 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.Registry; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; import javax.annotation.Nonnull; @@ -23,7 +21,6 @@ public class CreativeTabMain extends ItemGroup @Nonnull @Override - @OnlyIn( Dist.CLIENT ) public ItemStack makeIcon() { return new ItemStack( Registry.ModBlocks.COMPUTER_NORMAL.get() ); From c83eeb16a853f73f3069f9a027e79522e8720209 Mon Sep 17 00:00:00 2001 From: Wojbie Date: Fri, 15 Jan 2021 20:30:21 +0100 Subject: [PATCH 432/711] id.lua now handles more disk types (#677) Co-authored-by: Lupus590 --- .../computercraft/lua/rom/programs/id.lua | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/id.lua b/src/main/resources/data/computercraft/lua/rom/programs/id.lua index 964503e24..79aecf9e6 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/id.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/id.lua @@ -13,16 +13,30 @@ if sDrive == nil then end else - local bData = disk.hasData(sDrive) - if not bData then + if disk.hasAudio(sDrive) then + local title = disk.getAudioTitle(sDrive) + if title then + print("Has audio track \"" .. title .. "\"") + else + print("Has untitled audio") + end + return + end + + if not disk.hasData(sDrive) then print("No disk in drive " .. sDrive) return end - print("The disk is #" .. disk.getID(sDrive)) + local id = disk.getID(sDrive) + if id then + print("The disk is #" .. id) + else + print("Non-disk data source") + end local label = disk.getLabel(sDrive) if label then - print("The disk is labelled \"" .. label .. "\"") + print("Labelled \"" .. label .. "\"") end end From 52b112fae6cc50510cae2d13c5ba7f3b416cdecb Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 Jan 2021 19:39:12 +0000 Subject: [PATCH 433/711] Bump several action versions --- .github/workflows/main-ci.yml | 4 ++-- .github/workflows/make-doc.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml index 66f06fba0..64b5a89c0 100644 --- a/.github/workflows/main-ci.yml +++ b/.github/workflows/main-ci.yml @@ -16,7 +16,7 @@ jobs: java-version: 8 - name: Cache gradle dependencies - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }} @@ -30,7 +30,7 @@ jobs: ./gradlew build - name: Upload Jar - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 with: name: CC-Tweaked path: build/libs diff --git a/.github/workflows/make-doc.yml b/.github/workflows/make-doc.yml index ab7d60b1a..c3eaba350 100644 --- a/.github/workflows/make-doc.yml +++ b/.github/workflows/make-doc.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Set up Java 8 uses: actions/setup-java@v1 @@ -19,7 +19,7 @@ jobs: java-version: 8 - name: Cache gradle dependencies - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }} From 138132581365396a3d34b6cdef48bef84748086d Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 Jan 2021 23:16:58 +0000 Subject: [PATCH 434/711] Expand CONTRIBUTING a little Explain our overly-complicated build system. Because of course we need to. --- CONTRIBUTING.md | 91 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fdd97675e..802395905 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,10 @@ If you've any other questions, [just ask the community][community] or [open an i If you have a bug, suggestion, or other feedback, the best thing to do is [file an issue][new-issue]. When doing so, do use the issue templates - they provide a useful hint on what information to provide. +## Translations +Translations are managed through [Weblate], an online interface for managing language strings. This is synced +automatically with GitHub, so please don't submit PRs adding/changing translations! + ## Developing In order to develop CC: Tweaked, you'll need to download the source code and then run it. This is a pretty simple process. When building on Windows, Use `gradlew.bat` instead of `./gradlew`. @@ -20,6 +24,11 @@ If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` an These commands may take a few minutes to run the first time, as the environment is set up, but should be much faster afterwards. +The following sections describe the more niche sections of CC: Tweaked's build system. Some bits of these are +quite-complex, and (dare I say) over-engineered, so you may wish to ignore them. Well tested/documented PRs are always +preferred (and I'd definitely recommend setting up the tooling if you're doing serious development work), but for +small changes it can be a lot. + ### Code linters CC: Tweaked uses a couple of "linters" on its source code, to enforce a consistent style across the project. While these are run whenever you submit a PR, it's often useful to run this before committing. @@ -27,15 +36,83 @@ are run whenever you submit a PR, it's often useful to run this before committin - **[Checkstyle]:** Checks Java code to ensure it is consistently formatted. This can be run with `./gradlew build` or `./gradle check`. - **[illuaminate]:** Checks Lua code for semantic and styleistic issues. See [the usage section][illuaminate-usage] for - how to download and run it. + how to download and run it. You may need to generate the Java documentation stubs (see "Documentation" below) for all + lints to pass. -## Translations -Translations are managed through [Weblate], an online interface for managing language strings. This is synced -automatically with GitHub, so please don't submit PRs adding/changing translations! +### Documentation +When writing documentation for [CC: Tweaked's documentation website][docs], it may be useful to build the documentation +and preview it yourself before submitting a PR. + +Building all documentation is, sadly, a multi-stage process (though this is largely hidden by Gradle). First we need to +convert Java doc-comments into Lua ones, we also generate some Javascript to embed. All of this is then finally fed into +illuaminate, which spits out our HTML. + +#### Setting up the tooling +For various reasons, getting the environment set up to build documentation can be pretty complex. I'd quite like to +automate this via Docker and/or nix in the future, but this needs to be done manually for now. + +First, you will need JDK 9+ (in addition to JDK 8 which is required to build Minecraft itself). Sadly our version of +Gradle doesn't support multiple toolchains, and so you need to install this yourself. + +Gradle needs to be told about this JDK via the `JAVA_HOME_11_X64` environment variable or adding `java11Home` to +`~/.gradle/gradle.properties`. On my system this looks like: + +```properties +java11Home=/usr/lib/jvm/java-11-openjdk/ +``` + +If you just want to build the documentation stubs for linting, this is enough. However, if you want to build the full +website, you will also need to install a few Node packages by running `npm ci`. + +#### Building documentation +Gradle should be your entrypoint to building most documentation. There's two tasks which are of interest: + + - `./gradlew luaJavadoc` - Generate documentation stubs for Java methods. + - `./gradlew docWebsite` - Generate the whole website (including Javascript pages). The resulting HTML is stored at + `./build/docs/lua/`. + +#### Writing documentation +illuaminate's documentation system is not currently documented (somewhat ironic), but is _largely_ the same as +[ldoc][ldoc]. Documentation comments are written in Markdown, + +Our markdown engine does _not_ support GitHub flavoured markdown, and so does not support all the features one might +expect (such as tables). It is very much recommended that you build and preview the docs locally first. + +### Testing +Thankfully running tests is much simpler than running the documentation generator! `./gradlew check` will run the +entire test suite (and some additional bits of verification). + +Before we get into writing tests, it's worth mentioning the various test suites that CC: Tweaked has: + - "Core" Java (`./src/test/java`): These test core bits of the mod which don't require any Minecraft interaction. + This includes the `@LuaFunction` system, file system code, etc... + + These tests are run by `./gradlew test`. + + - CraftOS (`./src/test/resources/test-rom/`): These tests are written in Lua, and ensure the Lua environment, libraries + and programs work as expected. These are (generally) written to be able to be run on emulators too, to provide some + sort of compliance test. + + These tests are run by the '"Core" Java' test suite, and so are also run with `./gradlew test`. + + - In-game (`./src/test/java/dan200/computercraft/ingame/`): These tests are run on an actual Minecraft server, using + [the same system Mojang do][mc-test]. The aim of these is to test in-game behaviour of blocks and peripherals. + + These are run by `./gradlew testInGame`. + +## CraftOS tests +CraftOS's tests are written using a test system called "mcfly", heavily inspired by [busted] (and thus RSpec). Groups of +tests go inside `describe` blocks, and a single test goes inside `it`. + +Assertions are generally written using `expect` (inspired by Hamcrest and the like). For instance, `expect(foo):eq("bar")` +asserts that your variable `foo` is equal to the expected value `"bar"`. [new-issue]: https://github.com/SquidDev-CC/CC-Tweaked/issues/new/choose "Create a new issue" [community]: README.md#Community "Get in touch with the community." [checkstyle]: https://checkstyle.org/ -[illuaminate]: https://github.com/SquidDev/illuaminate/ -[illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage -[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ +[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub" +[illuaminate-usage]: https://github.com/SquidDev/illuaminate/blob/master/README.md#usage "Installing Illuaminate" +[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ "CC: Tweaked weblate instance" +[docs]: https://tweaked.cc/ "CC: Tweaked documentation" +[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator." +[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg +[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing." From a3a968450552a54bcc185f7eb884be134c2fd8fc Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 15 Jan 2021 23:23:51 +0000 Subject: [PATCH 435/711] Widen version range to include 1.16.5 Building against 1.16.4 for now to ensure we don't break it. Hopefully we can bump this too once most people have migrated. Will push a release tomorrow - don't want to be sorting out merge conflicts at 23:30. --- src/main/resources/META-INF/mods.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index ee8b92f44..c4959e475 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -1,5 +1,5 @@ modLoader="javafml" -loaderVersion="[35,36)" +loaderVersion="[35,37)" issueTrackerURL="https://github.com/SquidDev-CC/CC-Tweaked/issues" displayURL="https://github.com/SquidDev-CC/CC-Tweaked" @@ -20,6 +20,6 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a [[dependencies.computercraft]] modId="forge" mandatory=true - versionRange="[35.1.16,36)" + versionRange="[35.1.16,37)" ordering="NONE" side="BOTH" From ee27d8f081dc2329182ddc32832af2d116fdb7c7 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 16 Jan 2021 11:18:59 +0000 Subject: [PATCH 436/711] Bump version to 1.95.2 --- gradle.properties | 2 +- .../data/computercraft/lua/rom/help/changelog.txt | 13 +++++++++++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 15 ++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/gradle.properties b/gradle.properties index f9ef4fecd..03dc1afd4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.95.1 +mod_version=1.95.2 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 80a5bfdd2..28d5d109e 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,16 @@ +# New features in CC: Tweaked 1.95.2 + +* Add `isReadOnly` to `fs.attributes` (Lupus590) +* Many more programs now support numpad enter (Wojbie) + +Several bug fixes: +* Fix some commands failing to parse on dedicated servers. +* Fix all disk recipes appearing to produce a white disk in JEI/recipe book. +* Hopefully improve edit's behaviour with AltGr on some European keyboards. +* Prevent files being usable after their mount was removed. +* Fix the `id` program crashing on non-disk items (Wojbie). +* Preserve registration order of turtle/pocket upgrades when displaying in JEI. + # New features in CC: Tweaked 1.95.1 Several bug fixes: diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index 4cc63fb78..e4fbc7a53 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,9 +1,14 @@ -New features in CC: Tweaked 1.95.1 +New features in CC: Tweaked 1.95.2 + +* Add `isReadOnly` to `fs.attributes` (Lupus590) +* Many more programs now support numpad enter (Wojbie) Several bug fixes: -* Command computers now drop items again. -* Restore crafting of disks with dyes. -* Fix CraftTweaker integrations for damageable items. -* Catch reflection errors in the generic peripheral system, resolving crashes with Botania. +* Fix some commands failing to parse on dedicated servers. +* Fix all disk recipes appearing to produce a white disk in JEI/recipe book. +* Hopefully improve edit's behaviour with AltGr on some European keyboards. +* Prevent files being usable after their mount was removed. +* Fix the `id` program crashing on non-disk items (Wojbie). +* Preserve registration order of turtle/pocket upgrades when displaying in JEI. Type "help changelog" to see the full version history. From 23bf33c45481de985524ed6b1eacb16b44168068 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 16 Jan 2021 12:40:00 +0000 Subject: [PATCH 437/711] Use mixins to construct the TestFunctionInfo class There's some funky things going on here, but thankfully they're limited to test code. --- build.gradle | 14 ++++ .../ingame/mixin/MixinTestFunctionInfo.java | 76 +++++++++++++++++++ .../computercraft/ingame/mod/TestLoader.java | 8 -- src/test/resources/cctest.mixin.json | 10 +++ 4 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 src/test/java/dan200/computercraft/ingame/mixin/MixinTestFunctionInfo.java create mode 100644 src/test/resources/cctest.mixin.json diff --git a/build.gradle b/build.gradle index c80d6f659..604ecd9f9 100644 --- a/build.gradle +++ b/build.gradle @@ -6,12 +6,17 @@ buildscript { name = "forge" url = "https://files.minecraftforge.net/maven" } + maven { + name = "mixin" + url = "https://dist.creeper.host/Sponge/maven" + } } dependencies { classpath 'com.google.code.gson:gson:2.8.1' classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.190' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' + classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' } } @@ -25,6 +30,7 @@ plugins { } apply plugin: 'net.minecraftforge.gradle' +apply plugin: 'org.spongepowered.mixin' apply plugin: 'org.ajoberstar.grgit' apply plugin: 'maven-publish' apply plugin: 'maven' @@ -79,6 +85,10 @@ minecraft { testServer { workingDirectory project.file('test-files/server') parent runs.server + properties 'mixin.env.disableRefMap': 'true' + + arg "-mixin.config=cctest.mixin.json" + arg "--nogui" mods { cctest { @@ -93,6 +103,10 @@ minecraft { accessTransformer file('src/main/resources/META-INF/accesstransformer.cfg') } +mixin { + add sourceSets.test, "cctest.refmap.json" +} + sourceSets { main.resources { srcDir 'src/generated/resources' diff --git a/src/test/java/dan200/computercraft/ingame/mixin/MixinTestFunctionInfo.java b/src/test/java/dan200/computercraft/ingame/mixin/MixinTestFunctionInfo.java new file mode 100644 index 000000000..b4fb6ccd2 --- /dev/null +++ b/src/test/java/dan200/computercraft/ingame/mixin/MixinTestFunctionInfo.java @@ -0,0 +1,76 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.ingame.mixin; + +import net.minecraft.test.TestFunctionInfo; +import net.minecraft.test.TestTrackerHolder; +import net.minecraft.util.Rotation; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.function.Consumer; + +/** + * Mixin to replace final fields and some getters with non-final versions. + * + * Due to (I assume) the magic of proguard, some getters are replaced with constant + * implementations. Thus we need to replace them with a sensible version. + */ +@Mixin( TestFunctionInfo.class ) +public class MixinTestFunctionInfo +{ + @Shadow + @Mutable + private String batchName; + + @Shadow + @Mutable + private String testName; + + @Shadow + @Mutable + private String structureName; + + @Shadow + @Mutable + private boolean required; + + @Shadow + @Mutable + private Consumer function; + + @Shadow + @Mutable + private int maxTicks; + + @Shadow + @Mutable + private long setupTicks; + + @Shadow + @Mutable + private Rotation rotation; + + @Overwrite + public int getMaxTicks() + { + return this.maxTicks; + } + + @Overwrite + public long getSetupTicks() + { + return setupTicks; + } + + @Overwrite + public boolean isRequired() + { + return required; + } +} diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java index f2eef6f8a..9c4d7fa80 100644 --- a/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java +++ b/src/test/java/dan200/computercraft/ingame/mod/TestLoader.java @@ -19,7 +19,6 @@ import org.objectweb.asm.Type; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Collection; import java.util.Set; @@ -110,13 +109,6 @@ class TestLoader private static void setFinalField( TestFunctionInfo func, String name, Object value ) throws ReflectiveOperationException { Field field = TestFunctionInfo.class.getDeclaredField( name ); - if( (field.getModifiers() & Modifier.FINAL) != 0 ) - { - Field modifiers = Field.class.getDeclaredField( "modifiers" ); - modifiers.setAccessible( true ); - modifiers.set( field, field.getModifiers() & ~Modifier.FINAL ); - } - field.setAccessible( true ); field.set( func, value ); } diff --git a/src/test/resources/cctest.mixin.json b/src/test/resources/cctest.mixin.json new file mode 100644 index 000000000..f836d2638 --- /dev/null +++ b/src/test/resources/cctest.mixin.json @@ -0,0 +1,10 @@ +{ + "required": true, + "package": "dan200.computercraft.ingame.mixin", + "compatibilityLevel": "JAVA_8", + "refmap": "cctest.refmap.json", + "mixins": [ + "MixinTestFunctionInfo" + ], + "minVersion": "0.8" +} From 444830cf2daaf40ea65ac4e36c3d5f2e30864418 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 16 Jan 2021 15:40:42 +0000 Subject: [PATCH 438/711] Remove Grgit/jgit usage in build.gradle The replacement is objectively worse. However, it supports Git worktrees, which sadly jgit does not. We really need to rewrite the build script to make it lazy so we're not executing these commands every time. --- build.gradle | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 826343e4c..90d5e776f 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,6 @@ buildscript { classpath 'com.google.code.gson:gson:2.8.1' classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.190' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' - classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' } } @@ -25,7 +24,6 @@ plugins { } apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'org.ajoberstar.grgit' apply plugin: 'maven-publish' apply plugin: 'maven' @@ -200,7 +198,6 @@ import com.google.gson.GsonBuilder import com.google.gson.JsonElement import com.hierynomus.gradle.license.tasks.LicenseCheck import com.hierynomus.gradle.license.tasks.LicenseFormat -import org.ajoberstar.grgit.Grgit import proguard.gradle.ProGuardTask task proguard(type: ProGuardTask, dependsOn: jar) { @@ -253,16 +250,15 @@ processResources { def hash = 'none' Set contributors = [] try { - def grgit = Grgit.open(dir: '.') - hash = grgit.head().id + hash = ["git", "-C", projectDir, "rev-parse", "HEAD"].execute().text.trim() def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe'] - grgit.log().each { - if (!blacklist.contains(it.author.name)) contributors.add(it.author.name) - if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name) + ["git", "-C", projectDir, "log", "--format=tformat:%an%n%cn"].execute().text.split('\n').each { + if (!blacklist.contains(it)) contributors.add(it) } - } catch(Exception ignored) { } - + } catch(Exception e) { + e.printStackTrace() + } inputs.property "commithash", hash from(sourceSets.main.resources.srcDirs) { @@ -606,18 +602,23 @@ githubRelease { token project.hasProperty('githubApiKey') ? project.githubApiKey : '' owner 'SquidDev-CC' repo 'CC-Tweaked' - try { - targetCommitish = Grgit.open(dir: '.').branch.current().name - } catch(Exception ignored) { } + targetCommitish.set(project.provider({ + try { + return ["git", "-C", projectDir, "rev-parse", "--abbrev-ref", "HEAD"].execute().text.trim() + } catch (Exception e) { + e.printStackTrace() + } + return "master" + })) tagName "v${mc_version}-${mod_version}" releaseName "[${mc_version}] ${mod_version}" - body { + body.set(project.provider({ "## " + new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt") .readLines() .takeWhile { it != 'Type "help changelog" to see the full version history.' } .join("\n").trim() - } + })) prerelease false } From 417fda3019c3b18c1eacc01404a4d2e7c460a2f9 Mon Sep 17 00:00:00 2001 From: FensieRenaud <65811543+FensieRenaud@users.noreply.github.com> Date: Mon, 18 Jan 2021 17:44:39 +0100 Subject: [PATCH 439/711] Serialise sparse arrays into JSON (#685) --- .../data/computercraft/lua/rom/apis/textutils.lua | 12 ++++++++++-- .../resources/test-rom/spec/apis/textutils_spec.lua | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 30766e8ec..1c363d6fa 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -381,6 +381,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) local sArrayResult = "[" local nObjectSize = 0 local nArraySize = 0 + local largestArrayIndex = 0 for k, v in pairs(t) do if type(k) == "string" then local sEntry @@ -395,10 +396,17 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) sObjectResult = sObjectResult .. "," .. sEntry end nObjectSize = nObjectSize + 1 + elseif type(k) == "number" and k > largestArrayIndex then --the largest index is kept to avoid losing half the array if there is any single nil in that array + largestArrayIndex = k end end - for _, v in ipairs(t) do - local sEntry = serializeJSONImpl(v, tTracking, bNBTStyle) + for k = 1, largestArrayIndex, 1 do --the array is read up to the very last valid array index, ipairs() would stop at the first nil value and we would lose any data after. + local sEntry + if t[k] == nil then --if the array is nil at index k the value is "null" as to keep the unused indexes in between used ones. + sEntry = "null" + else -- if the array index does not point to a nil we serialise it's content. + sEntry = serializeJSONImpl(t[k], tTracking, bNBTStyle) + end if nArraySize == 0 then sArrayResult = sArrayResult .. sEntry else diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index 6db7917ea..c5669981b 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -101,6 +101,12 @@ describe("The textutils library", function() expect(textutils.serializeJSON(string.char(0x81))):eq('"\\u0081"') expect(textutils.serializeJSON(string.char(0xFF))):eq('"\\u00FF"') end) + + it("serializes arrays until the last index with content", function() + expect(textutils.serializeJSON({ 5, "test", nil, nil, 7 })):eq('[5,"test",null,null,7]') + expect(textutils.serializeJSON({ 5, "test", nil, nil, textutils.json_null })):eq('[5,"test",null,null,null]') + expect(textutils.serializeJSON({ nil, nil, nil, nil, "text" })):eq('[null,null,null,null,"text"]') + end) end) describe("textutils.unserializeJSON", function() From 763bab80fa22cbc8fc9dd9632019829d8edc64d9 Mon Sep 17 00:00:00 2001 From: FensieRenaud <65811543+FensieRenaud@users.noreply.github.com> Date: Mon, 18 Jan 2021 17:44:39 +0100 Subject: [PATCH 440/711] Serialise sparse arrays into JSON (#685) --- .../data/computercraft/lua/rom/apis/textutils.lua | 12 ++++++++++-- .../resources/test-rom/spec/apis/textutils_spec.lua | 6 ++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua index 30766e8ec..1c363d6fa 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/textutils.lua @@ -381,6 +381,7 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) local sArrayResult = "[" local nObjectSize = 0 local nArraySize = 0 + local largestArrayIndex = 0 for k, v in pairs(t) do if type(k) == "string" then local sEntry @@ -395,10 +396,17 @@ local function serializeJSONImpl(t, tTracking, bNBTStyle) sObjectResult = sObjectResult .. "," .. sEntry end nObjectSize = nObjectSize + 1 + elseif type(k) == "number" and k > largestArrayIndex then --the largest index is kept to avoid losing half the array if there is any single nil in that array + largestArrayIndex = k end end - for _, v in ipairs(t) do - local sEntry = serializeJSONImpl(v, tTracking, bNBTStyle) + for k = 1, largestArrayIndex, 1 do --the array is read up to the very last valid array index, ipairs() would stop at the first nil value and we would lose any data after. + local sEntry + if t[k] == nil then --if the array is nil at index k the value is "null" as to keep the unused indexes in between used ones. + sEntry = "null" + else -- if the array index does not point to a nil we serialise it's content. + sEntry = serializeJSONImpl(t[k], tTracking, bNBTStyle) + end if nArraySize == 0 then sArrayResult = sArrayResult .. sEntry else diff --git a/src/test/resources/test-rom/spec/apis/textutils_spec.lua b/src/test/resources/test-rom/spec/apis/textutils_spec.lua index 6db7917ea..c5669981b 100644 --- a/src/test/resources/test-rom/spec/apis/textutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/textutils_spec.lua @@ -101,6 +101,12 @@ describe("The textutils library", function() expect(textutils.serializeJSON(string.char(0x81))):eq('"\\u0081"') expect(textutils.serializeJSON(string.char(0xFF))):eq('"\\u00FF"') end) + + it("serializes arrays until the last index with content", function() + expect(textutils.serializeJSON({ 5, "test", nil, nil, 7 })):eq('[5,"test",null,null,7]') + expect(textutils.serializeJSON({ 5, "test", nil, nil, textutils.json_null })):eq('[5,"test",null,null,null]') + expect(textutils.serializeJSON({ nil, nil, nil, nil, "text" })):eq('[null,null,null,null,"text"]') + end) end) describe("textutils.unserializeJSON", function() From 154474928255049fdf2143df1b37666886c4e7bb Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 18 Jan 2021 22:20:48 +0000 Subject: [PATCH 441/711] Defer sending monitor updates until tick end We send monitor updates when a player starts watching a chunk. However, the block/tile data has not been sent when this event is fired, and so the packet is entirely ignored. Instead, we now queue a "send this" task, which is then dispatched on the next tick end. I have memories of this working on 1.12, so either something changed in an update or I'm a complete idiot. Both are possible. Fixes #687 --- .../peripheral/monitor/MonitorWatcher.java | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java index 13f4a71f2..888e316c7 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/MonitorWatcher.java @@ -9,6 +9,7 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.client.MonitorClientMessage; import dan200.computercraft.shared.network.client.TerminalState; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkPos; @@ -28,6 +29,7 @@ import java.util.Queue; public final class MonitorWatcher { private static final Queue watching = new ArrayDeque<>(); + private static final Queue playerUpdates = new ArrayDeque<>(); private MonitorWatcher() { @@ -58,10 +60,8 @@ public final class MonitorWatcher ServerMonitor serverMonitor = getMonitor( monitor ); if( serverMonitor == null || monitor.enqueued ) continue; - // We use the cached terminal state if available - this is guaranteed to - TerminalState state = monitor.cached; - if( state == null ) state = monitor.cached = serverMonitor.write(); - NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getBlockPos(), state ) ); + // The chunk hasn't been sent to the client yet, so we can't send an update. Do it on tick end. + playerUpdates.add( new PlayerUpdate( event.getPlayer(), monitor ) ); } } @@ -70,6 +70,23 @@ public final class MonitorWatcher { if( event.phase != TickEvent.Phase.END ) return; + PlayerUpdate playerUpdate; + while( (playerUpdate = playerUpdates.poll()) != null ) + { + TileMonitor tile = playerUpdate.monitor; + if( tile.enqueued || tile.isRemoved() ) continue; + + ServerMonitor monitor = getMonitor( tile ); + if( monitor == null ) continue; + + // Some basic sanity checks to the player. It's possible they're no longer within range, but that's harder + // to track efficiently. + ServerPlayerEntity player = playerUpdate.player; + if( !player.isAlive() || player.getLevel() != tile.getLevel() ) continue; + + NetworkHandler.sendToPlayer( playerUpdate.player, new MonitorClientMessage( tile.getBlockPos(), getState( tile, monitor ) ) ); + } + long limit = ComputerCraft.monitorBandwidth; boolean obeyLimit = limit > 0; @@ -90,7 +107,7 @@ public final class MonitorWatcher continue; } - TerminalState state = tile.cached = monitor.write(); + TerminalState state = getState( tile, monitor ); NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), chunk ); limit -= state.size(); @@ -101,4 +118,23 @@ public final class MonitorWatcher { return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null; } + + private static TerminalState getState( TileMonitor tile, ServerMonitor monitor ) + { + TerminalState state = tile.cached; + if( state == null ) state = tile.cached = monitor.write(); + return state; + } + + private static final class PlayerUpdate + { + final ServerPlayerEntity player; + final TileMonitor monitor; + + private PlayerUpdate( ServerPlayerEntity player, TileMonitor monitor ) + { + this.player = player; + this.monitor = monitor; + } + } } From a934e422197f407d08c824ce57829dae1fc1406c Mon Sep 17 00:00:00 2001 From: JackMacWindows Date: Tue, 19 Jan 2021 04:20:52 -0500 Subject: [PATCH 442/711] Finish the rest of the event documentation (#683) --- doc/events/alarm.md | 21 ++++++++++++++++++ doc/events/computer_command.md | 18 +++++++++++++++ doc/events/disk.md | 19 ++++++++++++++++ doc/events/disk_eject.md | 19 ++++++++++++++++ doc/events/http_check.md | 14 ++++++++++++ doc/events/http_failure.md | 39 +++++++++++++++++++++++++++++++++ doc/events/http_success.md | 27 +++++++++++++++++++++++ doc/events/key.md | 6 ++--- doc/events/modem_message.md | 22 +++++++++++++++++++ doc/events/monitor_resize.md | 18 +++++++++++++++ doc/events/monitor_touch.md | 20 +++++++++++++++++ doc/events/mouse_drag.md | 2 -- doc/events/mouse_up.md | 3 --- doc/events/paste.md | 18 +++++++++++++++ doc/events/peripheral.md | 19 ++++++++++++++++ doc/events/peripheral_detach.md | 19 ++++++++++++++++ doc/events/rednet_message.md | 30 +++++++++++++++++++++++++ doc/events/redstone.md | 14 ++++++++++++ doc/events/task_complete.md | 28 +++++++++++++++++++++++ doc/events/term_resize.md | 15 +++++++++++++ doc/events/terminate.md | 25 +++++++++++++++++++++ doc/events/timer.md | 21 ++++++++++++++++++ doc/events/turtle_inventory.md | 14 ++++++++++++ doc/events/websocket_closed.md | 21 ++++++++++++++++++ doc/events/websocket_failure.md | 25 +++++++++++++++++++++ doc/events/websocket_message.md | 26 ++++++++++++++++++++++ doc/events/websocket_success.md | 28 +++++++++++++++++++++++ 27 files changed, 523 insertions(+), 8 deletions(-) create mode 100644 doc/events/alarm.md create mode 100644 doc/events/computer_command.md create mode 100644 doc/events/disk.md create mode 100644 doc/events/disk_eject.md create mode 100644 doc/events/http_check.md create mode 100644 doc/events/http_failure.md create mode 100644 doc/events/http_success.md create mode 100644 doc/events/modem_message.md create mode 100644 doc/events/monitor_resize.md create mode 100644 doc/events/monitor_touch.md create mode 100644 doc/events/paste.md create mode 100644 doc/events/peripheral.md create mode 100644 doc/events/peripheral_detach.md create mode 100644 doc/events/rednet_message.md create mode 100644 doc/events/redstone.md create mode 100644 doc/events/task_complete.md create mode 100644 doc/events/term_resize.md create mode 100644 doc/events/terminate.md create mode 100644 doc/events/timer.md create mode 100644 doc/events/turtle_inventory.md create mode 100644 doc/events/websocket_closed.md create mode 100644 doc/events/websocket_failure.md create mode 100644 doc/events/websocket_message.md create mode 100644 doc/events/websocket_success.md diff --git a/doc/events/alarm.md b/doc/events/alarm.md new file mode 100644 index 000000000..db7f04845 --- /dev/null +++ b/doc/events/alarm.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] alarm +see: os.setAlarm To start an alarm. +--- + +The @{timer} event is fired when an alarm started with @{os.setAlarm} completes. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the alarm that finished. + +## Example +Starts a timer and then prints its ID: +```lua +local alarmID = os.setAlarm(os.time() + 0.05) +local event, id +repeat + event, id = os.pullEvent("alarm") +until id == alarmID +print("Alarm with ID " .. id .. " was fired") +``` diff --git a/doc/events/computer_command.md b/doc/events/computer_command.md new file mode 100644 index 000000000..245252399 --- /dev/null +++ b/doc/events/computer_command.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] computer_command +--- + +The @{computer_command} event is fired when the `/computercraft queue` command is run for the current computer. + +## Return Values +1. @{string}: The event name. +... @{string}: The arguments passed to the command. + +## Example +Prints the contents of messages sent: +```lua +while true do + local event = {os.pullEvent("computer_command")} + print("Received message:", table.unpack(event, 2)) +end +``` diff --git a/doc/events/disk.md b/doc/events/disk.md new file mode 100644 index 000000000..2946d70c4 --- /dev/null +++ b/doc/events/disk.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] disk +see: disk_eject For the event sent when a disk is removed. +--- + +The @{disk} event is fired when a disk is inserted into an adjacent or networked disk drive. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the disk drive that had a disk inserted. + +## Example +Prints a message when a disk is inserted: +```lua +while true do + local event, side = os.pullEvent("disk") + print("Inserted a disk on side " .. side) +end +``` diff --git a/doc/events/disk_eject.md b/doc/events/disk_eject.md new file mode 100644 index 000000000..71c3ede0a --- /dev/null +++ b/doc/events/disk_eject.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] disk_eject +see: disk For the event sent when a disk is inserted. +--- + +The @{disk_eject} event is fired when a disk is removed from an adjacent or networked disk drive. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the disk drive that had a disk removed. + +## Example +Prints a message when a disk is removed: +```lua +while true do + local event, side = os.pullEvent("disk_eject") + print("Removed a disk on side " .. side) +end +``` diff --git a/doc/events/http_check.md b/doc/events/http_check.md new file mode 100644 index 000000000..9af5ea7ca --- /dev/null +++ b/doc/events/http_check.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] http_check +see: http.checkURLAsync To check a URL asynchronously. +--- + +The @{http_check} event is fired when a URL check finishes. + +This event is normally handled inside @{http.checkURL}, but it can still be seen when using @{http.checkURLAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL requested to be checked. +3. @{boolean}: Whether the check succeeded. +4. @{string|nil}: If the check failed, a reason explaining why the check failed. diff --git a/doc/events/http_failure.md b/doc/events/http_failure.md new file mode 100644 index 000000000..d7572e601 --- /dev/null +++ b/doc/events/http_failure.md @@ -0,0 +1,39 @@ +--- +module: [kind=event] http_failure +see: http.request To send an HTTP request. +--- + +The @{http_failure} event is fired when an HTTP request fails. + +This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{string}: An error describing the failure. +4. @{http.Response|nil}: A response handle if the connection succeeded, but the server's response indicated failure. + +## Example +Prints an error why the website cannot be contacted: +```lua +local myURL = "http://this.website.does.not.exist" +http.request(myURL) +local event, url, err +repeat + event, url, err = os.pullEvent("http_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +``` + +Prints the contents of a webpage that does not exist: +```lua +local myURL = "https://tweaked.cc/this/does/not/exist" +http.request(myURL) +local event, url, err, handle +repeat + event, url, err, handle = os.pullEvent("http_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +print(handle.getResponseCode()) +handle.close() +``` diff --git a/doc/events/http_success.md b/doc/events/http_success.md new file mode 100644 index 000000000..3700b9211 --- /dev/null +++ b/doc/events/http_success.md @@ -0,0 +1,27 @@ +--- +module: [kind=event] http_success +see: http.request To make an HTTP request. +--- + +The @{http_success} event is fired when an HTTP request returns successfully. + +This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{http.Response}: The handle for the response text. + +## Example +Prints the content of a website (this may fail if the request fails): +```lua +local myURL = "https://tweaked.cc/" +http.request(myURL) +local event, url, handle +repeat + event, url, handle = os.pullEvent("http_success") +until url == myURL +print("Contents of " .. url .. ":") +print(handle.readAll()) +handle.close() +``` diff --git a/doc/events/key.md b/doc/events/key.md index 2b4b5aa22..72e464197 100644 --- a/doc/events/key.md +++ b/doc/events/key.md @@ -11,9 +11,9 @@ If the button pressed represented a printable character, then the @{key} event w event. If you are consuming text input, use a @{char} event instead! ## Return values -1. [`string`]: The event name. -2. [`number`]: The numerical key value of the key pressed. -3. [`boolean`]: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}). +1. @{string}: The event name. +2. @{number}: The numerical key value of the key pressed. +3. @{boolean}: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}). ## Example Prints each key when the user presses it, and if the key is being held. diff --git a/doc/events/modem_message.md b/doc/events/modem_message.md new file mode 100644 index 000000000..ec619f3d4 --- /dev/null +++ b/doc/events/modem_message.md @@ -0,0 +1,22 @@ +--- +module: [kind=event] modem_message +--- + +The @{modem_message} event is fired when a message is received on an open channel on any modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side of the modem that received the message. +3. @{number}: The channel that the message was sent on. +4. @{number}: The reply channel set by the sender. +5. @{any}: The message as sent by the sender. +6. @{number}: The distance between the sender and the receiver, in blocks (decimal). + +## Example +Prints a message when one is sent: +```lua +while true do + local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message") + print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message))) +end +``` diff --git a/doc/events/monitor_resize.md b/doc/events/monitor_resize.md new file mode 100644 index 000000000..03de804e7 --- /dev/null +++ b/doc/events/monitor_resize.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] monitor_resize +--- + +The @{monitor_resize} event is fired when an adjacent or networked monitor's size is changed. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side or network ID of the monitor that resized. + +## Example +Prints a message when a monitor is resized: +```lua +while true do + local event, side = os.pullEvent("monitor_resize") + print("The monitor on side " .. side .. " was resized.") +end +``` diff --git a/doc/events/monitor_touch.md b/doc/events/monitor_touch.md new file mode 100644 index 000000000..0f27a9cc1 --- /dev/null +++ b/doc/events/monitor_touch.md @@ -0,0 +1,20 @@ +--- +module: [kind=event] monitor_touch +--- + +The @{monitor_touch} event is fired when an adjacent or networked Advanced Monitor is right-clicked. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side or network ID of the monitor that was touched. +3. @{number}: The X coordinate of the touch, in characters. +4. @{number}: The Y coordinate of the touch, in characters. + +## Example +Prints a message when a monitor is touched: +```lua +while true do + local event, side, x, y = os.pullEvent("monitor_touch") + print("The monitor on side " .. side .. " was touched at (" .. x .. ", " .. y .. ")") +end +``` diff --git a/doc/events/mouse_drag.md b/doc/events/mouse_drag.md index 6ccb3ee6d..15451c9f8 100644 --- a/doc/events/mouse_drag.md +++ b/doc/events/mouse_drag.md @@ -20,5 +20,3 @@ while true do print(("The mouse button %s was dragged at %d, %d"):format(button, x, y)) end ``` - - diff --git a/doc/events/mouse_up.md b/doc/events/mouse_up.md index f3b382387..886330a6d 100644 --- a/doc/events/mouse_up.md +++ b/doc/events/mouse_up.md @@ -19,6 +19,3 @@ while true do print(("The mouse button %s was released at %d, %d"):format(button, x, y)) end ``` - -[`string`]: string -[`number`]: number diff --git a/doc/events/paste.md b/doc/events/paste.md new file mode 100644 index 000000000..b4f8713c5 --- /dev/null +++ b/doc/events/paste.md @@ -0,0 +1,18 @@ +--- +module: [kind=event] paste +--- + +The @{paste} event is fired when text is pasted into the computer through Ctrl-V (or ⌘V on Mac). + +## Return values +1. @{string}: The event name. +2. @{string} The text that was pasted. + +## Example +Prints pasted text: +```lua +while true do + local event, text = os.pullEvent("paste") + print('"' .. text .. '" was pasted') +end +``` diff --git a/doc/events/peripheral.md b/doc/events/peripheral.md new file mode 100644 index 000000000..5769f3942 --- /dev/null +++ b/doc/events/peripheral.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] peripheral +see: peripheral_detach For the event fired when a peripheral is detached. +--- + +The @{peripheral} event is fired when a peripheral is attached on a side or to a modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side the peripheral was attached to. + +## Example +Prints a message when a peripheral is attached: +```lua +while true do + local event, side = os.pullEvent("peripheral") + print("A peripheral was attached on side " .. side) +end +``` diff --git a/doc/events/peripheral_detach.md b/doc/events/peripheral_detach.md new file mode 100644 index 000000000..c8a462cf0 --- /dev/null +++ b/doc/events/peripheral_detach.md @@ -0,0 +1,19 @@ +--- +module: [kind=event] peripheral_detach +see: peripheral For the event fired when a peripheral is attached. +--- + +The @{peripheral_detach} event is fired when a peripheral is detached from a side or from a modem. + +## Return Values +1. @{string}: The event name. +2. @{string}: The side the peripheral was detached from. + +## Example +Prints a message when a peripheral is detached: +```lua +while true do + local event, side = os.pullEvent("peripheral_detach") + print("A peripheral was detached on side " .. side) +end +``` diff --git a/doc/events/rednet_message.md b/doc/events/rednet_message.md new file mode 100644 index 000000000..8d0bdf697 --- /dev/null +++ b/doc/events/rednet_message.md @@ -0,0 +1,30 @@ +--- +module: [kind=event] rednet_message +see: modem_message For raw modem messages sent outside of Rednet. +see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter. +--- + +The @{rednet_message} event is fired when a message is sent over Rednet. + +This event is usually handled by @{rednet.receive}, but it can also be pulled manually. + +@{rednet_message} events are sent by @{rednet.run} in the top-level coroutine in response to @{modem_message} events. A @{rednet_message} event is always preceded by a @{modem_message} event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the sending computer. +3. @{any}: The message sent. +4. @{string|nil}: The protocol of the message, if provided. + +## Example +Prints a message when one is sent: +```lua +while true do + local event, sender, message, protocol = os.pullEvent("rednet_message") + if protocol ~= nil then + print("Received message from " .. sender .. " with protocol " .. protocol .. " and message " .. tostring(message)) + else + print("Received message from " .. sender .. " with message " .. tostring(message)) + end +end +``` diff --git a/doc/events/redstone.md b/doc/events/redstone.md new file mode 100644 index 000000000..44eda304a --- /dev/null +++ b/doc/events/redstone.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] redstone +--- + +The @{redstone} event is fired whenever any redstone inputs on the computer change. + +## Example +Prints a message when a redstone input changes: +```lua +while true do + os.pullEvent("redstone") + print("A redstone input has changed!") +end +``` diff --git a/doc/events/task_complete.md b/doc/events/task_complete.md new file mode 100644 index 000000000..eddec51d2 --- /dev/null +++ b/doc/events/task_complete.md @@ -0,0 +1,28 @@ +--- +module: [kind=event] task_complete +see: commands.execAsync To run a command which fires a task_complete event. +--- + +The @{task_complete} event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as @{commands.execAsync} return immediately so the user can wait for completion. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the task that completed. +3. @{boolean}: Whether the command succeeded. +4. @{string}: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.) +...: Any parameters returned from the command. + +## Example +Prints the results of an asynchronous command: +```lua +local taskID = commands.execAsync("say Hello") +local event +repeat + event = {os.pullEvent("task_complete")} +until event[2] == taskID +if event[3] == true then + print("Task " .. event[2] .. " succeeded:", table.unpack(event, 4)) +else + print("Task " .. event[2] .. " failed: " .. event[4]) +end +``` diff --git a/doc/events/term_resize.md b/doc/events/term_resize.md new file mode 100644 index 000000000..0eb503bad --- /dev/null +++ b/doc/events/term_resize.md @@ -0,0 +1,15 @@ +--- +module: [kind=event] term_resize +--- + +The @{term_resize} event is fired when the main terminal is resized, mainly when a new tab is opened or closed in @{multishell}. + +## Example +Prints : +```lua +while true do + os.pullEvent("term_resize") + local w, h = term.getSize() + print("The term was resized to (" .. w .. ", " .. h .. ")") +end +``` diff --git a/doc/events/terminate.md b/doc/events/terminate.md new file mode 100644 index 000000000..0760b8c3b --- /dev/null +++ b/doc/events/terminate.md @@ -0,0 +1,25 @@ +--- +module: [kind=event] terminate +--- + +The @{terminate} event is fired when Ctrl-T is held down. + +This event is normally handled by @{os.pullEvent}, and will not be returned. However, @{os.pullEventRaw} will return this event when fired. + +@{terminate} will be sent even when a filter is provided to @{os.pullEventRaw}. When using @{os.pullEventRaw} with a filter, make sure to check that the event is not @{terminate}. + +## Example +Prints a message when Ctrl-T is held: +```lua +while true do + local event = os.pullEventRaw("terminate") + if event == "terminate" then print("Terminate requested!") end +end +``` + +Exits when Ctrl-T is held: +```lua +while true do + os.pullEvent() +end +``` diff --git a/doc/events/timer.md b/doc/events/timer.md new file mode 100644 index 000000000..c359c37b4 --- /dev/null +++ b/doc/events/timer.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] timer +see: os.startTimer To start a timer. +--- + +The @{timer} event is fired when a timer started with @{os.startTimer} completes. + +## Return Values +1. @{string}: The event name. +2. @{number}: The ID of the timer that finished. + +## Example +Starts a timer and then prints its ID: +```lua +local timerID = os.startTimer(2) +local event, id +repeat + event, id = os.pullEvent("timer") +until id == timerID +print("Timer with ID " .. id .. " was fired") +``` diff --git a/doc/events/turtle_inventory.md b/doc/events/turtle_inventory.md new file mode 100644 index 000000000..bc9392b6b --- /dev/null +++ b/doc/events/turtle_inventory.md @@ -0,0 +1,14 @@ +--- +module: [kind=event] turtle_inventory +--- + +The @{turtle_inventory} event is fired when a turtle's inventory is changed. + +## Example +Prints a message when the inventory is changed: +```lua +while true do + os.pullEvent("turtle_inventory") + print("The inventory was changed.") +end +``` diff --git a/doc/events/websocket_closed.md b/doc/events/websocket_closed.md new file mode 100644 index 000000000..60a8f59c2 --- /dev/null +++ b/doc/events/websocket_closed.md @@ -0,0 +1,21 @@ +--- +module: [kind=event] websocket_closed +--- + +The @{websocket_closed} event is fired when an open WebSocket connection is closed. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the WebSocket that was closed. + +## Example +Prints a message when a WebSocket is closed (this may take a minute): +```lua +local myURL = "ws://echo.websocket.org" +local ws = http.websocket(myURL) +local event, url +repeat + event, url = os.pullEvent("websocket_closed") +until url == myURL +print("The WebSocket at " .. url .. " was closed.") +``` diff --git a/doc/events/websocket_failure.md b/doc/events/websocket_failure.md new file mode 100644 index 000000000..f53bf10af --- /dev/null +++ b/doc/events/websocket_failure.md @@ -0,0 +1,25 @@ +--- +module: [kind=event] websocket_failure +see: http.websocketAsync To send an HTTP request. +--- + +The @{websocket_failure} event is fired when a WebSocket connection request fails. + +This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site requested. +3. @{string}: An error describing the failure. + +## Example +Prints an error why the website cannot be contacted: +```lua +local myURL = "ws://this.website.does.not.exist" +http.websocketAsync(myURL) +local event, url, err +repeat + event, url, err = os.pullEvent("websocket_failure") +until url == myURL +print("The URL " .. url .. " could not be reached: " .. err) +``` diff --git a/doc/events/websocket_message.md b/doc/events/websocket_message.md new file mode 100644 index 000000000..f42dcaefe --- /dev/null +++ b/doc/events/websocket_message.md @@ -0,0 +1,26 @@ +--- +module: [kind=event] websocket_message +--- + +The @{websocket_message} event is fired when a message is received on an open WebSocket connection. + +This event is normally handled by @{http.Websocket.receive}, but it can also be pulled manually. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the WebSocket. +3. @{string}: The contents of the message. + +## Example +Prints a message sent by a WebSocket: +```lua +local myURL = "ws://echo.websocket.org" +local ws = http.websocket(myURL) +ws.send("Hello!") +local event, url, message +repeat + event, url, message = os.pullEvent("websocket_message") +until url == myURL +print("Received message from " .. url .. " with contents " .. message) +ws.close() +``` diff --git a/doc/events/websocket_success.md b/doc/events/websocket_success.md new file mode 100644 index 000000000..dc8d95dd2 --- /dev/null +++ b/doc/events/websocket_success.md @@ -0,0 +1,28 @@ +--- +module: [kind=event] websocket_success +see: http.websocketAsync To open a WebSocket asynchronously. +--- + +The @{websocket_success} event is fired when a WebSocket connection request returns successfully. + +This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}. + +## Return Values +1. @{string}: The event name. +2. @{string}: The URL of the site. +3. @{http.Websocket}: The handle for the WebSocket. + +## Example +Prints the content of a website (this may fail if the request fails): +```lua +local myURL = "ws://echo.websocket.org" +http.websocketAsync(myURL) +local event, url, handle +repeat + event, url, handle = os.pullEvent("websocket_success") +until url == myURL +print("Connected to " .. url) +handle.send("Hello!") +print(handle.receive()) +handle.close() +``` From 657ceda3af035291413efd714a199786a755f558 Mon Sep 17 00:00:00 2001 From: SquidDev Date: Tue, 19 Jan 2021 13:43:49 +0000 Subject: [PATCH 443/711] Switch back to reobfuscated name in RecordMedia Fixes #688 --- .../dan200/computercraft/shared/media/items/RecordMedia.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java index 2fc56df0b..f1c0667b8 100644 --- a/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java +++ b/src/main/java/dan200/computercraft/shared/media/items/RecordMedia.java @@ -52,7 +52,7 @@ public final class RecordMedia implements IMedia try { - return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "sound" ); + return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "field_185076_b" ); } catch( UnableToAccessFieldException | UnableToFindFieldException e ) { From eaa7359c8ce4fb0387f39bc161fe173c49579bb5 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 19 Jan 2021 20:02:45 +0000 Subject: [PATCH 444/711] Add a whole bunch of tests Coverage graph goes woosh. Hopefully. More importantly, all of these are historic regressions, so very much worth tracking. --- .../turtle/core/TurtleCompareCommand.java | 13 - .../computercraft/ingame/ComputerTest.kt | 2 +- .../computercraft/ingame/DiskDriveTest.kt | 27 + .../dan200/computercraft/ingame/TurtleTest.kt | 40 ++ .../ingame/api/TestExtensions.kt | 26 +- .../computercraft/lua/rom/autorun/cctest.lua | 2 +- .../computers/computer/1/startup.lua | 2 + .../computers/computer/3/startup.lua | 5 + .../computers/computer/4/startup.lua | 4 + .../computers/computer/5/startup.lua | 9 + .../computers/computer/6/startup.lua | 9 + .../computers/computer/7/startup.lua | 10 + .../computers/computer/8/startup.lua | 11 + .../computers/computer/9/startup.lua | 9 + src/test/server-files/computers/ids.json | 4 +- .../disk_drive_test.audio_disk.snbt | 149 ++++ .../disk_drive_test.ejects_disk.snbt | 544 +++++++++++++++ .../structures/turtle_test.gather_lava.snbt | 550 +++++++++++++++ .../structures/turtle_test.hoe_dirt.snbt | 147 ++++ .../structures/turtle_test.place_lava.snbt | 544 +++++++++++++++ .../turtle_test.place_waterlogged.snbt | 550 +++++++++++++++ .../structures/turtle_test.shears_sheep.snbt | 648 ++++++++++++++++++ 22 files changed, 3287 insertions(+), 18 deletions(-) create mode 100644 src/test/java/dan200/computercraft/ingame/DiskDriveTest.kt create mode 100644 src/test/server-files/computers/computer/3/startup.lua create mode 100644 src/test/server-files/computers/computer/4/startup.lua create mode 100644 src/test/server-files/computers/computer/5/startup.lua create mode 100644 src/test/server-files/computers/computer/6/startup.lua create mode 100644 src/test/server-files/computers/computer/7/startup.lua create mode 100644 src/test/server-files/computers/computer/8/startup.lua create mode 100644 src/test/server-files/computers/computer/9/startup.lua create mode 100644 src/test/server-files/structures/disk_drive_test.audio_disk.snbt create mode 100644 src/test/server-files/structures/disk_drive_test.ejects_disk.snbt create mode 100644 src/test/server-files/structures/turtle_test.gather_lava.snbt create mode 100644 src/test/server-files/structures/turtle_test.hoe_dirt.snbt create mode 100644 src/test/server-files/structures/turtle_test.place_lava.snbt create mode 100644 src/test/server-files/structures/turtle_test.place_waterlogged.snbt create mode 100644 src/test/server-files/structures/turtle_test.shears_sheep.snbt diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index ab5f895ef..4ab393971 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -52,19 +52,6 @@ public class TurtleCompareCommand implements ITurtleCommand Block lookAtBlock = lookAtState.getBlock(); if( !lookAtBlock.isAir( lookAtState, world, newPosition ) ) { - // Try getSilkTouchDrop first - if( !lookAtBlock.hasTileEntity( lookAtState ) ) - { - try - { - Method method = ObfuscationReflectionHelper.findMethod( Block.class, "func_180643_i", BlockState.class ); - lookAtStack = (ItemStack) method.invoke( lookAtBlock, lookAtState ); - } - catch( ReflectiveOperationException | RuntimeException ignored ) - { - } - } - // See if the block drops anything with the same ID as itself // (try 5 times to try and beat random number generators) for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ ) diff --git a/src/test/java/dan200/computercraft/ingame/ComputerTest.kt b/src/test/java/dan200/computercraft/ingame/ComputerTest.kt index 48cd70204..4cbe70dc9 100644 --- a/src/test/java/dan200/computercraft/ingame/ComputerTest.kt +++ b/src/test/java/dan200/computercraft/ingame/ComputerTest.kt @@ -10,7 +10,7 @@ class ComputerTest { /** * Ensures redstone signals do not travel through computers. * - * @see [Issue #548](https://github.com/SquidDev-CC/CC-Tweaked/issues/548) + * @see [#548](https://github.com/SquidDev-CC/CC-Tweaked/issues/548) */ @GameTest suspend fun `No through signal`(context: TestContext) { diff --git a/src/test/java/dan200/computercraft/ingame/DiskDriveTest.kt b/src/test/java/dan200/computercraft/ingame/DiskDriveTest.kt new file mode 100644 index 000000000..e05dfd4b8 --- /dev/null +++ b/src/test/java/dan200/computercraft/ingame/DiskDriveTest.kt @@ -0,0 +1,27 @@ +package dan200.computercraft.ingame + +import dan200.computercraft.ingame.api.* +import net.minecraft.entity.item.ItemEntity +import net.minecraft.item.Items +import net.minecraft.util.math.BlockPos +import org.junit.jupiter.api.Assertions.assertEquals + +class DiskDriveTest { + /** + * Ensure audio disks exist and we can play them. + * + * @see [#688](https://github.com/SquidDev-CC/CC-Tweaked/issues/688) + */ + @GameTest + suspend fun `Audio disk`(context: TestContext) = context.checkComputerOk(3) + + @GameTest + suspend fun `Ejects disk`(context: TestContext) { + val stackAt = BlockPos(2, 0, 2) + context.checkComputerOk(4) + context.waitUntil { context.getEntity(stackAt) != null } + + val stack = context.getEntityOfType(stackAt)!! + assertEquals(Items.MUSIC_DISC_13, stack.item.item, "Correct item stack") + } +} diff --git a/src/test/java/dan200/computercraft/ingame/TurtleTest.kt b/src/test/java/dan200/computercraft/ingame/TurtleTest.kt index 37102388b..9f00e29ff 100644 --- a/src/test/java/dan200/computercraft/ingame/TurtleTest.kt +++ b/src/test/java/dan200/computercraft/ingame/TurtleTest.kt @@ -7,4 +7,44 @@ import dan200.computercraft.ingame.api.checkComputerOk class TurtleTest { @GameTest(required = false) suspend fun `Unequip refreshes peripheral`(context: TestContext) = context.checkComputerOk(1) + + /** + * Checks turtles can sheer sheep (and drop items) + * + * @see [#537](https://github.com/SquidDev-CC/CC-Tweaked/issues/537) + */ + @GameTest(required = false) + suspend fun `Shears sheep`(context: TestContext) = context.checkComputerOk(5) + + /** + * Checks turtles can place lava. + * + * @see [#518](https://github.com/SquidDev-CC/CC-Tweaked/issues/518) + */ + @GameTest(required = false) + suspend fun `Place lava`(context: TestContext) = context.checkComputerOk(5) + + /** + * Checks turtles can place when waterlogged. + * + * @see [#385](https://github.com/SquidDev-CC/CC-Tweaked/issues/385) + */ + @GameTest(required = false) + suspend fun `Place waterlogged`(context: TestContext) = context.checkComputerOk(7) + + /** + * Checks turtles can place when waterlogged. + * + * @see [#297](https://github.com/SquidDev-CC/CC-Tweaked/issues/297) + */ + @GameTest(required = false) + suspend fun `Gather lava`(context: TestContext) = context.checkComputerOk(8) + + /** + * Checks turtles can place when waterlogged. + * + * @see [#258](https://github.com/SquidDev-CC/CC-Tweaked/issues/258) + */ + @GameTest(required = false) + suspend fun `Hoe dirt`(context: TestContext) = context.checkComputerOk(9) } diff --git a/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt b/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt index 963addb55..aca550400 100644 --- a/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt +++ b/src/test/java/dan200/computercraft/ingame/api/TestExtensions.kt @@ -3,6 +3,9 @@ package dan200.computercraft.ingame.api import kotlinx.coroutines.CancellationException import kotlinx.coroutines.delay import net.minecraft.block.BlockState +import net.minecraft.entity.Entity +import net.minecraft.tileentity.TileEntity +import net.minecraft.util.math.AxisAlignedBB import net.minecraft.util.math.BlockPos /** @@ -37,7 +40,7 @@ suspend fun TestContext.sleep(ticks: Int = 1) { waitUntil { tracker.level.gameTime >= target } } -private fun TestContext.offset(pos: BlockPos): BlockPos = tracker.testPos.offset(pos.x, pos.y + 2, pos.z) +fun TestContext.offset(pos: BlockPos): BlockPos = tracker.testPos.offset(pos.x, pos.y + 2, pos.z) /** * Get a block within the test structure. @@ -59,3 +62,24 @@ fun TestContext.modifyBlock(pos: BlockPos, modify: (BlockState) -> BlockState) { val offset = offset(pos) level.setBlockAndUpdate(offset, modify(level.getBlockState(offset))) } + +/** + * Get a tile within the test structure. + */ +fun TestContext.getTile(pos: BlockPos): TileEntity? = tracker.level.getBlockEntity(offset(pos)) + +/** + * Get an entity within the test structure. + */ +fun TestContext.getEntity(pos: BlockPos): Entity? { + val entities = tracker.level.getEntitiesOfClass(Entity::class.java, AxisAlignedBB(offset(pos))) + return if (entities.isEmpty()) null else entities.get(0) +} + +/** + * Get an entity within the test structure. + */ +inline fun TestContext.getEntityOfType(pos: BlockPos): T? { + val entities = tracker.level.getEntitiesOfClass(T::class.java, AxisAlignedBB(offset(pos))) + return if (entities.isEmpty()) null else entities.get(0) +} diff --git a/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua b/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua index 1b4f6d778..197748f4d 100644 --- a/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua +++ b/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua @@ -1,6 +1,6 @@ --- Extend the test API with some convenience functions. -- --- It's much easier to declare these in Lua rather than Java. +-- It's much easier to declare these in Lua rather than Java.. function test.assert(ok, ...) if ok then return ... end diff --git a/src/test/server-files/computers/computer/1/startup.lua b/src/test/server-files/computers/computer/1/startup.lua index ac2e8f8f5..bb484e104 100644 --- a/src/test/server-files/computers/computer/1/startup.lua +++ b/src/test/server-files/computers/computer/1/startup.lua @@ -1,3 +1,5 @@ +-- TurtleTest.`Unequip refreshes peripheral` + test.eq("modem", peripheral.getType("right"), "Starts with a modem") turtle.equipRight() test.eq("drive", peripheral.getType("right"), "Unequipping gives a drive") diff --git a/src/test/server-files/computers/computer/3/startup.lua b/src/test/server-files/computers/computer/3/startup.lua new file mode 100644 index 000000000..3f25520f6 --- /dev/null +++ b/src/test/server-files/computers/computer/3/startup.lua @@ -0,0 +1,5 @@ +-- DiskDriveTest.`Audio disk` + +test.eq(true, disk.hasAudio("right"), "Has audio") +test.eq("C418 - 13", disk.getAudioTitle("right"), "Audio title") +test.ok() diff --git a/src/test/server-files/computers/computer/4/startup.lua b/src/test/server-files/computers/computer/4/startup.lua new file mode 100644 index 000000000..34214d536 --- /dev/null +++ b/src/test/server-files/computers/computer/4/startup.lua @@ -0,0 +1,4 @@ +-- DiskDriveTest.`Ejects disk` + +disk.eject("right") +test.ok() diff --git a/src/test/server-files/computers/computer/5/startup.lua b/src/test/server-files/computers/computer/5/startup.lua new file mode 100644 index 000000000..8efbb30ab --- /dev/null +++ b/src/test/server-files/computers/computer/5/startup.lua @@ -0,0 +1,9 @@ +-- TurtleTest.`Shears sheep` + +turtle.placeDown() + +local item = turtle.getItemDetail(2) +if item == nil then test.fail("Got no item") end +test.eq("minecraft:white_wool", item.name) + +test.ok() diff --git a/src/test/server-files/computers/computer/6/startup.lua b/src/test/server-files/computers/computer/6/startup.lua new file mode 100644 index 000000000..584bffdce --- /dev/null +++ b/src/test/server-files/computers/computer/6/startup.lua @@ -0,0 +1,9 @@ +-- TurtleTest.`Lava place` + +test.assert(turtle.placeDown()) + +local ok, down = turtle.inspectDown() +test.assert(ok, "Has below") +test.eq("minecraft:lava", down.name, "Is lava") + +test.ok() diff --git a/src/test/server-files/computers/computer/7/startup.lua b/src/test/server-files/computers/computer/7/startup.lua new file mode 100644 index 000000000..8f135bf73 --- /dev/null +++ b/src/test/server-files/computers/computer/7/startup.lua @@ -0,0 +1,10 @@ +-- TurtleTest.`Place Waterlogged` + +test.assert(turtle.place()) + +local has_block, block = turtle.inspect() +test.eq(true, has_block, "Has block") +test.eq("minecraft:oak_fence", block.name) +test.eq(true, block.state.waterlogged) + +test.ok() diff --git a/src/test/server-files/computers/computer/8/startup.lua b/src/test/server-files/computers/computer/8/startup.lua new file mode 100644 index 000000000..a3c105c80 --- /dev/null +++ b/src/test/server-files/computers/computer/8/startup.lua @@ -0,0 +1,11 @@ +-- TurtleTest.`Gather lava` + +turtle.placeDown() + +local item = turtle.getItemDetail() +test.eq("minecraft:lava_bucket", item.name) + +local has_down, down = turtle.inspectDown() +test.eq(false, has_down, "Air below") + +test.ok() diff --git a/src/test/server-files/computers/computer/9/startup.lua b/src/test/server-files/computers/computer/9/startup.lua new file mode 100644 index 000000000..0e80cd606 --- /dev/null +++ b/src/test/server-files/computers/computer/9/startup.lua @@ -0,0 +1,9 @@ +-- Turtle.`Hoe dirt` + +test.assert(turtle.dig()) + +local has_block, block = turtle.inspect() +test.assert(has_block, "Has block") +test.eq("minecraft:farmland", block.name) + +test.ok() diff --git a/src/test/server-files/computers/ids.json b/src/test/server-files/computers/ids.json index 234976137..87dab4f96 100644 --- a/src/test/server-files/computers/ids.json +++ b/src/test/server-files/computers/ids.json @@ -1,3 +1,3 @@ { - "computer": 2 -} + "computer": 9 +} \ No newline at end of file diff --git a/src/test/server-files/structures/disk_drive_test.audio_disk.snbt b/src/test/server-files/structures/disk_drive_test.audio_disk.snbt new file mode 100644 index 000000000..f4ccc9e0c --- /dev/null +++ b/src/test/server-files/structures/disk_drive_test.audio_disk.snbt @@ -0,0 +1,149 @@ +{ + size: [3, 3, 3], + entities: [], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + nbt: { + Item: { + id: "minecraft:music_disc_13", + Count: 1b + }, + id: "computercraft:disk_drive" + }, + pos: [0, 1, 1], + state: 1 + }, + { + nbt: { + id: "computercraft:computer_advanced", + ComputerId: 3, + On: 1b + }, + pos: [1, 1, 1], + state: 2 + }, + { + pos: [0, 1, 0], + state: 3 + }, + { + pos: [1, 1, 0], + state: 3 + }, + { + pos: [2, 1, 0], + state: 3 + }, + { + pos: [0, 2, 0], + state: 3 + }, + { + pos: [1, 2, 0], + state: 3 + }, + { + pos: [2, 2, 0], + state: 3 + }, + { + pos: [2, 1, 1], + state: 3 + }, + { + pos: [0, 2, 1], + state: 3 + }, + { + pos: [1, 2, 1], + state: 3 + }, + { + pos: [2, 2, 1], + state: 3 + }, + { + pos: [0, 1, 2], + state: 3 + }, + { + pos: [1, 1, 2], + state: 3 + }, + { + pos: [2, 1, 2], + state: 3 + }, + { + pos: [0, 2, 2], + state: 3 + }, + { + pos: [1, 2, 2], + state: 3 + }, + { + pos: [2, 2, 2], + state: 3 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Properties: { + facing: "north", + state: "full" + }, + Name: "computercraft:disk_drive" + }, + { + Properties: { + facing: "north", + state: "blinking" + }, + Name: "computercraft:computer_advanced" + }, + { + Name: "minecraft:air" + } + ], + DataVersion: 2230 +} diff --git a/src/test/server-files/structures/disk_drive_test.ejects_disk.snbt b/src/test/server-files/structures/disk_drive_test.ejects_disk.snbt new file mode 100644 index 000000000..27906efe0 --- /dev/null +++ b/src/test/server-files/structures/disk_drive_test.ejects_disk.snbt @@ -0,0 +1,544 @@ +{ + size: [5, 5, 5], + entities: [], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [3, 0, 0], + state: 0 + }, + { + pos: [4, 0, 0], + state: 0 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [3, 0, 1], + state: 0 + }, + { + pos: [4, 0, 1], + state: 0 + }, + { + pos: [1, 1, 1], + state: 1 + }, + { + pos: [1, 2, 1], + state: 1 + }, + { + pos: [2, 2, 1], + state: 1 + }, + { + pos: [3, 2, 1], + state: 1 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + pos: [3, 0, 2], + state: 0 + }, + { + pos: [4, 0, 2], + state: 0 + }, + { + pos: [1, 1, 2], + state: 1 + }, + { + pos: [3, 1, 2], + state: 1 + }, + { + pos: [1, 2, 2], + state: 1 + }, + { + pos: [3, 2, 2], + state: 1 + }, + { + pos: [0, 0, 3], + state: 0 + }, + { + pos: [1, 0, 3], + state: 0 + }, + { + pos: [2, 0, 3], + state: 0 + }, + { + pos: [3, 0, 3], + state: 0 + }, + { + pos: [4, 0, 3], + state: 0 + }, + { + pos: [1, 1, 3], + state: 1 + }, + { + pos: [2, 1, 3], + state: 1 + }, + { + pos: [3, 1, 3], + state: 1 + }, + { + pos: [1, 2, 3], + state: 1 + }, + { + pos: [2, 2, 3], + state: 1 + }, + { + pos: [3, 2, 3], + state: 1 + }, + { + pos: [0, 0, 4], + state: 0 + }, + { + pos: [1, 0, 4], + state: 0 + }, + { + pos: [2, 0, 4], + state: 0 + }, + { + pos: [3, 0, 4], + state: 0 + }, + { + pos: [4, 0, 4], + state: 0 + }, + { + nbt: { + Item: { + id: "minecraft:music_disc_13", + Count: 1b + }, + id: "computercraft:disk_drive" + }, + pos: [2, 1, 1], + state: 2 + }, + { + nbt: { + id: "computercraft:computer_advanced", + ComputerId: 4, + On: 1b + }, + pos: [3, 1, 1], + state: 3 + }, + { + pos: [0, 1, 0], + state: 4 + }, + { + pos: [1, 1, 0], + state: 4 + }, + { + pos: [2, 1, 0], + state: 4 + }, + { + pos: [3, 1, 0], + state: 4 + }, + { + pos: [4, 1, 0], + state: 4 + }, + { + pos: [0, 2, 0], + state: 4 + }, + { + pos: [1, 2, 0], + state: 4 + }, + { + pos: [2, 2, 0], + state: 4 + }, + { + pos: [3, 2, 0], + state: 4 + }, + { + pos: [4, 2, 0], + state: 4 + }, + { + pos: [0, 3, 0], + state: 4 + }, + { + pos: [1, 3, 0], + state: 4 + }, + { + pos: [2, 3, 0], + state: 4 + }, + { + pos: [3, 3, 0], + state: 4 + }, + { + pos: [4, 3, 0], + state: 4 + }, + { + pos: [0, 4, 0], + state: 4 + }, + { + pos: [1, 4, 0], + state: 4 + }, + { + pos: [2, 4, 0], + state: 4 + }, + { + pos: [3, 4, 0], + state: 4 + }, + { + pos: [4, 4, 0], + state: 4 + }, + { + pos: [0, 1, 1], + state: 4 + }, + { + pos: [4, 1, 1], + state: 4 + }, + { + pos: [0, 2, 1], + state: 4 + }, + { + pos: [4, 2, 1], + state: 4 + }, + { + pos: [0, 3, 1], + state: 4 + }, + { + pos: [1, 3, 1], + state: 4 + }, + { + pos: [2, 3, 1], + state: 4 + }, + { + pos: [3, 3, 1], + state: 4 + }, + { + pos: [4, 3, 1], + state: 4 + }, + { + pos: [0, 4, 1], + state: 4 + }, + { + pos: [1, 4, 1], + state: 4 + }, + { + pos: [2, 4, 1], + state: 4 + }, + { + pos: [3, 4, 1], + state: 4 + }, + { + pos: [4, 4, 1], + state: 4 + }, + { + pos: [0, 1, 2], + state: 4 + }, + { + pos: [2, 1, 2], + state: 4 + }, + { + pos: [4, 1, 2], + state: 4 + }, + { + pos: [0, 2, 2], + state: 4 + }, + { + pos: [2, 2, 2], + state: 4 + }, + { + pos: [4, 2, 2], + state: 4 + }, + { + pos: [0, 3, 2], + state: 4 + }, + { + pos: [1, 3, 2], + state: 4 + }, + { + pos: [2, 3, 2], + state: 4 + }, + { + pos: [3, 3, 2], + state: 4 + }, + { + pos: [4, 3, 2], + state: 4 + }, + { + pos: [0, 4, 2], + state: 4 + }, + { + pos: [1, 4, 2], + state: 4 + }, + { + pos: [2, 4, 2], + state: 4 + }, + { + pos: [3, 4, 2], + state: 4 + }, + { + pos: [4, 4, 2], + state: 4 + }, + { + pos: [0, 1, 3], + state: 4 + }, + { + pos: [4, 1, 3], + state: 4 + }, + { + pos: [0, 2, 3], + state: 4 + }, + { + pos: [4, 2, 3], + state: 4 + }, + { + pos: [0, 3, 3], + state: 4 + }, + { + pos: [1, 3, 3], + state: 4 + }, + { + pos: [2, 3, 3], + state: 4 + }, + { + pos: [3, 3, 3], + state: 4 + }, + { + pos: [4, 3, 3], + state: 4 + }, + { + pos: [0, 4, 3], + state: 4 + }, + { + pos: [1, 4, 3], + state: 4 + }, + { + pos: [2, 4, 3], + state: 4 + }, + { + pos: [3, 4, 3], + state: 4 + }, + { + pos: [4, 4, 3], + state: 4 + }, + { + pos: [0, 1, 4], + state: 4 + }, + { + pos: [1, 1, 4], + state: 4 + }, + { + pos: [2, 1, 4], + state: 4 + }, + { + pos: [3, 1, 4], + state: 4 + }, + { + pos: [4, 1, 4], + state: 4 + }, + { + pos: [0, 2, 4], + state: 4 + }, + { + pos: [1, 2, 4], + state: 4 + }, + { + pos: [2, 2, 4], + state: 4 + }, + { + pos: [3, 2, 4], + state: 4 + }, + { + pos: [4, 2, 4], + state: 4 + }, + { + pos: [0, 3, 4], + state: 4 + }, + { + pos: [1, 3, 4], + state: 4 + }, + { + pos: [2, 3, 4], + state: 4 + }, + { + pos: [3, 3, 4], + state: 4 + }, + { + pos: [4, 3, 4], + state: 4 + }, + { + pos: [0, 4, 4], + state: 4 + }, + { + pos: [1, 4, 4], + state: 4 + }, + { + pos: [2, 4, 4], + state: 4 + }, + { + pos: [3, 4, 4], + state: 4 + }, + { + pos: [4, 4, 4], + state: 4 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Name: "minecraft:white_stained_glass" + }, + { + Properties: { + facing: "south", + state: "full" + }, + Name: "computercraft:disk_drive" + }, + { + Properties: { + facing: "north", + state: "blinking" + }, + Name: "computercraft:computer_advanced" + }, + { + Name: "minecraft:air" + } + ], + DataVersion: 2230 +} diff --git a/src/test/server-files/structures/turtle_test.gather_lava.snbt b/src/test/server-files/structures/turtle_test.gather_lava.snbt new file mode 100644 index 000000000..1b51705ec --- /dev/null +++ b/src/test/server-files/structures/turtle_test.gather_lava.snbt @@ -0,0 +1,550 @@ +{ + size: [5, 5, 5], + entities: [], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [3, 0, 0], + state: 0 + }, + { + pos: [4, 0, 0], + state: 0 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [3, 0, 1], + state: 0 + }, + { + pos: [4, 0, 1], + state: 0 + }, + { + pos: [1, 1, 1], + state: 1 + }, + { + pos: [2, 1, 1], + state: 1 + }, + { + pos: [3, 1, 1], + state: 1 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + pos: [3, 0, 2], + state: 0 + }, + { + pos: [4, 0, 2], + state: 0 + }, + { + pos: [1, 1, 2], + state: 1 + }, + { + pos: [3, 1, 2], + state: 1 + }, + { + pos: [0, 0, 3], + state: 0 + }, + { + pos: [1, 0, 3], + state: 0 + }, + { + pos: [2, 0, 3], + state: 0 + }, + { + pos: [3, 0, 3], + state: 0 + }, + { + pos: [4, 0, 3], + state: 0 + }, + { + pos: [1, 1, 3], + state: 1 + }, + { + pos: [2, 1, 3], + state: 1 + }, + { + pos: [3, 1, 3], + state: 1 + }, + { + pos: [0, 0, 4], + state: 0 + }, + { + pos: [1, 0, 4], + state: 0 + }, + { + pos: [2, 0, 4], + state: 0 + }, + { + pos: [3, 0, 4], + state: 0 + }, + { + pos: [4, 0, 4], + state: 0 + }, + { + nbt: { + Owner: { + UpperId: 4039158846114182220L, + LowerId: -6876936588741668278L, + Name: "Dev" + }, + Fuel: 0, + Slot: 0, + Items: [ + { + Slot: 0b, + id: "minecraft:bucket", + Count: 1b + } + ], + id: "computercraft:turtle_normal", + ComputerId: 8, + On: 1b + }, + pos: [2, 2, 2], + state: 2 + }, + { + pos: [0, 1, 0], + state: 3 + }, + { + pos: [1, 1, 0], + state: 3 + }, + { + pos: [2, 1, 0], + state: 3 + }, + { + pos: [3, 1, 0], + state: 3 + }, + { + pos: [4, 1, 0], + state: 3 + }, + { + pos: [0, 2, 0], + state: 3 + }, + { + pos: [1, 2, 0], + state: 3 + }, + { + pos: [2, 2, 0], + state: 3 + }, + { + pos: [3, 2, 0], + state: 3 + }, + { + pos: [4, 2, 0], + state: 3 + }, + { + pos: [0, 3, 0], + state: 3 + }, + { + pos: [1, 3, 0], + state: 3 + }, + { + pos: [2, 3, 0], + state: 3 + }, + { + pos: [3, 3, 0], + state: 3 + }, + { + pos: [4, 3, 0], + state: 3 + }, + { + pos: [0, 4, 0], + state: 3 + }, + { + pos: [1, 4, 0], + state: 3 + }, + { + pos: [2, 4, 0], + state: 3 + }, + { + pos: [3, 4, 0], + state: 3 + }, + { + pos: [4, 4, 0], + state: 3 + }, + { + pos: [0, 1, 1], + state: 3 + }, + { + pos: [4, 1, 1], + state: 3 + }, + { + pos: [0, 2, 1], + state: 3 + }, + { + pos: [1, 2, 1], + state: 3 + }, + { + pos: [2, 2, 1], + state: 3 + }, + { + pos: [3, 2, 1], + state: 3 + }, + { + pos: [4, 2, 1], + state: 3 + }, + { + pos: [0, 3, 1], + state: 3 + }, + { + pos: [1, 3, 1], + state: 3 + }, + { + pos: [2, 3, 1], + state: 3 + }, + { + pos: [3, 3, 1], + state: 3 + }, + { + pos: [4, 3, 1], + state: 3 + }, + { + pos: [0, 4, 1], + state: 3 + }, + { + pos: [1, 4, 1], + state: 3 + }, + { + pos: [2, 4, 1], + state: 3 + }, + { + pos: [3, 4, 1], + state: 3 + }, + { + pos: [4, 4, 1], + state: 3 + }, + { + pos: [0, 1, 2], + state: 3 + }, + { + pos: [2, 1, 2], + state: 4 + }, + { + pos: [4, 1, 2], + state: 3 + }, + { + pos: [0, 2, 2], + state: 3 + }, + { + pos: [1, 2, 2], + state: 3 + }, + { + pos: [3, 2, 2], + state: 3 + }, + { + pos: [4, 2, 2], + state: 3 + }, + { + pos: [0, 3, 2], + state: 3 + }, + { + pos: [1, 3, 2], + state: 3 + }, + { + pos: [2, 3, 2], + state: 3 + }, + { + pos: [3, 3, 2], + state: 3 + }, + { + pos: [4, 3, 2], + state: 3 + }, + { + pos: [0, 4, 2], + state: 3 + }, + { + pos: [1, 4, 2], + state: 3 + }, + { + pos: [2, 4, 2], + state: 3 + }, + { + pos: [3, 4, 2], + state: 3 + }, + { + pos: [4, 4, 2], + state: 3 + }, + { + pos: [0, 1, 3], + state: 3 + }, + { + pos: [4, 1, 3], + state: 3 + }, + { + pos: [0, 2, 3], + state: 3 + }, + { + pos: [1, 2, 3], + state: 3 + }, + { + pos: [2, 2, 3], + state: 3 + }, + { + pos: [3, 2, 3], + state: 3 + }, + { + pos: [4, 2, 3], + state: 3 + }, + { + pos: [0, 3, 3], + state: 3 + }, + { + pos: [1, 3, 3], + state: 3 + }, + { + pos: [2, 3, 3], + state: 3 + }, + { + pos: [3, 3, 3], + state: 3 + }, + { + pos: [4, 3, 3], + state: 3 + }, + { + pos: [0, 4, 3], + state: 3 + }, + { + pos: [1, 4, 3], + state: 3 + }, + { + pos: [2, 4, 3], + state: 3 + }, + { + pos: [3, 4, 3], + state: 3 + }, + { + pos: [4, 4, 3], + state: 3 + }, + { + pos: [0, 1, 4], + state: 3 + }, + { + pos: [1, 1, 4], + state: 3 + }, + { + pos: [2, 1, 4], + state: 3 + }, + { + pos: [3, 1, 4], + state: 3 + }, + { + pos: [4, 1, 4], + state: 3 + }, + { + pos: [0, 2, 4], + state: 3 + }, + { + pos: [1, 2, 4], + state: 3 + }, + { + pos: [2, 2, 4], + state: 3 + }, + { + pos: [3, 2, 4], + state: 3 + }, + { + pos: [4, 2, 4], + state: 3 + }, + { + pos: [0, 3, 4], + state: 3 + }, + { + pos: [1, 3, 4], + state: 3 + }, + { + pos: [2, 3, 4], + state: 3 + }, + { + pos: [3, 3, 4], + state: 3 + }, + { + pos: [4, 3, 4], + state: 3 + }, + { + pos: [0, 4, 4], + state: 3 + }, + { + pos: [1, 4, 4], + state: 3 + }, + { + pos: [2, 4, 4], + state: 3 + }, + { + pos: [3, 4, 4], + state: 3 + }, + { + pos: [4, 4, 4], + state: 3 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Name: "minecraft:white_stained_glass" + }, + { + Properties: { + waterlogged: "false", + facing: "south" + }, + Name: "computercraft:turtle_normal" + }, + { + Name: "minecraft:air" + }, + { + Properties: { + level: "0" + }, + Name: "minecraft:lava" + } + ], + DataVersion: 2230 +} diff --git a/src/test/server-files/structures/turtle_test.hoe_dirt.snbt b/src/test/server-files/structures/turtle_test.hoe_dirt.snbt new file mode 100644 index 000000000..559e1a6fe --- /dev/null +++ b/src/test/server-files/structures/turtle_test.hoe_dirt.snbt @@ -0,0 +1,147 @@ +{ + size: [3, 3, 3], + entities: [], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [1, 1, 1], + state: 1 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + nbt: { + Owner: { + UpperId: 4039158846114182220L, + LowerId: -6876936588741668278L, + Name: "Dev" + }, + Fuel: 0, + LeftUpgrade: "minecraft:diamond_hoe", + Slot: 0, + Items: [], + id: "computercraft:turtle_normal", + ComputerId: 9, + On: 1b + }, + pos: [1, 1, 0], + state: 2 + }, + { + pos: [0, 1, 0], + state: 3 + }, + { + pos: [2, 1, 0], + state: 3 + }, + { + pos: [0, 2, 0], + state: 3 + }, + { + pos: [1, 2, 0], + state: 3 + }, + { + pos: [2, 2, 0], + state: 3 + }, + { + pos: [0, 1, 1], + state: 3 + }, + { + pos: [2, 1, 1], + state: 3 + }, + { + pos: [0, 2, 1], + state: 3 + }, + { + pos: [1, 2, 1], + state: 3 + }, + { + pos: [2, 2, 1], + state: 3 + }, + { + pos: [0, 1, 2], + state: 3 + }, + { + pos: [1, 1, 2], + state: 3 + }, + { + pos: [2, 1, 2], + state: 3 + }, + { + pos: [0, 2, 2], + state: 3 + }, + { + pos: [1, 2, 2], + state: 3 + }, + { + pos: [2, 2, 2], + state: 3 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Name: "minecraft:dirt" + }, + { + Properties: { + waterlogged: "false", + facing: "south" + }, + Name: "computercraft:turtle_normal" + }, + { + Name: "minecraft:air" + } + ], + DataVersion: 2230 +} diff --git a/src/test/server-files/structures/turtle_test.place_lava.snbt b/src/test/server-files/structures/turtle_test.place_lava.snbt new file mode 100644 index 000000000..22334744b --- /dev/null +++ b/src/test/server-files/structures/turtle_test.place_lava.snbt @@ -0,0 +1,544 @@ +{ + size: [5, 5, 5], + entities: [], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [3, 0, 0], + state: 0 + }, + { + pos: [4, 0, 0], + state: 0 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [3, 0, 1], + state: 0 + }, + { + pos: [4, 0, 1], + state: 0 + }, + { + pos: [1, 1, 1], + state: 1 + }, + { + pos: [2, 1, 1], + state: 1 + }, + { + pos: [3, 1, 1], + state: 1 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + pos: [3, 0, 2], + state: 0 + }, + { + pos: [4, 0, 2], + state: 0 + }, + { + pos: [1, 1, 2], + state: 1 + }, + { + pos: [3, 1, 2], + state: 1 + }, + { + pos: [0, 0, 3], + state: 0 + }, + { + pos: [1, 0, 3], + state: 0 + }, + { + pos: [2, 0, 3], + state: 0 + }, + { + pos: [3, 0, 3], + state: 0 + }, + { + pos: [4, 0, 3], + state: 0 + }, + { + pos: [1, 1, 3], + state: 1 + }, + { + pos: [2, 1, 3], + state: 1 + }, + { + pos: [3, 1, 3], + state: 1 + }, + { + pos: [0, 0, 4], + state: 0 + }, + { + pos: [1, 0, 4], + state: 0 + }, + { + pos: [2, 0, 4], + state: 0 + }, + { + pos: [3, 0, 4], + state: 0 + }, + { + pos: [4, 0, 4], + state: 0 + }, + { + nbt: { + Owner: { + UpperId: 4039158846114182220L, + LowerId: -6876936588741668278L, + Name: "Dev" + }, + Fuel: 0, + Slot: 0, + Items: [ + { + Slot: 0b, + id: "minecraft:lava_bucket", + Count: 1b + } + ], + id: "computercraft:turtle_normal", + ComputerId: 6, + On: 1b + }, + pos: [2, 2, 2], + state: 2 + }, + { + pos: [0, 1, 0], + state: 3 + }, + { + pos: [1, 1, 0], + state: 3 + }, + { + pos: [2, 1, 0], + state: 3 + }, + { + pos: [3, 1, 0], + state: 3 + }, + { + pos: [4, 1, 0], + state: 3 + }, + { + pos: [0, 2, 0], + state: 3 + }, + { + pos: [1, 2, 0], + state: 3 + }, + { + pos: [2, 2, 0], + state: 3 + }, + { + pos: [3, 2, 0], + state: 3 + }, + { + pos: [4, 2, 0], + state: 3 + }, + { + pos: [0, 3, 0], + state: 3 + }, + { + pos: [1, 3, 0], + state: 3 + }, + { + pos: [2, 3, 0], + state: 3 + }, + { + pos: [3, 3, 0], + state: 3 + }, + { + pos: [4, 3, 0], + state: 3 + }, + { + pos: [0, 4, 0], + state: 3 + }, + { + pos: [1, 4, 0], + state: 3 + }, + { + pos: [2, 4, 0], + state: 3 + }, + { + pos: [3, 4, 0], + state: 3 + }, + { + pos: [4, 4, 0], + state: 3 + }, + { + pos: [0, 1, 1], + state: 3 + }, + { + pos: [4, 1, 1], + state: 3 + }, + { + pos: [0, 2, 1], + state: 3 + }, + { + pos: [1, 2, 1], + state: 3 + }, + { + pos: [2, 2, 1], + state: 3 + }, + { + pos: [3, 2, 1], + state: 3 + }, + { + pos: [4, 2, 1], + state: 3 + }, + { + pos: [0, 3, 1], + state: 3 + }, + { + pos: [1, 3, 1], + state: 3 + }, + { + pos: [2, 3, 1], + state: 3 + }, + { + pos: [3, 3, 1], + state: 3 + }, + { + pos: [4, 3, 1], + state: 3 + }, + { + pos: [0, 4, 1], + state: 3 + }, + { + pos: [1, 4, 1], + state: 3 + }, + { + pos: [2, 4, 1], + state: 3 + }, + { + pos: [3, 4, 1], + state: 3 + }, + { + pos: [4, 4, 1], + state: 3 + }, + { + pos: [0, 1, 2], + state: 3 + }, + { + pos: [2, 1, 2], + state: 3 + }, + { + pos: [4, 1, 2], + state: 3 + }, + { + pos: [0, 2, 2], + state: 3 + }, + { + pos: [1, 2, 2], + state: 3 + }, + { + pos: [3, 2, 2], + state: 3 + }, + { + pos: [4, 2, 2], + state: 3 + }, + { + pos: [0, 3, 2], + state: 3 + }, + { + pos: [1, 3, 2], + state: 3 + }, + { + pos: [2, 3, 2], + state: 3 + }, + { + pos: [3, 3, 2], + state: 3 + }, + { + pos: [4, 3, 2], + state: 3 + }, + { + pos: [0, 4, 2], + state: 3 + }, + { + pos: [1, 4, 2], + state: 3 + }, + { + pos: [2, 4, 2], + state: 3 + }, + { + pos: [3, 4, 2], + state: 3 + }, + { + pos: [4, 4, 2], + state: 3 + }, + { + pos: [0, 1, 3], + state: 3 + }, + { + pos: [4, 1, 3], + state: 3 + }, + { + pos: [0, 2, 3], + state: 3 + }, + { + pos: [1, 2, 3], + state: 3 + }, + { + pos: [2, 2, 3], + state: 3 + }, + { + pos: [3, 2, 3], + state: 3 + }, + { + pos: [4, 2, 3], + state: 3 + }, + { + pos: [0, 3, 3], + state: 3 + }, + { + pos: [1, 3, 3], + state: 3 + }, + { + pos: [2, 3, 3], + state: 3 + }, + { + pos: [3, 3, 3], + state: 3 + }, + { + pos: [4, 3, 3], + state: 3 + }, + { + pos: [0, 4, 3], + state: 3 + }, + { + pos: [1, 4, 3], + state: 3 + }, + { + pos: [2, 4, 3], + state: 3 + }, + { + pos: [3, 4, 3], + state: 3 + }, + { + pos: [4, 4, 3], + state: 3 + }, + { + pos: [0, 1, 4], + state: 3 + }, + { + pos: [1, 1, 4], + state: 3 + }, + { + pos: [2, 1, 4], + state: 3 + }, + { + pos: [3, 1, 4], + state: 3 + }, + { + pos: [4, 1, 4], + state: 3 + }, + { + pos: [0, 2, 4], + state: 3 + }, + { + pos: [1, 2, 4], + state: 3 + }, + { + pos: [2, 2, 4], + state: 3 + }, + { + pos: [3, 2, 4], + state: 3 + }, + { + pos: [4, 2, 4], + state: 3 + }, + { + pos: [0, 3, 4], + state: 3 + }, + { + pos: [1, 3, 4], + state: 3 + }, + { + pos: [2, 3, 4], + state: 3 + }, + { + pos: [3, 3, 4], + state: 3 + }, + { + pos: [4, 3, 4], + state: 3 + }, + { + pos: [0, 4, 4], + state: 3 + }, + { + pos: [1, 4, 4], + state: 3 + }, + { + pos: [2, 4, 4], + state: 3 + }, + { + pos: [3, 4, 4], + state: 3 + }, + { + pos: [4, 4, 4], + state: 3 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Name: "minecraft:white_stained_glass" + }, + { + Properties: { + waterlogged: "false", + facing: "south" + }, + Name: "computercraft:turtle_normal" + }, + { + Name: "minecraft:air" + } + ], + DataVersion: 2230 +} diff --git a/src/test/server-files/structures/turtle_test.place_waterlogged.snbt b/src/test/server-files/structures/turtle_test.place_waterlogged.snbt new file mode 100644 index 000000000..a7930b6e0 --- /dev/null +++ b/src/test/server-files/structures/turtle_test.place_waterlogged.snbt @@ -0,0 +1,550 @@ +{ + size: [5, 5, 5], + entities: [], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [3, 0, 0], + state: 0 + }, + { + pos: [4, 0, 0], + state: 0 + }, + { + pos: [1, 1, 0], + state: 1 + }, + { + pos: [2, 1, 0], + state: 1 + }, + { + pos: [3, 1, 0], + state: 1 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [3, 0, 1], + state: 0 + }, + { + pos: [4, 0, 1], + state: 0 + }, + { + pos: [1, 1, 1], + state: 1 + }, + { + pos: [3, 1, 1], + state: 1 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + pos: [3, 0, 2], + state: 0 + }, + { + pos: [4, 0, 2], + state: 0 + }, + { + pos: [1, 1, 2], + state: 1 + }, + { + pos: [3, 1, 2], + state: 1 + }, + { + pos: [0, 0, 3], + state: 0 + }, + { + pos: [1, 0, 3], + state: 0 + }, + { + pos: [2, 0, 3], + state: 0 + }, + { + pos: [3, 0, 3], + state: 0 + }, + { + pos: [4, 0, 3], + state: 0 + }, + { + pos: [1, 1, 3], + state: 1 + }, + { + pos: [2, 1, 3], + state: 1 + }, + { + pos: [3, 1, 3], + state: 1 + }, + { + pos: [0, 0, 4], + state: 0 + }, + { + pos: [1, 0, 4], + state: 0 + }, + { + pos: [2, 0, 4], + state: 0 + }, + { + pos: [3, 0, 4], + state: 0 + }, + { + pos: [4, 0, 4], + state: 0 + }, + { + nbt: { + Owner: { + UpperId: 4039158846114182220L, + LowerId: -6876936588741668278L, + Name: "Dev" + }, + Fuel: 0, + Slot: 0, + Items: [ + { + Slot: 0b, + id: "minecraft:oak_fence", + Count: 1b + } + ], + id: "computercraft:turtle_normal", + ComputerId: 7, + On: 1b + }, + pos: [2, 1, 1], + state: 2 + }, + { + pos: [0, 1, 0], + state: 3 + }, + { + pos: [4, 1, 0], + state: 3 + }, + { + pos: [0, 2, 0], + state: 3 + }, + { + pos: [1, 2, 0], + state: 3 + }, + { + pos: [2, 2, 0], + state: 3 + }, + { + pos: [3, 2, 0], + state: 3 + }, + { + pos: [4, 2, 0], + state: 3 + }, + { + pos: [0, 3, 0], + state: 3 + }, + { + pos: [1, 3, 0], + state: 3 + }, + { + pos: [2, 3, 0], + state: 3 + }, + { + pos: [3, 3, 0], + state: 3 + }, + { + pos: [4, 3, 0], + state: 3 + }, + { + pos: [0, 4, 0], + state: 3 + }, + { + pos: [1, 4, 0], + state: 3 + }, + { + pos: [2, 4, 0], + state: 3 + }, + { + pos: [3, 4, 0], + state: 3 + }, + { + pos: [4, 4, 0], + state: 3 + }, + { + pos: [0, 1, 1], + state: 3 + }, + { + pos: [4, 1, 1], + state: 3 + }, + { + pos: [0, 2, 1], + state: 3 + }, + { + pos: [1, 2, 1], + state: 3 + }, + { + pos: [2, 2, 1], + state: 3 + }, + { + pos: [3, 2, 1], + state: 3 + }, + { + pos: [4, 2, 1], + state: 3 + }, + { + pos: [0, 3, 1], + state: 3 + }, + { + pos: [1, 3, 1], + state: 3 + }, + { + pos: [2, 3, 1], + state: 3 + }, + { + pos: [3, 3, 1], + state: 3 + }, + { + pos: [4, 3, 1], + state: 3 + }, + { + pos: [0, 4, 1], + state: 3 + }, + { + pos: [1, 4, 1], + state: 3 + }, + { + pos: [2, 4, 1], + state: 3 + }, + { + pos: [3, 4, 1], + state: 3 + }, + { + pos: [4, 4, 1], + state: 3 + }, + { + pos: [0, 1, 2], + state: 3 + }, + { + pos: [2, 1, 2], + state: 4 + }, + { + pos: [4, 1, 2], + state: 3 + }, + { + pos: [0, 2, 2], + state: 3 + }, + { + pos: [1, 2, 2], + state: 3 + }, + { + pos: [2, 2, 2], + state: 3 + }, + { + pos: [3, 2, 2], + state: 3 + }, + { + pos: [4, 2, 2], + state: 3 + }, + { + pos: [0, 3, 2], + state: 3 + }, + { + pos: [1, 3, 2], + state: 3 + }, + { + pos: [2, 3, 2], + state: 3 + }, + { + pos: [3, 3, 2], + state: 3 + }, + { + pos: [4, 3, 2], + state: 3 + }, + { + pos: [0, 4, 2], + state: 3 + }, + { + pos: [1, 4, 2], + state: 3 + }, + { + pos: [2, 4, 2], + state: 3 + }, + { + pos: [3, 4, 2], + state: 3 + }, + { + pos: [4, 4, 2], + state: 3 + }, + { + pos: [0, 1, 3], + state: 3 + }, + { + pos: [4, 1, 3], + state: 3 + }, + { + pos: [0, 2, 3], + state: 3 + }, + { + pos: [1, 2, 3], + state: 3 + }, + { + pos: [2, 2, 3], + state: 3 + }, + { + pos: [3, 2, 3], + state: 3 + }, + { + pos: [4, 2, 3], + state: 3 + }, + { + pos: [0, 3, 3], + state: 3 + }, + { + pos: [1, 3, 3], + state: 3 + }, + { + pos: [2, 3, 3], + state: 3 + }, + { + pos: [3, 3, 3], + state: 3 + }, + { + pos: [4, 3, 3], + state: 3 + }, + { + pos: [0, 4, 3], + state: 3 + }, + { + pos: [1, 4, 3], + state: 3 + }, + { + pos: [2, 4, 3], + state: 3 + }, + { + pos: [3, 4, 3], + state: 3 + }, + { + pos: [4, 4, 3], + state: 3 + }, + { + pos: [0, 1, 4], + state: 3 + }, + { + pos: [1, 1, 4], + state: 3 + }, + { + pos: [2, 1, 4], + state: 3 + }, + { + pos: [3, 1, 4], + state: 3 + }, + { + pos: [4, 1, 4], + state: 3 + }, + { + pos: [0, 2, 4], + state: 3 + }, + { + pos: [1, 2, 4], + state: 3 + }, + { + pos: [2, 2, 4], + state: 3 + }, + { + pos: [3, 2, 4], + state: 3 + }, + { + pos: [4, 2, 4], + state: 3 + }, + { + pos: [0, 3, 4], + state: 3 + }, + { + pos: [1, 3, 4], + state: 3 + }, + { + pos: [2, 3, 4], + state: 3 + }, + { + pos: [3, 3, 4], + state: 3 + }, + { + pos: [4, 3, 4], + state: 3 + }, + { + pos: [0, 4, 4], + state: 3 + }, + { + pos: [1, 4, 4], + state: 3 + }, + { + pos: [2, 4, 4], + state: 3 + }, + { + pos: [3, 4, 4], + state: 3 + }, + { + pos: [4, 4, 4], + state: 3 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Name: "minecraft:white_stained_glass" + }, + { + Properties: { + waterlogged: "true", + facing: "south" + }, + Name: "computercraft:turtle_normal" + }, + { + Name: "minecraft:air" + }, + { + Properties: { + level: "0" + }, + Name: "minecraft:water" + } + ], + DataVersion: 2230 +} diff --git a/src/test/server-files/structures/turtle_test.shears_sheep.snbt b/src/test/server-files/structures/turtle_test.shears_sheep.snbt new file mode 100644 index 000000000..dbd5ba6a6 --- /dev/null +++ b/src/test/server-files/structures/turtle_test.shears_sheep.snbt @@ -0,0 +1,648 @@ +{ + size: [5, 5, 5], + entities: [ + { + nbt: { + Brain: { + memories: {} + }, + HurtByTimestamp: 0, + 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: [ + { + UUIDMost: 2135385928807173041L, + UUIDLeast: -7913974980122166977L, + Amount: -0.04393447767139704d, + Operation: 1, + Name: "Random spawn bonus" + } + ], + Name: "generic.followRange" + }, + { + Base: 0.0d, + Name: "generic.attackKnockback" + } + ], + Invulnerable: 0b, + FallFlying: 0b, + ForcedAge: 0, + PortalCooldown: 0, + AbsorptionAmount: 0.0f, + FallDistance: 0.0f, + InLove: 0, + CanUpdate: 1b, + DeathTime: 0s, + HandDropChances: [0.085f, 0.085f], + PersistenceRequired: 0b, + id: "minecraft:sheep", + Age: 0, + Motion: [0.0d, -0.0784000015258789d, 0.0d], + UUIDLeast: -5245632071702074643L, + Health: 8.0f, + Color: 0b, + LeftHanded: 0b, + Air: 300s, + OnGround: 1b, + Dimension: 0, + Rotation: [99.779915f, 0.0f], + HandItems: [ + {}, + {} + ], + ArmorDropChances: [0.085f, 0.085f, 0.085f, 0.085f], + UUIDMost: -3792049278188698748L, + Pos: [-12.5d, 6.0d, 110.5d], + Fire: -1s, + ArmorItems: [ + {}, + {}, + {}, + {} + ], + CanPickUpLoot: 0b, + Sheared: 0b, + HurtTime: 0s + }, + blockPos: [2, 1, 2], + pos: [2.5d, 1.0d, 2.5d] + } + ], + blocks: [ + { + pos: [0, 0, 0], + state: 0 + }, + { + pos: [1, 0, 0], + state: 0 + }, + { + pos: [2, 0, 0], + state: 0 + }, + { + pos: [3, 0, 0], + state: 0 + }, + { + pos: [4, 0, 0], + state: 0 + }, + { + pos: [0, 0, 1], + state: 0 + }, + { + pos: [1, 0, 1], + state: 0 + }, + { + pos: [2, 0, 1], + state: 0 + }, + { + pos: [3, 0, 1], + state: 0 + }, + { + pos: [4, 0, 1], + state: 0 + }, + { + pos: [1, 1, 1], + state: 1 + }, + { + pos: [2, 1, 1], + state: 1 + }, + { + pos: [3, 1, 1], + state: 1 + }, + { + pos: [1, 2, 1], + state: 1 + }, + { + pos: [2, 2, 1], + state: 1 + }, + { + pos: [3, 2, 1], + state: 1 + }, + { + pos: [0, 0, 2], + state: 0 + }, + { + pos: [1, 0, 2], + state: 0 + }, + { + pos: [2, 0, 2], + state: 0 + }, + { + pos: [3, 0, 2], + state: 0 + }, + { + pos: [4, 0, 2], + state: 0 + }, + { + pos: [1, 1, 2], + state: 1 + }, + { + pos: [3, 1, 2], + state: 1 + }, + { + pos: [1, 2, 2], + state: 1 + }, + { + pos: [3, 2, 2], + state: 1 + }, + { + pos: [0, 0, 3], + state: 0 + }, + { + pos: [1, 0, 3], + state: 0 + }, + { + pos: [2, 0, 3], + state: 0 + }, + { + pos: [3, 0, 3], + state: 0 + }, + { + pos: [4, 0, 3], + state: 0 + }, + { + pos: [1, 1, 3], + state: 1 + }, + { + pos: [2, 1, 3], + state: 1 + }, + { + pos: [3, 1, 3], + state: 1 + }, + { + pos: [1, 2, 3], + state: 1 + }, + { + pos: [2, 2, 3], + state: 1 + }, + { + pos: [3, 2, 3], + state: 1 + }, + { + pos: [0, 0, 4], + state: 0 + }, + { + pos: [1, 0, 4], + state: 0 + }, + { + pos: [2, 0, 4], + state: 0 + }, + { + pos: [3, 0, 4], + state: 0 + }, + { + pos: [4, 0, 4], + state: 0 + }, + { + nbt: { + Owner: { + UpperId: 4039158846114182220L, + LowerId: -6876936588741668278L, + Name: "Dev" + }, + Fuel: 0, + Slot: 0, + Items: [ + { + Slot: 0b, + id: "minecraft:shears", + Count: 1b, + tag: { + Damage: 0 + } + } + ], + id: "computercraft:turtle_normal", + ComputerId: 5, + On: 1b + }, + pos: [2, 3, 2], + state: 2 + }, + { + pos: [0, 1, 0], + state: 3 + }, + { + pos: [1, 1, 0], + state: 3 + }, + { + pos: [2, 1, 0], + state: 3 + }, + { + pos: [3, 1, 0], + state: 3 + }, + { + pos: [4, 1, 0], + state: 3 + }, + { + pos: [0, 2, 0], + state: 3 + }, + { + pos: [1, 2, 0], + state: 3 + }, + { + pos: [2, 2, 0], + state: 3 + }, + { + pos: [3, 2, 0], + state: 3 + }, + { + pos: [4, 2, 0], + state: 3 + }, + { + pos: [0, 3, 0], + state: 3 + }, + { + pos: [1, 3, 0], + state: 3 + }, + { + pos: [2, 3, 0], + state: 3 + }, + { + pos: [3, 3, 0], + state: 3 + }, + { + pos: [4, 3, 0], + state: 3 + }, + { + pos: [0, 4, 0], + state: 3 + }, + { + pos: [1, 4, 0], + state: 3 + }, + { + pos: [2, 4, 0], + state: 3 + }, + { + pos: [3, 4, 0], + state: 3 + }, + { + pos: [4, 4, 0], + state: 3 + }, + { + pos: [0, 1, 1], + state: 3 + }, + { + pos: [4, 1, 1], + state: 3 + }, + { + pos: [0, 2, 1], + state: 3 + }, + { + pos: [4, 2, 1], + state: 3 + }, + { + pos: [0, 3, 1], + state: 3 + }, + { + pos: [1, 3, 1], + state: 3 + }, + { + pos: [2, 3, 1], + state: 3 + }, + { + pos: [3, 3, 1], + state: 3 + }, + { + pos: [4, 3, 1], + state: 3 + }, + { + pos: [0, 4, 1], + state: 3 + }, + { + pos: [1, 4, 1], + state: 3 + }, + { + pos: [2, 4, 1], + state: 3 + }, + { + pos: [3, 4, 1], + state: 3 + }, + { + pos: [4, 4, 1], + state: 3 + }, + { + pos: [0, 1, 2], + state: 3 + }, + { + pos: [2, 1, 2], + state: 3 + }, + { + pos: [4, 1, 2], + state: 3 + }, + { + pos: [0, 2, 2], + state: 3 + }, + { + pos: [2, 2, 2], + state: 3 + }, + { + pos: [4, 2, 2], + state: 3 + }, + { + pos: [0, 3, 2], + state: 3 + }, + { + pos: [1, 3, 2], + state: 3 + }, + { + pos: [3, 3, 2], + state: 3 + }, + { + pos: [4, 3, 2], + state: 3 + }, + { + pos: [0, 4, 2], + state: 3 + }, + { + pos: [1, 4, 2], + state: 3 + }, + { + pos: [2, 4, 2], + state: 3 + }, + { + pos: [3, 4, 2], + state: 3 + }, + { + pos: [4, 4, 2], + state: 3 + }, + { + pos: [0, 1, 3], + state: 3 + }, + { + pos: [4, 1, 3], + state: 3 + }, + { + pos: [0, 2, 3], + state: 3 + }, + { + pos: [4, 2, 3], + state: 3 + }, + { + pos: [0, 3, 3], + state: 3 + }, + { + pos: [1, 3, 3], + state: 3 + }, + { + pos: [2, 3, 3], + state: 3 + }, + { + pos: [3, 3, 3], + state: 3 + }, + { + pos: [4, 3, 3], + state: 3 + }, + { + pos: [0, 4, 3], + state: 3 + }, + { + pos: [1, 4, 3], + state: 3 + }, + { + pos: [2, 4, 3], + state: 3 + }, + { + pos: [3, 4, 3], + state: 3 + }, + { + pos: [4, 4, 3], + state: 3 + }, + { + pos: [0, 1, 4], + state: 3 + }, + { + pos: [1, 1, 4], + state: 3 + }, + { + pos: [2, 1, 4], + state: 3 + }, + { + pos: [3, 1, 4], + state: 3 + }, + { + pos: [4, 1, 4], + state: 3 + }, + { + pos: [0, 2, 4], + state: 3 + }, + { + pos: [1, 2, 4], + state: 3 + }, + { + pos: [2, 2, 4], + state: 3 + }, + { + pos: [3, 2, 4], + state: 3 + }, + { + pos: [4, 2, 4], + state: 3 + }, + { + pos: [0, 3, 4], + state: 3 + }, + { + pos: [1, 3, 4], + state: 3 + }, + { + pos: [2, 3, 4], + state: 3 + }, + { + pos: [3, 3, 4], + state: 3 + }, + { + pos: [4, 3, 4], + state: 3 + }, + { + pos: [0, 4, 4], + state: 3 + }, + { + pos: [1, 4, 4], + state: 3 + }, + { + pos: [2, 4, 4], + state: 3 + }, + { + pos: [3, 4, 4], + state: 3 + }, + { + pos: [4, 4, 4], + state: 3 + } + ], + palette: [ + { + Name: "minecraft:polished_andesite" + }, + { + Name: "minecraft:white_stained_glass" + }, + { + Properties: { + waterlogged: "false", + facing: "south" + }, + Name: "computercraft:turtle_normal" + }, + { + Name: "minecraft:air" + } + ], + DataVersion: 2230 +} From 6d367e08a32c01c0f567156446d0257a6608366d Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 19 Jan 2021 21:15:18 +0000 Subject: [PATCH 445/711] ./gradlew checkstyleMain Every time I forget to run this before pushing, I get very sad. --- .../shared/turtle/core/TurtleCompareCommand.java | 2 -- src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt | 4 ++-- .../resources/data/computercraft/lua/rom/autorun/cctest.lua | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java index 4ab393971..3d7fd5881 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -15,10 +15,8 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.fml.common.ObfuscationReflectionHelper; import javax.annotation.Nonnull; -import java.lang.reflect.Method; import java.util.List; public class TurtleCompareCommand implements ITurtleCommand diff --git a/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt b/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt index 4c2c8be8f..de0c0b47f 100644 --- a/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt +++ b/src/test/java/dan200/computercraft/ingame/mod/TestRunner.kt @@ -4,7 +4,6 @@ import dan200.computercraft.ingame.api.TestContext import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import net.minecraft.test.TestCollection import net.minecraft.test.TestTrackerHolder import java.lang.reflect.Method import java.util.* @@ -50,7 +49,8 @@ internal object MainThread : AbstractCoroutineContextElement(ContinuationInterce } } - override fun interceptContinuation(continuation: Continuation): Continuation = MainThreadInterception(continuation) + override fun interceptContinuation(continuation: Continuation): Continuation = + MainThreadInterception(continuation) private class MainThreadInterception(val cont: Continuation) : Continuation { override val context: CoroutineContext get() = cont.context diff --git a/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua b/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua index 197748f4d..1b4f6d778 100644 --- a/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua +++ b/src/test/resources/data/computercraft/lua/rom/autorun/cctest.lua @@ -1,6 +1,6 @@ --- Extend the test API with some convenience functions. -- --- It's much easier to declare these in Lua rather than Java.. +-- It's much easier to declare these in Lua rather than Java. function test.assert(ok, ...) if ok then return ... end From e1cbbe36284e6c682ec5d06eeec3809fb5a675e0 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 19 Jan 2021 21:33:05 +0000 Subject: [PATCH 446/711] Haven't been hoisted by this petard for a while I really should move this to Gradle. Probably should just write my own plugin at this point. --- tools/check-lines.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/check-lines.py b/tools/check-lines.py index 47ff15fc9..6280835f8 100644 --- a/tools/check-lines.py +++ b/tools/check-lines.py @@ -3,7 +3,11 @@ import pathlib, sys problems = False # Skip images and files without extensions -exclude = [ "*.png", "**/data/json-parsing/*.json" ] +exclude = [ + "*.png", + "**/data/json-parsing/*.json", + "**/computers/ids.json", +] for path in pathlib.Path("src").glob("**/*"): # Ideally we'd use generated as a glob, but .match("generated/**/*.json") doesn't work! From 1316d6a3c906eb1dcc0323982b46f655777ee628 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 23 Jan 2021 14:58:08 +0000 Subject: [PATCH 447/711] Migrate all examples to use tweaked.cc Might as well, I've got the server capacity to spare. Hopefully. --- doc/events/http_failure.md | 2 +- doc/events/websocket_closed.md | 2 +- doc/events/websocket_failure.md | 2 +- doc/events/websocket_message.md | 2 +- doc/events/websocket_success.md | 2 +- doc/stub/http.lua | 6 +++--- .../core/apis/http/request/HttpResponseHandle.java | 4 ++-- src/main/resources/data/computercraft/lua/rom/motd.txt | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/events/http_failure.md b/doc/events/http_failure.md index d7572e601..dc10b40d7 100644 --- a/doc/events/http_failure.md +++ b/doc/events/http_failure.md @@ -16,7 +16,7 @@ This event is normally handled inside @{http.get} and @{http.post}, but it can s ## Example Prints an error why the website cannot be contacted: ```lua -local myURL = "http://this.website.does.not.exist" +local myURL = "https://does.not.exist.tweaked.cc" http.request(myURL) local event, url, err repeat diff --git a/doc/events/websocket_closed.md b/doc/events/websocket_closed.md index 60a8f59c2..9e3783d19 100644 --- a/doc/events/websocket_closed.md +++ b/doc/events/websocket_closed.md @@ -11,7 +11,7 @@ The @{websocket_closed} event is fired when an open WebSocket connection is clos ## Example Prints a message when a WebSocket is closed (this may take a minute): ```lua -local myURL = "ws://echo.websocket.org" +local myURL = "wss://example.tweaked.cc/echo" local ws = http.websocket(myURL) local event, url repeat diff --git a/doc/events/websocket_failure.md b/doc/events/websocket_failure.md index f53bf10af..eef34e777 100644 --- a/doc/events/websocket_failure.md +++ b/doc/events/websocket_failure.md @@ -15,7 +15,7 @@ This event is normally handled inside @{http.websocket}, but it can still be see ## Example Prints an error why the website cannot be contacted: ```lua -local myURL = "ws://this.website.does.not.exist" +local myURL = "wss://example.tweaked.cc/not-a-websocket" http.websocketAsync(myURL) local event, url, err repeat diff --git a/doc/events/websocket_message.md b/doc/events/websocket_message.md index f42dcaefe..53b9d4bd2 100644 --- a/doc/events/websocket_message.md +++ b/doc/events/websocket_message.md @@ -14,7 +14,7 @@ This event is normally handled by @{http.Websocket.receive}, but it can also be ## Example Prints a message sent by a WebSocket: ```lua -local myURL = "ws://echo.websocket.org" +local myURL = "wss://example.tweaked.cc/echo" local ws = http.websocket(myURL) ws.send("Hello!") local event, url, message diff --git a/doc/events/websocket_success.md b/doc/events/websocket_success.md index dc8d95dd2..dcde934b3 100644 --- a/doc/events/websocket_success.md +++ b/doc/events/websocket_success.md @@ -15,7 +15,7 @@ This event is normally handled inside @{http.websocket}, but it can still be see ## Example Prints the content of a website (this may fail if the request fails): ```lua -local myURL = "ws://echo.websocket.org" +local myURL = "wss://example.tweaked.cc/echo" http.websocketAsync(myURL) local event, url, handle repeat diff --git a/doc/stub/http.lua b/doc/stub/http.lua index 6854ac9ea..28d04d648 100644 --- a/doc/stub/http.lua +++ b/doc/stub/http.lua @@ -58,10 +58,10 @@ function request(...) end -- @treturn string A message detailing why the request failed. -- @treturn Response|nil The failing http response, if available. -- --- @usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), +-- @usage Make a request to [example.tweaked.cc](https://example.tweaked.cc), -- and print the returned page. -- ```lua --- local request = http.get("https://example.computercraft.cc") +-- local request = http.get("https://example.tweaked.cc") -- print(request.readAll()) -- -- => HTTP is working! -- request.close() @@ -123,7 +123,7 @@ function checkURLAsync(url) end -- -- @usage -- ```lua --- print(http.checkURL("https://example.computercraft.cc/")) +-- print(http.checkURL("https://example.tweaked.cc/")) -- -- => true -- print(http.checkURL("http://localhost/")) -- -- => false Domain not permitted diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java index 5ab40814d..c5d72134b 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpResponseHandle.java @@ -58,10 +58,10 @@ public class HttpResponseHandle implements ObjectSource * If multiple headers are sent with the same name, they will be combined with a comma. * * @return The response's headers. - * @cc.usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), and print the + * @cc.usage Make a request to [example.tweaked.cc](https://example.tweaked.cc), and print the * returned headers. *
{@code
-     * local request = http.get("https://example.computercraft.cc")
+     * local request = http.get("https://example.tweaked.cc")
      * print(textutils.serialize(request.getResponseHeaders()))
      * -- => {
      * --  [ "Content-Type" ] = "text/plain; charset=utf8",
diff --git a/src/main/resources/data/computercraft/lua/rom/motd.txt b/src/main/resources/data/computercraft/lua/rom/motd.txt
index 8c8f16945..1745d4ee3 100644
--- a/src/main/resources/data/computercraft/lua/rom/motd.txt
+++ b/src/main/resources/data/computercraft/lua/rom/motd.txt
@@ -1,5 +1,5 @@
 Please report bugs at https://github.com/SquidDev-CC/CC-Tweaked. Thanks!
-View the documentation at https://wiki.computercraft.cc
+View the documentation at https://tweaked.cc
 Show off your programs or ask for help at our forum: https://forums.computercraft.cc
 You can disable these messages by running "set motd.enable false".
 Use "pastebin put" to upload a program to pastebin.

From 7514cf7320bbee1ab8cd7bf9642e0e863d82461e Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sun, 24 Jan 2021 21:23:29 +0000
Subject: [PATCH 448/711] Mark as compatible with 1.16.{4,5}

Closes #694
---
 build.gradle | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/build.gradle b/build.gradle
index 604ecd9f9..79a09871c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -560,6 +560,9 @@ curseforge {
         relations {
             incompatible "computercraft"
         }
+
+        addGameVersion '1.16.4'
+        addGameVersion '1.16.5'
     }
 }
 

From 396cf15a1f8ae9132296aa563ac2c46abba697a5 Mon Sep 17 00:00:00 2001
From: SkyTheCodeMaster <34724753+SkyTheCodeMaster@users.noreply.github.com>
Date: Fri, 5 Feb 2021 14:10:11 -0500
Subject: [PATCH 449/711] Fix `redstone.getBundledInput(side)` returning the
 output of said side.

---
 src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java
index 27c13b957..186199302 100644
--- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java
+++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java
@@ -191,7 +191,7 @@ public class RedstoneAPI implements ILuaAPI
     @LuaFunction
     public final int getBundledInput( ComputerSide side )
     {
-        return environment.getBundledOutput( side );
+        return environment.getBundledInput( side );
     }
 
     /**

From 061514549dd82e32d6afa48da775c62b4aaebacd Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 13 Feb 2021 12:39:52 +0000
Subject: [PATCH 450/711] Bump Gradle/ForgeGradle version

This is definitely going to break the build (it shouldn't, but these
things always do). Anyway...

 - Use the new Java toolchain support, rather than requiring the user to
   install multiple Java versions.
 - Bump versions of several plugins.

We're sadly stuck on Gradle <7 for now, as they drop the old
maven-publish plugin, which drops SCP support.
---
 CONTRIBUTING.md                          |  16 ++-----
 build.gradle                             |  19 ++++----
 gradle/wrapper/gradle-wrapper.jar        | Bin 56172 -> 59203 bytes
 gradle/wrapper/gradle-wrapper.properties |   2 +-
 gradlew                                  |  53 ++++++++++++++---------
 gradlew.bat                              |  43 ++++++++++--------
 6 files changed, 73 insertions(+), 60 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 802395905..24b3ce1ca 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -51,18 +51,10 @@ illuaminate, which spits out our HTML.
 For various reasons, getting the environment set up to build documentation can be pretty complex. I'd quite like to
 automate this via Docker and/or nix in the future, but this needs to be done manually for now.
 
-First, you will need JDK 9+ (in addition to JDK 8 which is required to build Minecraft itself). Sadly our version of
-Gradle doesn't support multiple toolchains, and so you need to install this yourself.
-
-Gradle needs to be told about this JDK via the `JAVA_HOME_11_X64` environment variable or adding `java11Home` to 
-`~/.gradle/gradle.properties`. On my system this looks like:
-
-```properties
-java11Home=/usr/lib/jvm/java-11-openjdk/
-```
-
-If you just want to build the documentation stubs for linting, this is enough. However, if you want to build the full
-website, you will also need to install a few Node packages by running `npm ci`.
+This tooling is only needed if you need to build the whole website. If you just want to generate the Lua stubs, you can
+skp this section.
+ - Install Node/npm and install our Node packages with `npm ci`.
+ - Install [illuaminate][illuaminate-usage] as described above.
 
 #### Building documentation
 Gradle should be your entrypoint to building most documentation. There's two tasks which are of interest:
diff --git a/build.gradle b/build.gradle
index 90d5e776f..6d5f6b279 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,7 +9,7 @@ buildscript {
     }
     dependencies {
         classpath 'com.google.code.gson:gson:2.8.1'
-        classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.190'
+        classpath 'net.minecraftforge.gradle:ForgeGradle:4.0.16'
         classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
     }
 }
@@ -18,8 +18,8 @@ plugins {
     id "checkstyle"
     id "jacoco"
     id "com.github.hierynomus.license" version "0.15.0"
-    id "com.matthewprenger.cursegradle" version "1.3.0"
-    id "com.github.breadmoirai.github-release" version "2.2.4"
+    id "com.matthewprenger.cursegradle" version "1.4.0"
+    id "com.github.breadmoirai.github-release" version "2.2.12"
     id "org.jetbrains.kotlin.jvm" version "1.3.72"
 }
 
@@ -32,7 +32,11 @@ version = mod_version
 group = "org.squiddev"
 archivesBaseName = "cc-tweaked-${mc_version}"
 
-sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
+java {
+    toolchain {
+        languageVersion = JavaLanguageVersion.of(8)
+    }
+}
 
 minecraft {
     runs {
@@ -156,11 +160,10 @@ task luaJavadoc(type: Javadoc) {
 
     options.docletpath = configurations.cctJavadoc.files as List
     options.doclet = "cc.tweaked.javadoc.LuaDoclet"
+    options.noTimestamp = false
 
-    // Attempt to run under Java 11 (any Java >= 9 will work though).
-    if(System.getProperty("java.version").startsWith("1.")
-        && (System.getenv("JAVA_HOME_11_X64") != null || project.hasProperty("java11Home"))) {
-        executable = "${System.getenv("JAVA_HOME_11_X64") ?: project.property("java11Home")}/bin/javadoc"
+    javadocTool = javaToolchains.javadocToolFor {
+        languageVersion = JavaLanguageVersion.of(11)
     }
 }
 
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 28861d273a5d270fd8f65dd74570c17c9c507736..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644
GIT binary patch
delta 50996
zcmaE}jrs67X4U|2W)`l=4>Cn3N(l>dF)(m&FfcGUGURTwvvpu#V6dO);47@vBCaYX
zvPA4-(Z?c22DlD>76t}}{GxPyW`x+p8={P0<0dmR%8Db*o2q(w*-l0V21#ZH2K~t&
zCB!ECGK$oz80sbGBo-I<2A$5k>>y%$c}JQ*<29yASgr~A=Ptyt
z>*o!%RW4jPF=|g%q-?BzEj&4;((&5LqGp?~9}SKu=d^y1967~AM6cK
zpX*&NHSMs3uFjKlQbXZl$c}HM$abHiyq(8BOsO%b1<}UkGzv#z`E9g*hB0>K}JeD6q9AlRcmf^
z#?`1eawi7fIMuyafln{d^H?3DLffL2RJPPpCOhXEZYi2MU9xF;NpQKJ@eiSs+C2Yy
zLLczl4!!$i^VCa9+n;ZBZPrMiodD_blp~rcnw{BrlPr7p1VCUqx
z8Nt#KPCH#z#0nkmW4o{CxkK!a@%$LgEG
zhnIWq>n@tQ-*)lZ9Z5nZMP?gkJ=gBbo0-bFeT9|xuE>C`T{GjKZIh0#U!+>P_GCbh
zZXs9Z@2}~sUygp><$FQ5x;G|mZP(oAO`e@u;isn{55#CenhaaCa>W?qc7FnO%?LU8R_v^H|F&9oQ-xnb$_Q<*U=|U0b
z^V24KcW>ud+j5(WX9|nZr_IkTRhKeITXN~F@%RzZ$a`w#;ss6CT<^M)8CDBj6RBzP
z7rk@1_LSb%@>8#ug~(=~V%8K|^uV~rZ>?5TQ_$_8P}chR2i~ml53^q_sk&s`7W!<_
zKCXQS6J%r7N||(r@Gw4!X1)KgvFZKChGlO=+jAatG|7KZK72u2%ixRM`ufaI+ah?M
zzR8^H7Nz1nE%s8zCV#bgbFUuz`1Ms-{>5jV_pZ8yuW4*Z);;4p@xIHZ!i?p|X1}%y
zog6ZMVo2-9X{WAOE7u1-@he;V=0niuDi4)t^^$Dc38zxeK2tk7drkhPUCWiQdp0{+@wdU9f`x6
zOQy{8`{epsf5q(bHMjRH)y=Z~FlpP0i7QrA8tU_~M_-HioyPeo^p;HO_sR8Ty$gf&
z&2_f%HCH%A)@+}3c4m~Pj?KrpUfbTd%PiopV0d(%U2U4&-1V2EXU*%G*Z7ckL;TB4
zyv`+Tu}LDFR-*n4o;;T)C$cP7aXs~hMdcU!yMDVv+ip7lUr;W*FXqPk|ICeZ@=bno
z9OU(=&r_PB9OQnkdsvUJ(3ZNwL1;-FCh&3+LBa^eFf7
zxULWSV_qnr+O^l|;(cXa!8=RD9ds=UtzF7yRC_-*V3j(c)py~n`?hlz`4=TW@l`z~
zZQ)nHXZDlFzH=6|><#svdfeJ`kKrPh4R1MrsUDg4sI6r}ONUFD-_9A5_m<6f`SNz<
z)ko=ze!i%z5#D&GpyEB-x0TAFU)Cl!$o+l&Li*;Be|Oj(h04s3{3{*1xc~2d2dS^J
zwI}3uEfvk|5R?e8m>aTE<7(Cfhvl5#44Jf?`X=8|*j4Dnmab`2^qh@rlKe6Teqjkl
z8xQ*lJSg$fEUH4^Rxx+=4l%cnmzPe7
z^qui9)8n~9$%nal5iH^h#p_z?E?C3}Nn|ye{6jcW2;5Lu%BfA|M+;1ao_W}
zL+;BPE*s9AQ~iBT^||-ucHf>Iw3oln{DJ45k>GLeuNen9HQAP)n4#iVf9>Iv&dU`W
z89C=noV8i)T;dAG!xDxQOg~KO)QIbwGqds6j1!3=U7y*G@x&MyoD(SAQxy4wN4E03
z{_@jy`j$$2pL}j*eYpJdsTqkYv^m|UR4PdH<&_uQh%S=tpRV^S?xy%uuY2oQ4u!6(
z7O&ZuQGNB)G0BJGtK
zPrKI>mRY_R-D!NZHrnp`l!poD))|!Wb!+c=#bWK6wxLLGtux>H5Ejchw|cKH{NLfW
z)N@MKHm3v4S*aO)yHf*`GCZHH|KvKa%yq&(lZmH$`cBQ^iPJjCz|+e=TXK=>`K1dS
zyLxNH*V;`sw~Sxz
zVau<6dFRK8uZto$a?Y!Y<%Zl$y1G!a@`&%zrDf(UaR=s>&f4hP^;&E5gV2-e+1}GG
zezo{3bm354%$5sXd&O>D$V-&B(vfks-}uV>Lsu(jy@-y?F~RP8v(tHfqIR@sGGD&*
zNo#7U^evv>Q?4z%v|N2vUc&iq-o-9+3_r|jytyR~;&{
z(rRzN;XR(Hpt2RU$G5k}t=js|NM<$fB&Wq6KXE^LyQ-jD>GI~I1z~fiHBYSUh*SKK
zyWOXG`-!=$B=$Si&-H({&1#*j!tx(w2Ro9BGTi5ETYE+Ac}>2jWJ*@=>^4KacBk3T
zuRrB^T2$1wrE>PIYa6}KUU1!>D04(yYSz;u7rtKCX>YqWVUBdv;gtLR%qsksF6+EB
zje5LNbVJB{Bd3-7QZqDjB_CR!T0J>MyJXV*$?wHi9G{+XB)sK|>BGkQx>NFZEtagi
zz2i`7mik2JEz57NdAPTqqqgzjx?i*3C;7i}&X|ADr*vyu_=3rMD!BuL+GZ)sADl7m
znZMv0op=;$+?tX9i!u;!lvfl&sqk67$ICGotD$H{V
z+9>V9AL*QRef7Do7vtK+`nOJ)b#HyW)KhlTQ#WVKeDx;IvGz>KGqx`+b=>Y9kroU0
zw=+*Fc8YKH+>+e>evx9!%MhpKTKC*8FZjo~$oTCqE~)qT10OKETv)aABg-p~e?G2%
zTctj0_dPV<^xspx&Yi73fu(+BNT2XdH>LT@TuL|1DEX9mb;cXFs>rD#!PYaUESt2d
z*(|Q$T*Fm|%8R^#r?Z}th
zq0RCOPDf&@?E2NO+Uv*Kod|AwwjZ^Dd2yHD8y#i_h68L23?`uRX7Vm}srt~n!9sx|
z|6^Umue){z1bV^p
zAk%lw9ZwJB>b>vS(VfWdCbQ%C)j-DjWTkh>F)iHu6{|QIgPELoLX%f5oAsDSH157o
zv+WXf(Y9S3t2B#u_L?4zm~j14N}>CgmN{{gc&EPScH6ykUD`=;(=Th^o}9CDUBns)=jkXd33J|1Z^09e3c>y_
zGTXAa_s7IP{uW4XY~Z^c!b4|cYst|`dUSJ|@I`GA)5ga7+9ot;0-%B^KVkYMV%v4
z%q>;DKeWE($&b2uFWO4z_@#1r=b+EK^_!Ac^c;IOJzSznZ`Sq})!L~?BU*fxt~ueP
zv9jcRz~SS2>Mfe)DgXJXxb~6m#TVUQtNnNRyNR$h`EOq-KdZxwGs`+#OZw>MmA9Xn
zU9DVrXG+Nrkq4~Ku}{sE5??JWy*a~#XQs!Ez57C|rc3!-CYc`5k2o#4xQVYy{Pn?l
z(G4G~S=zL>a8FuN=)SaGeB1XWH!iqjPfh*PllEbC0^@}yvq@$3c28O#=x^CPIp*8*
zz>kdI$~z{6&2$eZwoE>d`T}8=4u}cgO
z{krHotJhdJr10*lj=zp~SYP=Z>veKeR>^J6+i-dJ#R3kECl6;$_j{07$9=y$Y|_~y
z2b_7<2|bqME4F-bf2G{R&SmwenM#G>WZh$a28IX)1_nh?rmBbZ%hyJ6R!AQ&t?Osm
z=v`3hD5UzLB~@00|H7owNz-yBE>iK><1%52X5^&s1Cv@cQe9pc2XLrUu!L#)hFY3L&%$NJ6
z|11CEAAie`{|-y#t6sR9EH+qqM()-T)l`*#R|G-}GxA2n}
z|J&zLIW6HU_uO(;uk1ZlH#I+~a_xe9^*qZzS@H9Js+wwE@#6KKz^7HM=A1#zr+T%_
zHNQx<&bF0#AT~8$(8x@CkL$ze(0i*snN8ikdXMwdxrdI$I#sVem8*4s*{8gz-&fS^
zK2^SAPqa^`FLX3X=E@?2*6yGPJgbo2L_!XIa>bpNGOe8p(e$#of*
z%nqEWf5Q6m&XapnY}1as&4}3UE3lfqn(zA;xwn?4S8mF4ef!q1_O;yKHTQ%rKVGb>
zc)RPE`|TN8)@Ld%U3>g(f}FRcR=H8=7XEkl@87J~60vC$WcTiT)wy!j`u*P>>eDq!
zRy|foncmfLa97{GdGpToF=kkp3cPvuMpnk+s_dIrTy0kMhMVx|lSK{_JuzucaK7UhY$H}XSZV4%+;U;-smK^h!zSdA@mB#UZ
zcA~A>lITFgvJSm!o%$|?^-(8MW@PAP-0a_c_xrBisfosRLbAS*$L_qDl&8N|+-Is{
zH2?gU*M!gIUFldX))_c|qO|#&X$Su;Sge}0?M?qNo|TRll?4-}f>uuu)s!%tRA%z-
z#VW0sZk87|;$}igLfzS$teOjNZ+KM2!yV*#_?C5+MPx6>e81kFjw>4VmiPFMe!Nn#
zU$JM+2H)uZQpt~j)jIx@1W!)-A)qw#>;^t#)ewb@54>-prsbE3b7|(av<7aNu<*;W
zn=dCw+9ls$zF2tJ=ceW3gW+99`z4yg
za{B)7x+QXN{RhTYel3}h9}^C>7uTN&Tz0jXX>;bf&*7p1PLm6x?ZXp_y*gGpf4TKF
z#l*(k*i4l7PmOw~$cL8VWR?DoC&+)#
znY}R-R*ai>JY7=RFeCfqnZ|fymEvjPCwbO7t$AZx%P-cr+v~!%uTgV%iFR|XQ?0Cz
z`6)N4$NH1RU8B_(B4=%PQmUCg$Kk}T8Ci_{4?}#m_a2<1eod@D?BTYh&mRd%Uu9|W
zn;};ASXV&(bYo^=Z6K$dqqNZ@!NQV|6gIvC*UtGp&B!yJ+4!i)c&7iI?AAb&c@t)C
zI@G2S=HMdM$>h}M)_;NZqRqmK>@OXA0I#&M4;Dd4WmbXGxJsx$L%+{Y2b?d!O*sINYEOq~=y2&n|%-(wo%pZm)
z7HsBOa!kGcr-CQ4p&iK%AY_ZL7C4v39
zzl3*9HTmPD9=rVd%u^}d;YoRV_BUe{jiC;y3(5AFd{VP8tTKCt|$HDvD4nx?wAV5$AoUSy`(a$BCi8jpjLS=mD?-9O-V}d`QTb^sRqw>m
z$nxSqB>Otk^d|=jO4BUtyaUgqC=^@OS6t9mcrCOce2xFMHU7U|Usu2VtjGkn>xVR4$jZ|3|5!e9xoGH$O}7h6?;^G(0`$
zM2z=z5!;fPeE;{~U3D~7&0bpFQG7$!AqM?vwmJ_|dG~vB->rxz`@;X|E)_d1TY1j0>2_spz%519
z*Ar#-a>Z$$n7gzxPjgRHceTn9rEO*3d>QJvoVKanm##ncs(*WTqOaqwlPkR*Z2nMF
z7E|%?RKU^daudlpww9muf7UX!7fsXAa%!vN42uYTlhm`<{GY^5Zq1vYne&Uwv~C)*
zWgc4QTKsNaJ0IuGRN=5IZb6zK90RIul^<4Wy8WT3-}K>(nIi8KlZ^N-o_+t)?Y+#O
z+~OZ|xqmwSSvA+X-bYHzZ<&mb$MLDk9~OR?p?Dz3@&AIETa5SGG3>Z}+0|~v3t3Oe
zM>7OM_uaqbe*7t~^~ZUW%I#Et)JLnWDO=p|C8EgBF6C~CPVyQTJHab8`#qDQmzi-b
zxM)8AY-MQUWS4aokFM?aR@ltdlDv6+WVuLWam~G1HJYE}?o7Lz!FR5{q#>
zUFQ_mJTy7A_Z4URR{vX%en-b{lgUvG>P+{M+-9-Jotk!W+@`$uFvp
zO3$pZdt>u4sC7B}p8gB%7wcFSJ8IP{i_d$?+k5AVjcbi(S7nINv<10}Q}Y%czmR>x
z;L_tSfj{SNkI_oHDZI)n#a}~vs+OLG*1Q(3kEs>Thef8En8Yo+)b{N3ldKOr^@1Z0
zo9t|tp1sUtr;nDzsr0Yw)m&@D+pk3{mTQMzG>h`N{cw-$mU(4fv$v(GJkPl`VRL5l
zo%+1aH?}IdLbi!>xkL6uSzWuUxmGpm<=2>nUDsD0TK%wc?y6-gi)Jie@ro;yd$!k7
z-_RgG>8ls=q8zt-OK&+-b-YdeV{@C-!)N`MgD*@iEM6HCd3VaPSteKIas{ftoy#**
z-XVMLokRV6kvHdcPUfzgHE&t^l1*8^SZal|?Nz55*3WhNe{;>IOPilen_m*WvpxE>
z)cOmHOmy=~{Vz{?n7K;2?a|WUEo+WH_nW-_>eUM`ihVB@{it(Y{iwJy{MQtdwV!ro
znIF1fdhYW3;-xQ_UE6f4s>(Gt^k~N0GXI}_U7uv9?lYP{YuW7f?bD~*_#YFEn!fDo
z{AH^87unt)Gr8)2d0Bm;{u1-J)vF_d>f-JP28L_SpISP#du8UHKQqryYSTRbGkxCT
zr<2m&tjPJHwX%1?)zCdYjOM1luUt}nnweFZ_$$%artuH~7xKZxXhf9G-8Z{zvcdtqNLU3nI~?8Ub1wO5a}YB+VQ|5blWwPIh_
zy+zwoZ|yy5_v2@7oZ|eMEspHVBkcheKal=j}&E7PSBh$LUMAF5i-Jn|J
zigl)hX}!7Za)Z0B$|X#t^+H=~xH7BEFB$e^xV@-6Q`72}IqTR9UMps4p)az#rtk9>
ztL4|;*UwTn``Am_uEVof)-SHE6ppNyQJB3wplkbOmiJ6e9e*mtDmS&(O|$DY<=S%J
z|NO=D35lF9esCtZS$>(f^!%ddjo(zheX$8m&~vnJjZ^*hiT79LFUgb})+NTZe3L{b
zhTg1kIe*gqi_y=BL)I@pe<=>(lD-iceeCuN)?bwsE4yaD5Pu;)aqc3IeV(Gm0bwgI
zWYxEpX@6mD-M8XGH&?CaLVfL$polYi4(E8T>Yq3|>GiW+k`n7ho-+S9o6yfX`H9a)
zr)Xua*g1^bu81TT{A*x6%VSolEL(YXMb~+Ez5{po?YSkg<}JH>m^bs*;f%cF@A>|G
zdvv`o{tms1
z(&Al~xnlXr>X4rIC5bjMuVnceZ@kJ%J0tIX`QtUC`KQC%P9`5-+Iw&Jr4lBd07OzC3%=H+P<
zY}d(fvUnby^!m%L$tTYzsx;N_yeWN5@aEgz1#dHV`DHiE(VkOt@aMM8Y!TTe>7Sk|
zZOVRTIWLiXO3F
zqL%sI(`TP!zExSBw3kcLybpbc4(Yw0vBgYl&DVR)+pa#fRhCP=H=|<5-p8h^cDz$0dIwe<|c6E|l|vmeSoaUz4`NdBq4m4!Zkrrnv%fBe7s6WgQxTEEn)QYUPl
zTPJO6Zc*=^^)FV2tL1dO=7Xp|i+6YJylSDscjP~71h2vOKl>V;dU-L(Am5lGgR%w~M92CI8DtUb?lqv?g;^*jZn{C@t%aQ`x+_a-3wY`#trZ
zbF43V`h*hQxi_TOmmSR#J$@&6mQ%FG_H7pe5-Jw*^BBMNS*=ph_GRT6gTvB1^^EWTJSh>YyFw53O{#|
z_$vi|?lR|B9G-sV-JUk?vlVfW4X{8Gs}CjW)2l0~MM>OAz~dA0oQk&i6XK8o_jU;SX(`0eA#
zg&Vn*e|~((9h~m&_USxVNngB?{_M#5+a=F72k%R_{QQ?`t@FCzkG{v}8@^p7lJRlv
zq>|PDTwEQVu$E1Uy?xGl-xs~v+mw#6>m2{o&w0e?XU+E>hmsSzK^t=K6g^p)mFZV?
z`Pm%ZskYk_ZW%92Us*g?;;Xn$*2%uz_iD=S8Fz0xqgR=>Q)lm+4^x|B*G5c#+L3zt
zpp#>Ln3nLeYG(e7xb#nn$ns{X_3>+RS=gGsM>4s;=zBmfX~h`>SKG
zOfH_DaxnbVlc}4Y>KY#j+?BGs)wS`i;$r8$t*n;|m&9`N7<9Q#)!2E@S}kp{xR%jo
zC)3~m`t6y{o{C$sWbww@OP^lMTpg43-DmlWX@`C|Z)>l=mNWNeiF;|(-P@*@qm?AM
z_@DUZ>6|Ru891%|{oAhxzLfkooZ6y!Uq{Dp##0BM!`Dq~oDZ9u)_6Ol|4g~Ly+i#_
z#;IB5KKow)Z~D$U0TBxl2~HxYCdBW}d5E
z?A9gu##2vPn>BR{)C(NR@m^RcvLjzw&dvB~*j}f-*M7h2J7cGsvw%OGSLTQ!^Ii*;
zgf;wU4{-n3c7S>I?)NTNH+5e!{-Cr@vV!xz;ETU5v5sfH-fVScz8}i<>%*qT@DHmR
z->-c7yJG5roynhlt_H5%8>Z5D*g5a2-ZI(i{^B;7zl>tdLN8rD$|iBSUOZNRt-`E*
z9=9`@*SEISB_s$fXO-I{t;4ExZ&IWDBX_pCp7|0LQt2jp@*eQ+(VQ@YFWu+X-Wg$y
z|EGLb@a5;?-ZUf5NO%58PM`H#W2|!iZF$c&?}^4Y<2|Vltkz}y*x9(fFzT>A&mW=i
z$P3nv>$|tr8Z)teyCYoG`+N7+VCDMVxA}T_<9zfh-UY3g6fu`mu*T{{>5Mhse7--+
zTr~0Nl*mU<&-r{WYqnl@;h{+9%rnm;7#9<30IjXK0S*={Hl)tk|^Adh-78vPEFSGctKH?zrJaSnU24%eM!g?IbKWaaXp4<)X7Tt2$%6
zS3T{Q2-&ja+ppUe^}Cv$IH?8aHgi}X@KT64QNreBO)ph^Kx{x03P?Ol*
zop;}_sap~9Wu5uncC)FSQs2tnJ^uHA&7AM9Qm|`mT$is-+o8?x^BiR8e5wjqhyaAx9F_@aQNf=
zKUROlk8S8G6g;@(g2h^1p3Ac*D|PO<(Hgi>JoypBd;3<-DpO6q$ry97vX
z&v?t3@nwPAY|Bd>-E4h3UN0{dd{b}NpM2zE-K&30nZ74F%BoBcc=-P5-8WZZRo4&h
zwht=yN$r|>Ydre`KB;I1U-;MjSZdLqyPLb_W?WpretfypqP8V%Hu8%P>@Qq&{*uAA
zQ+k)SJ!Ni|J6y51Un1p##_}J>!^8J3?_()<`0V@Uekb$N`)f^uZ5GVuos`&O^YuXK
z*I2#Pr{_O67W(qUJ>%`pR(F{HJpAPUP&}w8uia!sN3(xSoU0y-#@4qEpGlz|h75TgFs%R%)`GB4@oySx@7Y
zDc)QnUYaUfjn-p3lXuMH`SopPJZ!q9339V{0$?WO({ql3AU(SuGyL-a0L}#bpQFB@Q>|3FJf8T%TJ)6@jHE+Aj>G*_3x`
z(f9fImJ*U(N+FpA+a+&l1xOkKdT%H>a;BUyRTEOp$@xA#JwG
zeF@iFwIsK{65a8@=*X;I&#pSHs*A@B3jH%xmK^g6rdWF5dHkaqjvrFytlF+n(i}P
z-DT>eE;?V{aLe=^``_+NxnQ3t(SLuhMQ2+1%H@(1^PFbfDttbJt1!cFV&bbf-PeAt
z#`pJ5`E777#cbY%!yT8Tvs`^-q(co$g4OJ<>N4IdPSzDXbR>Q04gU_mnSp%1^BQZp
zH4M8RGQ2sc+?7?|+rY>Z)R(}~|9bX*ma`3+Yro3m?)-W`Kwscg;OYR_9>CVtio)vJ%p3m8?)
z+sb@ZEtkKzV5K={(Q9_4LsGjF*G_+wk?{Q`@?;G!gCoPtWHa;SoD2-SVv{#08`oEe
z92fn^K6lIVt4a%n-)7h)JE#Y?XtH&uDRO!iC^#@F6*N5E;=x|NJt@C`l7+3G>d_^)
zIxh=b%Le&v5>?o1vG@C{FZY~U`gW92IN=~j1`j~Y`JMsPG!`V+hM2UWXT*?*q{wl|PF8^!jd5MZe6w*T-G$^;WJp
z^83l3zgl+n4g9N4Bt#tLkPG@~;3it*aWGZ%b)oCg*d4Eqw?A#`|M4-9Reth(`RU#B
z13r4ztm2w~EM3G#$*Bf8+iUb+*oHb?1>u
z$JUiRnvwYR)$vDdA(whyef+yibn<7Ni|PEwf|$IOmYH5KNqG6UaPiBYrTn~-VZrUj
zwhzvgz1pbK`$_eOwt;cYiYxUg?z{4M1=gQSj&wMylz&~fF>AVVnptl5QQmc7{E=$n
zZ)Z%LB*J*q$alA{+r2KuyIzuiB4(^lH<8QEG8N{uy{X@O_w5IP6-HTV{=y!45z%`V
zK94zNCbYYF(IK4szX4GBG>;R^QRt$6j9Ys~69f
zpZeBBc*|y`JU$+e)aO;MijQ=P;(e!Gs=L;)EO+vs?ma*FMT$JPZ=c^Qwa$`j-?;}b
z{{B6hC$K{^Mqb|Mbz}pmwAyz`@%dLeVF+>%s%@V<-PhV^=*;+Vd06_
z5|o!d)Od0Ig3EHJ!{#4#f9?MfVAQTw{6UgylV9=8Y0Eix)J%w6@bLDJzNYtCKjilL
z&kJUHy8KeT;bF0ezx6WKy!Hq9P5*G%hkX#{?SHiV%%YFZS5_`(lXT&=KYU*FkJDlO
zkJ`M3Hm-*S{4y;Xmuvml+IIiJcBW#RGp{B+wUB%MuuS}1z|*Oh7Vg*n@<8H$-d(vI
z&!s&qn~zPZ*+2cTJj*NF8QV97EzR*;vVTUwI>-7W^I5k1u~}5_`R<(P)
zH~Ax4fB8eX6XR!av~)6%>z%xK7DD
zq<%^?a3QDbkD31F7LH%8RQSE|Reu|C=!C9Nd`Onl)TkeQ!Ii!toW2RgtLOR5DqC@X
z!9>nB1CgoE^E&=<$(pYXxK^*Ocy^wTt4nK4%tl=b#mE{wgYjjrE9b+*NIK>cW+3t
z2)ppbIWF_D=ApGW=ViyKUY}Up{XBHp4c1<{2}g5RO_mgy9=_RX*|Q_%%Pt)$3X0lZ
zA#-;|__Jp|yEcB&+oP(Ta&zfv>uG6{&V{k}#Mg-Yyxy)Z8moWi*U8+a;aSI4`mHVX
zU4GH*v`PJI*V!-kF^KhP&QJ1KJEL~p${Fd0BVO*)Ykw{GGp_KxYt5@E3;Naz<$wEn
zE#hZ~$jMmMVsYQ?74BvtVxKv)}UC{Fk*??B$ftxzRsc@&9y|4~iWeWljm=>A?XrAfiF|z-BRNt7pz)-Ui?Cp
z(TrJ+UoCdJOfgBiw6XFj4^wJZ{xi#ob9zUKMCz2!3MDei
z*X2|MUF~D*ro^!I8OyNEwQF$Hm{Q8VzOP;K_~$E+Sp0m(T3a=&g|1J)MQ@q5$6({+VHvb
ziebIiRQ-Kx4s5--WmVFjX*>VxiK$-i+w){q(H|zK8wTI8b4
zjR^;j{WgdeVxCl=Z)8GjD;x;hmkgN(0XOu|>YRcjCa+g8P|s9-#04=^s_<&L*$gx!V6(ylzdk=$dMtsa)^4N;O4RopMjV_P|b^zk#*4aTU+DyWKDI
zo>;y-u^@PrZIj;1V>X-i1bh!((`b2SYhk%wLD2=#C^p0Pq#ujUc16w?4Yuui>#}~~
zio`b>edkWv?0BU!Cqc`5-SYqZ;10*+dwMTL5W8e7b3`76aWF8n2~GZ}CpEe59AEw1
zh{_s~a?$_)HXYZQ%y=olNjzhAR8Fz}L#>v>PELloLJEp4EKBCT;hU|v+4%JvoyMww
z+_mm|Ur()?AK|+6Mvl|PW4|4;_vT*=TkCH7TK-$GYi)j-`OUjJnuhbw|2tRy_ulV)
z-+%j_`}=%hJL8%|_RkWTb@C?N*)u_U_G}UJzWN@qC8{zL1rK$!EH+A6Qd!jFzP&v4|lx=No7~kt>H)VCZ+`T+6PDa2Cb{uyO3-HI+PM4mv;4jOJWMjRb$+#K
z>+7mZoQ+=oGZ)VK=)o^IqcDlX%DF1*s8{3DrCYYl)^s=JS$2EL>|L8(AFP{olY@J1
zK-M(t*Q)Ya%dT#%X8p4^tY^=@4bJ9U*Oep%Z2rEYS*HCIAK&S?tJf;$#eVs$$vUO%
zvdYJ{SzehYd$XoZUX!uR`L}1ikn74t%eGnU=z2GCD_`ctM9%poss8I@R5C1Y{#>Hs
zQzmp$Q|4z9kGSLFqrqOc%k%7|u1>lsahmh0+_jwkntdxXH-^kMO_G`>rF@L>P?VSL
zlC7f2zJ+U2+RI#wIr>X}aQR!km7d7ANcCW7>pJUcXLhdN)ln9_(0ZG|`#*B-z4d(M
zt30Q>9$Kz4XVM3TNbA%puS1!Qr;E>(DDNu%ut6;K?&qp6J62j{&c2d6*Kw+u~Wzm&D}En$hF1`EHL?Sl5CpD=nSFd=4!awdpWqy}*8@TCbd^}AW7i8z-;N0}$hTARR>E@IQNS>(D}
zcErK-iha!ULq8a(iPrSZKL7ca_y4gc;d`OV0@%yTxe?2vrrolX4{7pQ-*=G-6tf&EY5!O1@+H`zbd
zcZp$|(Xt{;JNL*c-_tAoW^aFeGRtd0*6~GtCY&w1Oifc~>Z*KQU-Mx9!}nbC4lOxw
zDf4~la$k4qCCSxYtDrSJT!b3FmrR(?8w~1Ia%D6
zKTRy}g`SDFnzppEJ9%dNn|aBa?u%F7S$?zZAM3_$zh@VInwU;Z|C)7ePvyB;+=?4l
zwD36vO-g5bSXrpKB%q<$P)|eTOseV?|NG%W_e1w?^V?qN`;d9zwja4utgp>VFRjmb
zDN!EraR>J`rh;_+88;8e?ptBd)slF0xo`C8Wx2CEzk!~mF^eg1y>QyK2pBHsmG_mbU$n>%)S+nn#
z?4HADzJal~*f3#1$xppd*}YYh{>z=JzI3+bdVSTl)bFY{CiVaD)~vK-m5w-g?Ei1c
zw_S^vODE}=`f-NY#V&dF%5|Ue9_{7c(hpTbE>HL4K4HhAt@T5bC1Ahm?aR$4-oEsG
z^6iUGQFWF1Me{}db=Dth9_1~+$Z$#_us$~SuY^nNVTn_(q>evW&HelMgZ13(#{^bz
zvmX~&Bi;U`o*{7B!?djCBm8TQ=w1oCDCOzEzKfy!$gCHR2mP6DDckOg7EG{B{S?{q
z>$RLqB-`h6PVeO1cbW$q&4}OGFpEd5@AB^HVYQMmW?f&uN`~|;nkmMjUnSkGR#2IK
zm_@8#$tCvc%F7W>e?=u*I_om$t8e*a=kZVY!*8?8ckCNeW9v`58``YqJiXi}<74~Z
z$iO6~@H9{D^-4|0c-E;c;#sx#Y<5J=je5589~IwxUlMzJ`sNBI?Wj9K{(k-n&xYI#(}X#_?@kx=O99mvbCyoFi-Z$=#N?4J;ZkBJ8mgOZbcE8ha`$(qhsPYZ-Pf
zMDuR~P5wcCUniB>pImo5PKwp@Qr(w{xr}b5V!urv6@IzA?m)+m=|$Q0ALYcqKVXP_
zbNKQiA^ii6lZxbc*F9m#WENTU{ac>0fBlLrmw0|Mee>k-d{M{7{p`L+nWfXA2dp~N
z1f~j9v#o7cHTlcU{;!uK&{5gUp3^F1@5P(1{pRpb9^4p#kAB|ZnWR#~#K0iQ#=r#K#aVlf
zquw*GxFj(r$2lW4IUBM*cgeV|U$k(ydciRO21370oqE;HZRWkD9B#
zf$xXBh_+1|{+`HN{ZBc6#|4)~7ms-B{|P*1yxBY2i`T^W{F$3`zgxb)IrFZ4ef=M%
zfJ4g6g-=o=`~oyid~jH%ZPis2V>-dX^SD%fbKut>`?TZCvYHaN)Ev2Ad^$5iUnbmU
z88`c#!rSw1i0wPSdW(|qnu5x`S#P)4ERS0nTD7C=U`^=v=sTs``C4n&T-x?x-`z~x)EV!ac`{ZxrA4>%g~}{zdiX>1
zp(T6Yjr5MR;`b6k*1CD}`JdBnOgR{;&b|7mlCxrU>W&mwJF(pjlUQtcQlr#MH!`=_MxWSpmwB6#qFUagX`O*F^~Q-xsfQdc9T9o=Dk42%
z*CJ(M;T^h%o!d&T-=4i!IdQv$+W-E**&zpc_6BlReN;N(!ESQe!`ehmL%n=~u-8p1
zlUa<%{Ew7J{*(T4-pka_Q1AT)&Y0ypCD$C{J!+6LxtXKVtihnPPhdyq2{z|LdZ~d@
z$5;IEsQW1rwXdM-#q@eUHD}cW%NA~wRJoz!c5{x?ITj@F_T^>Z~Jq@
znPRD@dqe(dZ@GVAtN(>X>LrS|9+z%Bo~^}le{ns}#3#nnYbM=$`oYhG+cw
z$F_4M(p1}z6wlbNpl1A+KW9S)V>k1Wi>o`|mzV9){?~UR_0bd|{Zg~t;d*EEgxP=3
z2{mlra;x@NieQV`D|ys(`=pGiV6g}TgPtw}g93Q-@!4~{^=l(JYeKGGwO8M~C$U1O
zv&A5X&qF~w(VZ!2vVe*Nld2Byl~>-MCiR>Vy1&PeGj_{b(XDIOMrBv?;owd@9qA6r}+FQ`{(njpSSe@+3g;(moO$UC
z*QXr2;8_I|o`1NbAp2nRl9|g33nwi5P_r<8L7``ZcXNsO^voE!B`;$Hm+amdR3&yQ
zdg>nCOBIC^4#{wR5{i>rVil)0|Mb#G#j~eAmh_zG`=HgkI<=y7!oAbkOFqx3XIMY=
z`A)|=_UkM=!rWfD{3>;dkYAz{C;#B{lbw!_+Z5J5>6MxcjVjbJy*T7a{aOQ+(A9FmsIW-sB?IH
z+GL-N$FvJ^hvcVl$_u61%PcWJ!W(;O&%yAFKZ3pMQ!YtA^1R*Q_IlTuZMLtB^P)-v
zm1mkv_NiZ3`t^18HuJpQ1+mVbx2@&fdV9NRPTsBp@3Y%@eOP%UfoonW(Kfx61EyM*pl(+i4f?=0=6~W(gQG
zzwMk?VUoDT_-vVSPQ-M%>7l!LcduqsIu^C~Q02PYExJ2R>SvhTeUsb0Y|=#UvtK8!
zh`f9)O>Oe*o*fHQRu?@Es6WJ+@H}3))BVj>pZA)T+Frys3M6l2knJ_Jj?(qOFz1Ec2p`CV8)n{$gdV{KyUliXPhP8W@A`{B7E9Ge
zKJGX4-Fsz=l5Fixu{*Oo7$TqdU#ePjX1wyvcx->1oL_yU
zY1?Gke-iy+rfyRtoA_Syc1rM=m!=%}QkveRW|Q@3*2JXsv1>mbZ@=o(zFtUM^IUA4
zQP{@GT74(3CG}l?z_R$PpJX8G)WVZ4r?QMg9eT{Gcb_%8ofEFyxT4u}g;d$`;B~L;
z9JxKz>)*8w
zsgCdgyX5WB^FA=Vllm*A=XdnG+k%fX*A-5C%{X6j``UeLgr_tbZsm$x6X&L~_8{|3
z8O4K>5;s{ck2hMpp}vb_Q&-W9tH*;4jc4Do_0q}Tt@*oqoB3p|?qloTIZU!&_)(ql
z>Nc11c)w*yQ4x=39lVoTynteW{7x#xOG
zXIk3H4I-yqxW4n6E4RMZx@o0(IAfZfozglw9$MDjBQuVRV
zoom|9-G7kpRlNLM`%kyI?-z;B)U)zGDSb{?^bmK~WbQ+6IgKUz)ZZ9rh28Era@cJT
ze@eaBw(BiRHn%?f^(9VvoA5)vlusLOcIR5&5|5j+^mTNHR&vCSvuni{M?c^FQ*Lg5
z!Txj1HSCvJ)kT!{mI-;Q9NM^Dz44s;&$!X()kRa;zqXl8mR@j(5~x5ZtLkA4(uxII-Z?Mv(K
z9`CaSt22)s-X{2Znv%jD;f=e+#ExHmd7!KHt=?g`%h%ktl!?oIQowDY*9V`zHB!xq5YU~=-l(@VrmAYkVXq?z^0&QIj|%%4
zZVM3MelE5n@k;vDhxLzA3T-9_91e;-HR1Byuc^_y{MLlUG0raN)%tdf=fxk{eS%-l
z8tmJ)>`|FYTH0#?&Ry*RqCDyMrA{0DQel1lC$=i^`TLKDt?J|N$u%;+WbN!s$X1!x
zmz?;4IfPMt)dIH#*2P*Mww4|h(x|l2p00oWXM2ZfL1oDE;}Q>lw=mSzuc}TxE>d)J
z&s@W~^+)`<7B64&^CQR7O;hKe^Y3=uljPsIX@1HHx3B`M{~;&R_LmAS|9HNnuC0FE
z=gpI>yN^Aav4!*0E1{JcySrqj?Cdz`GgtbZoL$EhZ;`sbdDQt%v^Y&%OhiOwzl?MGgp|f(G{qftKyoa|t
zw5sy1llb)5=4xiSX3ptZN!FHJ=QUPJd(Yo%vC3j&S>6*y>xmPcyH#E%-!=1F`;Tv{
z@`}lqCDL{ukGc{1C+F%zJ8u-E_svtb=8BDhGM6G-PC=PEzBvcm{5}M
zq43(#Gizjw1*4SVs^DrSnCaJT9-Y;JE
zsZ-;#ZBcYVRru+-q00h-mfr~Gx^gBo`bA6qb&;a4lU~R~dVgCutIu*~zW1(%^jY;@
z-s{d46qRM%jCi6~P+k1ZeZ`!{t6H;7)v6|3<2_kF)3hiv=K2MJ#T9Xs_ufr<|ba6YosfaOT$v$>wMQ?#GYQ*3bPX^LBm?)5Qe6=Uf-%Z$FMH
zYHyop`mFxbYOV0=g4e6nn>MUxzuoOwoS{EeXkx$97sg#ZGxUy!%hgWcdUB5OJ!=u;
z!g=AB?7r^lT6gR-&xJT=dDq{DHL-kraW>DV@?O}n$&qWDNYDA@?ra|RPQs^7^-l;3
zD{T3bI@LYnQR3D^$1nP++uzzbLvopBiCD@E_suIM@;|?fs_&U%Y4cL}i>K08HKUDH
z!Ye;rnSJ7^A`&C6ZeNCg}$i|fAL4f`%hf|n&hXSP>(%oz5c`JgA3JDcK$4P
zI^kJjHkX_6{8Fi}Uoua24C#N)
z<`pRX^@884rD3lY=P_*QzsK#cPkzJe*3NqUaJBahp4<$R^)HAg&Jn1n>)gi^T=w{{
z0?*oudQpDy2UqOKtG{OY`{il_lS5p#@r&1M-(0`Mxr99>Z_(!$(hnXTeU<%kc8U5A
z&WPy~%~-b8^?u6=S#mK}>h4*oyUt(K&c?03IPpNehWvf0)}Iz$rH2!n*
z6r28$vz=2~Gq3AmZ}S$ez;NBn%&&}5&Bte{W$fJ&G^aABRk){h-|fskmPbPB9Oo?^
zs$4yGPrvqTqHv9VSWnrz>j(b}@YJ!3{AKfHZV+cav|1rb_ntXJi{x{?W%V_pY*HH2
zFMfY1sKIb@Q&*mkwN1m!N6+@GDV{s;_eEu{>66nrJbg~H95d{#Yp`$YOyj;_dz0~L
zlIQaNNB@(*?AV-pprKCnm-7v?bG8om4mXEf35xsB$GGa|5#Q#J+mH6oe-&lJ`uf4w
zrm7z@>*DX*I6SwktYQ9SQ50~PG0NVfUOJlXRxSZU#YP~G^aF4RV3rx@@I2T^d~*a^<~docDRf^Zey^_((S}niEmgD!`{<)teG~`%V
z_SgGfZHUxO*eYzWizDJDbAF7Q{eeH~2VVxVyh#3Va`J<377c$`zV*r{##eA1_-mN<
z&!uvUbiv)uyDvC!1-~HsX
z+$Wh+$I2RozDsueE1vN^^1xrq)Si`m?OUX*e3wiQIn#B5(Wz>ln$VMz@3mis_8$_M
z^ge9bYJ=zw_viI$=Wj)d-r##aMbjbdOcav~--PgO*Jhu1ZduaGuJ}X9V>)lQN%+z4
z-W&d$j`$&ZFNA)MB)wiyFCmQ8cf5I)na7EnF8RAUmf^Sb@FMihi>AF|r)JXd^
zOYUpfcQ6T`_?$m$#l`%}YqJw3sqYtG>fN$@!w#2AUz@L}9(6q8_^JNrro(S0%BnR@
z*I+I)R8M=vzQSY5>IwZUS6(mAYdLhexrFo4i7ZJ&Gl!Fmn*w!P_gtFF^^^TYQ0K~d
z%_avs*Ug*o?ZCl>{wEjhy(AfszmVb6#_4(o&gDB=b?1ELIiw!s^X{c7W&`M;ppZid}g=f5zms4>dwu}{|Ztht`vTWkB*bnoR@eo2-u
z*B_o<$gQOCpKs-!Q=)8{|CgPV+S_Mg?H4L_v~5DzR+%}cId+*=H3#U(R8Btjl=tB4
z`h7Z`T!E5OP0wo
zy0tVz@%4A@Gt~t}H@x3FzwuLiexGq(^Qrth^^D;0&dCqYNp9xxnZzWH
zSUKS3wO+lKk%8eo69a?AWYGDV=g#v^zTqcXA9&mAu!Df@>?OTxKZ?CCXO+(qWj<=|
zIzh})LrbG+U+(RtdA*)Dmvz-IO%Sa4!2Cy}uq^t>DusP#&di)?T%7j(?cb-O4veQG
zml(`#Y?jPTi#@YDBB3CA)6|$#YKIGU9?Y*)c>KVjEophUmgmt4_ohzt`6e-~_^*euGIc~}3Q9dG&8n(;iP;x`(mx?r{y%!eUI9`$O>kxN6=%;!F|NO(3)mENy
zSbzJ1^a+EH+Bg6C?fc)Vm6LeshGx&C>&vZXD96r(Ec<}Zv}}1^Qen={z%Y@IfkACD
zB-(`Qr-r?(m%b`$o9r!BX%n~T2B%qBz#NAZ&uz09d}q&?a>JRs>e6i+XI
z{`dD=^ZQH%T>mE(*k7|Y;PO2b8Z+5L>tnz(NAbiD-`MK)=LsfyP1tbGTFkplg75rw
z)s7tpZ_l>L>HM*yrMV*PkopHt&iP5Lfi~jDmaE$IpZ7TNaI?-`k&l-1?DZ2l^gn!9
z)S=(;BS|8DQh`W3-(&4He?sN<9dn3Je<`gL$Mtx&PMvm7e)~sR&ihBd&p5KyV4wUk
z{vRK71@*Zt43eKrtq+RYoD+Q7a$DL9rYAk?RzC~z+^BO^sNlz;LqETq`Eu*iqc4YU
z9o_ln%dJP3oYKBEHJmsT`gGSMEzK&!tsV?jAJ;Uj({$dR
zT3NShcZOE$q+K~HpSdnRBPG|9wnXltmzHCTnn~>D^PCy|z3VtQd?ZR->iSW
>!wMzM#(ddPD$4)Jse_Y7Gi9={>JO)Cs!L~&PsXV zkh4B>+qK}3w|hTEbZ4oR_ zts5?VDhQ9bkpwtYJU^*PCt8YEu} zIk~IeKeG2Tr=)O&$1%w{q92tdGyg;!n_S^_OzT;yO_$Eyw|7q%)is5uJPBM7eeX=t zrHfvySEqaozV=hH&d<^FJKvmYnK|o9m*m~BZlAZjVKW@2W?p5H$q8g+ zVw2v@-Itf0T6%rHb8uU*mP_g3zIDL|-Aro_Z(JOAvd8#aZqe+P{SSO4Z~s``vw!35 z+c|o_^76P}?+~?nwRF5uHf$zHwiv+KlM+uuxVp`(9NROIh{eGZl>C= zUR*DE%=YnZu7&aR-K(CxwTY5ln7w6SOVW%<)vd=mCtO<%Ba^Oig*^BwWK1Ya*PXPl_NVs>%3 z#3t7APx}uS6ior5b+cG!HGh<9 zxgK-1|ANLv9v*TS87tHw9@v*QwnSKdz`KPE@@`FwCLB>a7IR*&YR>C$$p@x4$xR zP3!t1znFuC)BPBar{bk0?`Oz!cZV^~@;}m<@H_WQc;Sk+!<%{IZGI)o{q+jw@}G1u zSa0tR_Tc5^hn6bs5E4$UDo?z&^!l-Qt@#I5m-PAfxxd@h+o&TcGskz**4^6;w@4`j z9X6GDX&ZOccIq3m`o48;ZW`go-|aZzuK6topNe(vAGQyX@k=Mi)YNuz z1n&O6aN%@8pAez9&Y^e03*U1WckP&G>()72Q9H6^;(h+zs;}p*jecE!SoQiW52@)N zSt38Z{l^~r#pW@4NB;LptCKUDMV1TSR9XJ)Uh&}+n@CSS_Ic}+u5GC6uwko|RIyL} zv~l{L9)Tj|=;l(k=7__WQP5)cL(V3RowPwwNB05~?e zT>t#u?7zS7+y7(vptO&Bfp8$JFyj>ksRI)C0t_S@{H2l^H7bJr?oGN?Kcy*?)tD=d zIm6*fzoq3q-J^R%J~D*pc>J*b8gV4ZR_{@l$mybqJDOJ4?U6oET@l~KzhsBnMfq#V zBD0!A8=w6ss!_D6&CRPT>r=84-0k%E%B(VH?&YS&l6}_O64jKMcpp!jS!!}Q^2#O4 z*ahF35~a?~Xi&ehS>u81_OMJ_oBGrlzkKqNUAK#GnYu-9awMnj-W507=7{&ksi&r} z{#veME$MgbR#p^${;epr#kU{+2)lOC{8>)7@bL?qC(rWSepaYYrF8iv?E<3^jq4i@ z3A;u0e-T+`dEBFY`Bt9Cf7(vwzPQ!quz^R~*w}LU10|mg8>UUNH<6V z_1C`Ys$F`MlILtbx2P{I{Mwfm=PL_+R_e{1*Y@cW%d74V-7vMAt8`2!+}ytTTJ5{N zvhGV3_gr3kCONMClyIEIjT6n&3~%1qu~_w*6x3|4HcXmo%*)rYSsr%0D zZ7YjQ*Ile-mf)4R^27t>$O&texZNH7j`HTL+R-_sOSeYn!tXcVo71(UKk;b&a5=jC zhtJXHJC;7;u37o0Ub|-PBk3CL3lWuNl}x9kG#9*6|6u5wcf{$`HnZ;XYJH7oFSb34 z&{=#s$Gn`EPHCTj;&+wRMStJKHl6m_syh-ANFktc|0+9mGA4cAf_8zCG=~} zwolSMw!I}Ol=GuX>c{kd?Jt5-<;o%+)QJ8tRz2{U<5N8EgPjZOx{}4yO*5YRp9pXI z#G{+o*R**3cex|)^_I-ubj_4aa8Z2-H^Y|&)01U?UGNuaJ{tc)i1W|3?paT(Klpro z_VBOZzJ0rQf4CT6y_Y+6=FGpwf0-+AA+c1E!Z>bojFH+2KkP zBiCTLv&`QMp48RLxtCv1GBDoI9M)*P!)K{)!V&2&&kEP!nTiWaoTI$ozfL?|y8>33qe0$R7&lb|niOmT%m_#%AA1>kI zQsVRo^$~Su6}mq`cg|Cfos)L2R;$zURZ-jbf%(V69^-QEDXFt(s2OiI{yhKh+jn2j z-;dwVxPa-j)sh339wah7o0Q<-+U(9*;q%aDCaaPE2^-bTD-KR#J1-%@-X~w-w^-OB zclyElfVUm>&!%OwU;B2A?V9o3ucq&A^K1(A@80dZy3cgG=J&nN4=Of0m9MHhq5YZr z>p4T_x2ubVd>3iF>eaViC%nesh5poXi6e1a_&3a3XSwe0y5c(<_VVw!$n`z%{pV|Z z-({k@Q*BdCB5e zk8c*gsQa$8%H^=DtIn&pecSW*m%MoA9x86*z1(mC$90JwZMoKGYkuvk?K%Ja;nn@O zqGH#Fe&6=`>e{{6XXn?iW=lz!ad3vyu7|%E^S4SYIcM}`>QACpdhnO_-7ZnZ69zt()PeE9j0xYK+lx99HGO{-(i z7=JN8JO99$od23f&gA?N*<#?=QuwJ_L*6yIg>g$|N8*yl6L`|P4chD-7StCA#I#Gl zkaXLAL`|$}74HmthyP`EI(jVPj~a_V=1Pb^5`FV-abEE+kuTgLwrBhnJoB?yC{fzU zDROb|g=4}u3Pn}antik!-yO0Q_3&ZSTzu>eqZ7Zgw7-_4iDZf!XHh)wqLT{6D^`AC zILS3ZQ}x6G9;5XvnkyaIQYW}x(fR7baFTPvCLtBYW}EP)8Cerrcs6y-+A60|$!N5e z#q*RxsOkx3Q;#6Fn+|7Z%PFuj8VP5m{f7*Az-w{$KP&h}IT;vaCd(xl)_<=TelGcc zp6<^lk0XrOa(D!fHB89iVd2nTa%0A$YtCD9IuzGhdZ+((xTd*W_<_i*i{4zG~k0-*2AV?)~&$Jf3X>>;Fj~ zJ9^xmD|{S9?`b{GvXVAj`@sG&-ni=8#?H_o~Kd-DXYw7>+Cs3`vCtRNYp|DN; zq;~(-4>ITHKYM6wWG8*-c|;@knSYh6<&U}7JQA<`sv1{o*|L7auk*%-xs8@p*3CQV ze_}`diUjL@r=G0W^mr`P92aKL9LXB~;j2L0lnWd7TU%OOxNB%~2op1pnRnp%(3A|;%?sSL8eC&kLO6eT6y zf8fYpSSe{(S#bZvwA|b7lbrVoO_P1;*Q3Jzn|+s-V7=`WE(_K4nU;4q@!IMqu3TJo z(9Gy<=OfFN`xhK3J#b>eKW-Vn!#U4w3$H9W^Ja#jUZQh_=WP0JH9w^n>M zjp3%M_{5@+?QB~E>#v#KNnW<)jN)0NiuZDx?yigZr1|n8lbROK-1%F!Ug?a}eSUBC z&Eyo`>h&#OMWcT0&O5BgDHOZ`Y$7w_wrm@diGZ!#)TOwM}Q zqOR-YHccq|SHgo}4?#vCl`D?k0Ct!H}59-nve*K^lbEs>r(g*DE}=GXs}&NbZp z6ExiyyXWia*)Pe{+vam@`nAMaW-pgNtuo!_y*cNuP$5^wHH*mT=gQ4f3}ieweYXp1 zB%WNs|4;YSp>R>I35Uxr%u$*Bd}96YI|%`~Yr5~Pxx;2(8@fGd`7aZrw^gaE~^iyS$?#D!LFS*y~Or}}cPuAgE(wd?(( zYMr-Irt_`W$ce5${5n+TKz68%%XY5bQro7*TI(MFR#ADYd6iFh{puf#ae)($dy3kp zc&5s5o}Cx)QTf>qL*dtZk34B{(+}Kau=0^Q-?2>5dizwfuZqgkmuS4`YngBO^?51_ z`wwxSAF9HyYIdnsZn&(Ia_NxwokdE^YhFHS+ZK7)O^IL0`Bk%Niu3v6mZd2Ru`p5C8{6}@s`e!~8#{(tn13!lU@jZ4w z^bhm@DI37Qftrt<`6?WxWRyXDJ!44wVmd)BPiG%sqNl-L@+@JYzEYkt*# zf}UTVe7eTMB5~&OIp0?wx&7WTA|!H+(6t}?@>B0NRi%|qIW9GEOXbF;yVfmyUJ|tV zZ*}YT-Bz7%@0Y#$YbAR!YR3AS1Tpv1@fOckt*&UZ_`ITP@xDc`KGoHqnJO@6vH54K z<)^hPy0{-TN z)w#L9Z0?GMq8AL4*w!FPU9n%Ji;4X>A9OpIw~>0MRKnJ;i*tAqwq zU%j)~mTNb7oX#ixl*wv8?DatPjP$xb)%6Z@kN#P$qZ6jLIO;@%gRy{ekHxGD&n8}d zHEW{Co*-f0F9}voOMky~YVcc@yg9<*05@mF#Z;ZXt#NJ^V*7h`S!5Q=`5%j3pWyjM zC@?M1zIkbqWZbdKJk!oEN@VLjca!V+8qYavOU{MWTc(#!Y*#Xlcq?OO-JZ>o++Dow znq{>5xohzb$@2>ivmNIxEOWlClN7E$>7SrYYq~(G?1e^GlRTyDYZv|>JsaWlf2Q;c z{#2IR8q02X7V#ggWq)_v&nHP-?r7ew{nG`$J+OIqlw0I~OF?48H}67@_EzuZFOL~0 zguU_bTw~$9s=md0`l46%EJ3~pCkLut-XAt=amlImHoY=Y-3F^O@)VyRtv<1M?RCq1 zjdZ<*d2G2Qn&17kuAPACWir=(ba5Ua5-y z3UKF|VwAmgb<^y~Qn{I2^)Gf9%~w;3-c-bQyZt2d_bFBNS?fEze7w__Wy`db ztKv`BExPg~WbM)b9R<(CNumD5%4dC_#9UKWDv5rXX0hJFpl1uqVvkDakn@U{8FwS8ai?q`@>kyi2w=ahI+m4%3T}PKPh~_Niwe%Nj>k@L-=+HamQLi4m zgt;Z;t-{t{iZ|ye-0L~AI(W+}p&83#&pgi%7uo6}>C?KoGJJtz0k0`<Nfp<_@4=N801Q7H@7?k1A{E+P8o*DG8a`R@6D9qc*+F1)&+DAoQWm_ z14DXIVoFY`Zh28+K|yMfZb4#EVs2_lYLRYUVs2`&UO`cQL26M+W@<4rT%#T%*Jl2# zE+!Ggq}281t(zlQ7#QAgO0 z-nQ;#O*f>hecB8J(jJ{*dFcP+UDUqcQSpmP*6#ZC=Kn{>>Dz1l^aO-5PZ>p8K7UjD z?cQ_i-({a(-}kR){9v{((4gmgYR!TKj?Xna7AG*4i|Ra*Q@4Mz`Zw35A07vfpZJnc z&w1K*#!)W$u-zXzndI%>I&EWbt~k(n{>KKjBiSrzsk~#C9OtZaEZ1M!L zH+v3Vm~N<>ymQa?Obh-kXO#+_B%`l)WzR}3+I4Kop4`i+J7#X2>$K=W#?M6)FLb9R z)m{E7+M_W%O0xKOR{mf#l9$5`ef#|qXrV4X=Ph# zbpx-gaZ-A1xhz!S;zY5FyW5t}bX7iYa4qfpRoTsH8>6?c)!iIW#_=iSiOCJ&3t^_m zRb%c59-I_m?6WUo-jcVs0@FRiCr;e5COq~)!E)AKgPHaVr>?PD{AT9SBa_0s-25+! z?40E5n2^bJXZP6D#}jv=YSun)sY87|?JS8O9n4oPNVQqCAnk0^(n_Tj_xEj)wssM+ zRsZ)}mRV?)_H666cdCom>a_i-7Y*M%$!jjRzWbV#x0@DAfA^8w7EzzhYI8VuWre6R z&)?;5S5@#n)>1Rjd+aTmub}=|TeRO%YI04w@U9-4`wJQJS860gx2;TK->ubkBRKKk zvOW9OE^1jXx!_Ra>O;;m`F~GQ^_?Cnc+_O+ot;&JcYmth@o_D!DVZfPD}B3Rp;PHS z%_-k`PG_qa9{$n&i_7%diNn__>Rqif4bvsoe~&DUE`GgX#j5o#Rz`QcqkPYnntif& z%vmYW7NWi_`iqo$%v+yHRh)a}7v)cqcbYiab-rP2T+80GGHrUB1-~v-YppW-Am_a< z%8bwE8$TRjaKfL&b<0=!_<=9sq?O+^e?XW zTYh`r=7%2E`%E0`rP>bK8%gL_O6dztT`)6Cxbfxu19eMU`4^k8u^RUne%K|-w4>#8 zgUZK!3eP%k*_=$DR4E&t<>syOcKOdNoewkBM{(IBrGI`2cg$*L>6?TZI2d!I> z{rATe0Tn5C&KDB3`iWhBPdJXPzP5_vNLE)}PyLf$EB?B8%>MYyG3d{i`!BvIoZTs5 zzrE=l*A(S120HQ9O{YG{ie(lyKD4aazC=*-O0?ts90i#la?FKFzxxdy9RI~Hp?XT5 zFGN6U;vvSDg{a zlk}zca#q)i{I_;#G6Xg~w0(FX`tRqGib-MOtPJ}L78%KQ+aFJ0eW;$!61}p~YTL`zk-iVN z&3OI~a*^fc*utrdj9in~T$0?(Q|!iwR2T)Pab0C%V_-<aVX)v=u@O}9o_B}tA z?fIaf*BBak`srl;eLuzjNa{`BaX!Ur=A9*{+vj|qTfA@c{@efjo_(*c`^S3V^bfV3 zTnqKbH4=<-vR&n;MHMpUbH7|9aj)}%K)s&p2QIyC$Eh1-9Hk^BXZ4gH&d|SmiYwFA zqlzQ^(46&Mt%8SES)A-VDB>J|uA|xKZF$eQgshgWTXFqr$i-{DSLUSk zdu7bMyxH=qUev6XyHl4ZFI~Fu*`}42w=Wgnym)xe!WCiLcC32(=4W(e+^r{@5e|ko5 zzLM%J{WgArfQ-5EEDzDdw64{sXPN4sYdM@2WhxfpEuLLozxim%Va{9HR>pf?-}DQ8 zc6_t$!rhk`F29yq`8>P%)t0k2vwpqWGOK*uDUDM*^b~g{vP^6&2-}=~U30VMy?EzY zd#_gW&gopUqBU7BT7~C$_KHjUC+5hm+Nu6x%fi*wkEDZwYwC=ilpV8wxct?#uNB%S zZzW~6E;@LkD%-DLyi|E{edHpAEW7njjV?zmT#y!dI%LnnPeE%11N){4G5xM6m0dEI zFTBDcsC(B&9#_fNhKCLEe+XX?d7u6|_ha8O$))qmP3Ctky4+Y4UugOAbxdox|5WMn z9n>8etaRsQ(D@#%%Cb2?F(Z)B$ zZtt1Rm6y1^DK_cFaX!}f54SaaH(dOHxkh8*=3P8Sc0nHu?Gi7ZS`b{-xTVunp{Z$a zh2udLyU+>)TYmQ}0#z?GCpzo&VUn$2jy`%t_UYexh5KrkfH= zBcHBS*Z)u!mYMnVnT+V1&*y~ysLuWC_wMa+hU?8Se;d_UEa!XLv`wjKI`H#&MpZ|` zBX<*f7w<}UzjcZ#iBOFgspc=XQwk|-j$$L0U*7X3fpnbv$4?kAq&dVc8~ z$I|90y9FvvO_-JP<)nqm=WdRA!8IZuR)nHBFQ%@S{WGi{Yj+l`x#MW3%o zekS3bnAT$Lq&}s??OOd?mYOoQmu07(7oFIu{IJ5dXIqto^AU>x@njicy<@Us=PuSZ zl@%>W?%MhK53g6ynf?u#hKfrvzU(}H<4s5G#k{VQ?j2KuH@CJOSbt4m_2q+$z8Eau zE%`>FS#NpP2~&9`cmD~}OMkT~{Oy&SDZh&GW8coayU)A~wrzi}mt=D7bG`1Nljr94 zU)ViEMj+4jLr?i;r34$tCN~agRS$km6&`gjg}C0T*uzeUd`UO zsB~8cyX-x-Tm4)oBKeCBwZ0LUaB*Axduau|9|G1|g12RkEIGa^Q9RI(MP4aN_@mJK zm=6n2%B}o%wf)7a#vLvlr%M&jRTciMwyfH}YPxZ0RbbY(mpbuN)%uQ@ zzg-f%@e?hd7tSbmG?{K@$au)TlzYCfqT00$QhI;Y(iB8k{y$sK9pYeNn zK%G|P5x+y#k@psDdEn8F-ctVawrl-T1_p+w3=9k!43h(IC{Lb$nVq+_$C2xhfq?7( zjICR_CV#Awujl#P&j0@Z_1_;^HXO5Xkw|jsIR7lI_+D5S=jJmey;qLzyHqpj+Q!&x zpY%8{_nwSGUDwRig%M9y3E4k9+GTJv^Q>9$CCjpwC9j3OUIoeM zn?Bc7{2M-biNco;bN9tph$lR#Z&-N!MEo1cR}Ct^APsK@K?dlJ%_^d4)!xhu4ErZ9 ztoEt5-Jlx~An?9JbfNARR>2JoPE)%@xEwt{+}{@a+Uch1ZPyys`G>*}xHNku{aOBT zW>4X{yvC&HZ4yHN=bSz>Cx4%%wQ+Ubzki=Z4=9AGm?&TJa1L?eRuW2*_>#o&-J;F% z9rxK4EPaN3>@tsq_RN@~@KEu%a-Sw!|4%PnmPI^w>pkzDa4l+^b5?tzPh79cm$kZ) zr`1AzBd7H?B^^0g6>~MDcv9lF>o@=8b9>Lx-Prwot>F&gs<6Zi!KS5i*KSF&nS8l& z(iYXPJ#*qG^M=0ZcG|w+bV1>(r7I`;2BY7KYnxd05}XU$>>m=3^q; zW|?BUGmkZ$r(eEm&|@i7xh^;B*Sau8d8^ecYj$*HH{DQD-L$y5RqKQ7Rgu4@YBT0K zghVZkcFgwV(QJEIziMMt(k5HKx2M{QjFx3}9o#I=`*dHi*xXqx+XSD^oO4p6)hWTm zE7B^&Iq}QQ)LqG|esY9PU9my9o=NNZoFt>GXixWcl{tN7yI;$2>=v!ndqy_Ab%C z;6Jgfc+2|5H^q5sTeKy(-YH*{Xzl-ZLbC#&*WLH6cjp>+(`x_;I3 zos?KN*|TXCCjKn;2flK?`;dNR_Xpm2OaHykux5zopSVo%#J7t(${8~MGTi$b zFk{=kf6lI#=edSm$PiA*5nP+Y`BtZuA$sEqmRxoB5VZpCyDpAv@-ClpWo#EbAbaSg zVkYwqeHIIwy2hK)DzlZ=9(Wk`<&8yEe?yY7YVx`t6Se#7n9{FlWgOKHQ!G+{xBdPh zi36##mY>Wuw%u&yS=9V&b{=OrYs>ydzas`rANO@B@_oF~C0P2=s5|l2+e1ueJ-2^h zN9{c?m2_FWh>3wgjh%tP7*Zz0T@k8ZI~6jq_P<(pZ;|en6$*CYEREU)4P8pdTs|nO zi26=&t4Q3mCEarGyP0nn{t*15w{L=r>cu1c5892+#hov@G>JKR)|+!@&izYEE6@A= z`TBNwhP1-l4Sj*knLVYGP1Y^WQ0Vkz4&G4W^Lj?&iI6>2bGx%n3Yr}bI62vLwOW1U z)vas0UPt)v%(-!OY3+R0wkxvk7XM<~CT^_w{?W*}=;Uf4o8>&(x4-&E+dZDG7wI=; z4_Eo=7%MOSUeEf|nFcBE_kPL!`K0%Kh11H@PB)59KJ9JuT~%sOq>?tFMW*lF@-?4J z|J7ZN`?~YXY`3<58!u`9n-;AnZkl~{dfy7&p89+Pl^ttVKDi|(S!E;W_+m!ti|kWp zS8RC^%quN>LN@8B_{C#k&)>KHOt;zisMG#x%D+egSOwr{zwrabs_BUtuuSXqbpP#bIpqpn?){c3u<~*|I63>!fWmR3yZ8tb?P`QRJWroGMo5pA4_M5)=+-o1&c5$1u?VEjEg>^jgR;It| zGiGGS|I6N$Tln(x)2pwVW#c~?m2ZFR9M@pP^(AK6OWvjK4qrt)V=sivpSZMri~EvH zlXRbL>}PfA9FwMp@a{GFrsQZne{uKP!wJ$SCgv`9*=OU&)VQR6Lr>lE3-V6SGs5Dc z9wm2ARg%8Z&EcGFXtHSzpG32TxRKmtzOKGI^pQWpWw8hTnW6);YaG@lZu~;#{ z^SS3Gk9`f^idBYdZU$U=6u#t4?W%=gH^eTT>0FYv<%HYhIpMAGe3jo%x*zqQdDM2p zU1rI3u0}pvEi`#pk1t!IZ70EJB*j@4w{$j>&o1@3$Lu~?Ie)&nwZrR<~}^X z^Ucl8zuzvmUH$j-{P;R%gZ6eKzvPcByxvA_8%|7|te6<-CN}->j;7Tz@?B@Sj;{*X ztyb@Rth7&B@y?SSs*la=CK)!A_U-A>Ftgy2DVO{;H@~N3pW^yEbptHpOqg3soK%@vMEtuN%ETvHnKs@*5iFxkeh>eS^1OUzN3Y z-Q-(~^iNcTJBwsSSO>gy@=Mp@VV)LQ5^`J9ri|zGlOHXK7ow~8y||zl9XX9) z%T~>r>T_`;@8(Ibr}+GIe!sz2qG?sE;FZ!Fi}TZW{&JbL{R3Y{bjIzps?t6A6&qSt zIbA*;c=O3ijzb(<>$erV*S@KX=~FsYfAve6+??!LJ*LI=DzU12XH0L{ z*!l6-5fkSp3X$AT-FH1Js9Eda8d-5gLhonWmO2lI!*}^xVztD?|3??TV4d*1=xJxx z>$eSj)-$aCWiNMsHh-PFTHo>`8}0?WzWN$?a@DezU#n^g+vKj-@V~D-_4#T+PgYx3 zqXthd)2b}dyNMR}xh|ic5?&td%3jYgjiu>hoIp;Y!2E}1W&2+rJ0-1QyOwo#xS#TR z<%LClDedXy1 z-Ymx5fzu94M7wpxy7k2_-Bxh5b>D-=TkY$Tm?qb=M6OwuA?h%rE{Jo#<$eLcrzG(ir zN6DHE`WgR%CQ1H>44=R!+P7$}j`C$dpl^4}W+wg;VV?^5ar&2SW} zFkIHM!q;ckmHs6y-xtchdQdj~OkQXG(fDN~J2dCx+Fn z7yQECDi*ka)9>>4rFj)fJgVY0nXJ2>f7|k+>eAbaQ>i)eKVmO`U3y{Rm8pVLN}KL> z`r914RP@?GhV!~`-Fe>$UmyBxJ!yI{aS2oX;TMujb7J#1ZCY1<>%O|cb&=Z>U+k$< z;|sp{eAnI^))VHgu$!~eEcZ_TLFJ`+S9(8Rn_cSkH2y-%$8E2EDoIIvjIN)RCZKu# z@6#LCHay5(rnRNH@!g5#r#xm$W^GUFk`XC5c~B~b{dEE7()%lAe3DMF{r>f${{PM5 zH=PQHuDEt_bT7WE#p>PJewzFT)5n5-KTSpBxPa_mp+^6tCnr` z^wFi{clF9||2MohlIh+$)&IoWPw!cNKHlGieVO%p|FWPqs%qW@ox8xsz@R3`z+ek$RMmIN z)Sr!bSuPwZ@_(<{*(H}5y(en97P`EcRMOaF9hU97W{c}uF>O7blN0!s7?-A9YLb4p zyQ9k^u)w)c+$LzvgQ`3H|J$DbFt4z9wbyv^l3b?DpHHTLzjvqn`&ZTaKcByDXNdaP z+EaB$bunYP_YQYAO|vP&E{{`{^$X*K_PprX<>^#!)Wpcy*5i6ZXE9Usk11UV8<^B| z+@vN2c31zrJng}$6~_u#l#P;ZXeCR(dp!Gh>YW~TiH`?47?*0Q|vB__u&$~I2Z zJMFhkC0BRirTXYcnv0hnmXf)0#$|fqEAz~4i*I+UUy9ch_@>ICW5v7D-}#2MJn zv{m*fB(}GRv)29o|2(GfO=?`+w4B&er;XyGDkIOG=2~|+vp}K!dsL?Ny7>Hpgw>x5 zW?9OL#B@&G^G0OG?A7neZeQD0*!lUYH<#YgRIWuCVHcW~a!p$pdax*F(F3hCF_612Ca>LbY&%{cX`O=qR{Z$i&oECnKo(r%&1_!%IkS| z)*ScTJpCir>h0bKSKrXxu<35d*Mo}X(bIfnFUpjj*w)tDGB3b9a+{QW>x(qb^_n-D z16gBVglrJc7TMEhDs)d^$C4G>ck>=!81w0KYrPL&)WJPX1=lL&3*T-$=Mu>J`{S~f z?IL@6%SHBd-{slXBXgBXk>HZjz znnQg5Mdo|{h;h&jv*F@|b6V@}UtTsffBAu5 zncsgJXYLh^vRP++?oq1tv>^U>GhX^=zBswk?P)59?Y0w{Gi`S6u5WnUeSX!R#M)I8 zJ^3Y%@90kr()iW%JwCM7`5*TNHR;tp#WMvqcT7C{@RjG0nRnFKE;T&+P~GG*>t0z| zt#e(}hRed8cNRM;Zd{$KZM)^%1C!atoz?5lv20dj>^O3beeJ`XrMi}}H;n$hYWCW1 zA@$<8kL0R~BNtb8EuXXf@`BH0^|MOv`4tO<_?PG%6y><=^?0&ExL}I<-yfQb_nK+- zEmEoCS^C#q(5h)u#v6`97mq1VSmf(2(0NWh;b&sMyYyOaMaCrkQ%B@Nx~?1g?`f3U z$S>aUH$v&&k*h764?XY6F3^22HzN4q+=%N!?~mM?R;7N;+~vFM4!sNSbSE8(u)SDs zc%pja0|~8PtEXHrpK&!_>aWnld+QB;Yn=O~XV!M=%-1=8vaO~cJr)?+RC*-io#La2 zSCN6v_Zlk1Cs{bm+TR~lD3JTexumP#hI>`*%Si634P4hJ=dFGz<8+dh`(+KY6?3k6 z#VuxUk9j6-o81lPtM*SWHt32x9&q=3oZa&aDfOypn}0qk4(WCdI4V9b;b^)DN8HE^C~8tE34y{l#u>z8>_hb!+TI=^r@#`-+HY14*+fMX|LzsQqO-|hLv#wteRgRR)t zBeRYbTs&A`|NqlX9l7OmPCcAE`{3%giLD%4-#yr0e`%x5^DAMSWFA>O>&h1pz8@S? zf57&Udr!yw4c>ox0zY!^om6+Y@S}B|Q2m4O!b6|Kr_^lf{|p{{a^{X!ub+u0u0-*WNMys6-x-0S<< z*W`FtevAcf>?`d-g5JNLj<(<#z0C+{F(o<;y4Z2(9`4<6fuQdEUe$ z4;D;(7k;6xu;c%#f(w54_nz5j3}4t77;G3A z81jqK^(T8b$xi0DCOw&VB5%E@q*h12kIPNwO}rBoS8$$dmr$RTU~n*8{MwmW@5J)0 z7k%u_|8n_dY>#FV;OZF^xnz1RXxc<6n zY}?LR%F;*Mo|N9!$-5P{@s-K!m@C=S44C(yRGy&PRdiiwTKW8ilispVh)(VZoon^f zcnME<)LGu(eUGHg=FVAXIr~oB<4ZwR6%wECMNN5kqWE;F?nRCXr#A_PZM|UKy>4EJ z*RGTHc{7%H>hEw5+_bg4X0~{)p48D$|4Fxl>htC*o=SCoTK+`s@B(E%g=@PNb~*fh zU3W@QyYB}7R4aq~?01Xa%RWnJ*rIIZBiCtlb>7*vM-7jEShl|N`!~(s(Skn%f~FfC zeo`1C@g;P*s`=UD({4?=sBC7uN|LQ@LfG`%Y$bDy4Ehb3MRg>0ba=D9OR(v4ZTtCe zT1Vn9mA|R=Gi)oFCDp37Hz&T5ILs+Ecf*~(te5^~=HFb#6?|%5MRdu2(Y4DoZQ6YF z(^Fo&ox0?^l&xo$luBmD3eJls4Kn>bx-Zmgo&P3qQoK%SmvdIj8OLXVpY9xDsOF#R zIcMSKiw9)VJ)873br#>Z>}kDlRAALp?%f@=*`G~z@o&3(@M8Tf8Q$lG2cKV<)-oqu zWWLdXgn#Udc1vjZym$It$MOB-@l>Y6W_bojG(FWdoj#@Zv_Gg$Z1QAXCiA#`;e6{N zpKS|Imi0--@CJ&;^9N3O{QCdf%Tuj?H?jPF^|WZaOuac*JC zELqVqvz$x$dnT=W+!lXvisk#6OJ_B59?7s!l`#Cus-4L4>UZcN(M#$g3Uhy;4UvVg zc-yUFVqiGJ25-%Mm@HR+JMS`h4|3t79V%1IVos?p(e%CReak^}Z-J($tLQ=nR#&Zj z>EkSykF2}K*XsX}yW%0E3Rj0$4TF5^4Bxwxv>f$B_3zD{x%qiddfMCh`}h542spCW zLg>WG3kF){*F&m$R-QmcuzK9L>{kN??Ym(}oTAsrJ`@VGTf7Z&j{dMamb)DV&O#aPL zJmVUxc1Lu{G>dO-$?^g!eJa)a#bXPOxnF*>ym#Z*8Tr3OgHHQ-OFWyU+FNq{W#-Bi zik(y1F3-4pp+8tEFDc^Sp0?Fof5ih<*q9$AKo$WxqkNS*$cXIw#W8P5#IeZ{@we+?9KOZ| z@cdFY`AY(9PivT0PMK5jsYP(1q7=hn$xU7@9G7QZQZK7NSn^F&v9?J3q5r?g3z1!$ zbwbRVR8A*$)MR#Dl#Dvh{C4gY4#DTFJipI$r+9~i%>U7JqTP9)#?gbHWNj`w&(qL* zBy?0#PxZZBNeZ{@(slic3PBV|+Q{LJBV_E(x`P=#0rlBVf zEE7n+EW7Kd^W8=3t39WF<8oTuFQOI4akK1_vW5FHAqE6(2l(r-NsV1A3WP9EgtZ%b#(XV4v?tHlU|FISE zz0bGt`k86!#hyQ1d#?DM?ei~nf4~0ZZg8EVnqr{5aQ^;Z2HHt}O$?!jn7ow4Ty;D> zimmH=)s@05YC?|$3uY@_ldLlHx&6glauRE5zoUjVJKN#4t1_jn*FM|#aNou6x}SK$ z=I+XS`*PjMw++F=-c3*7SEcacjfA^hM2+z4)aC+LiN;bu5tNLySNUy6) zkj%Pk6ne<4^moJZ%C)=aJ@kuzdO_kyRYKsR@YZaOL-iiIatlK`E^~enIvi4SK(%J# zxmzZcR}#Jk*k23v-Y%VWw%m93!q#k-lj66;%D?mX?pj}3HKmI~m*M!eB}+ceQ@N*a z;B%kl?1gA!>22?}S6p26|CaA*bKS50OU)l~Z}hwpbT)Hm>Eop*t?h43teY2n`b3h$ zF}8V~3uZ>`O}u{Cseaq}^BLb+&&?P97;{W)Tjqy#-(d)E=)oR`{4_>3_Mu`}xGm`Vx0Uzs~4-e7q^@y1^d<&f0Ef)}^^TS#9fM ztEWw9ORJALwx4Uo7`VSU)FQ|d@@Tp?NCbOzb8tQ zOeb}&uv=4I>*jpmsbBDnW6Dwfj|v;kFBb4%-R|iZc-BZG=!(V5FQ=EC3_fCWGjq~u ziT}K)o$@DX&NG%XGB7M=W?-;@C;G`A*9GgRPP*?U?I?0=|K`ZeyOv4)H@Uj)+6uY=x1w#s3vO*5z7?EJx1E3=+O{})5;ic7|`8#-D|c8lMix%vK2 z*>iLL{(b&Xyg~VjlgI|aL&x13&N75LeT>LVwHN04x|i=@{<2!nh#XB_|Muo}CeIhm zE=b!s^;^BmB|*2HpDkYA_MR#@?cBPxUSIhWjWTbAMf?l-wQj4)S(lWVDW{KzWj)d` zTQvW~is>s>%;aNp`W`z!F!rtF62}M+)AnQYPDTGddW3Ns$7lavGS|MVEuQamIK(*H zV!|yUzgKIu3zZkSys*fMUR-i##;hFz-oJfQ`a|}e>E0t49#^k^=@i55mb<@FKD4(* zHd9c8d?S^V<5gNA+F#mMho-zpA$zZ@f& zSp7+(<(10h_^1D`w^w(4xZ|V1QqvXDS(^4=?w%~WTw1ZP`b+g^7J9ur93PoJRHjFq zDwWjUx$aTwI??I+*3WNAxc%$ADt-9n{ST*37&JY&+il)mU$fPsiiar+mq)6{mY8dO~Mz;BO)15Q) zOSHDs>puI|9==EMWyX&46S|t8ZER!b(LWzjUS5}aQ~K%UH3F%M&m@Y{JCk2L-uBid zaGj04_rs}wEO%erSWv5bgERN}PVF{>J8cHaPCPLV#~j3(ooq}D8h8x#r}F3|OiX-I ze`mS%y6{pb=Kc*S53K5sNk~}6ADq#4oM&nA$FviF4#(fUQ}*V^l$R&67gh7WT=(4d z_g9T)i86bOAM3U)Mk?Y%xzxK?RASSlQW9_jI+v_m$fU>3gvVB+xSizh$eign$Z+D&0*F`iF&o)6~;Wu zJ9tja^*H>*PbDbB|8mCC&Lw<0v+gfQo6P>=XVXUc3ub&1g|hT-O6sy-*q`*}#e(-& z4(c6MS6MFCc+}+N;fzPyDq@!IXG{IG)=geb?VW3PgX`)7pIPh%W&NwOl_b?CO!8gQ zv*M4NcE!|BtC()i(UWt!X)W7#-{?+G&@LHsm%}cr6{Ye{wRObuP4-9$+R?hwEG^_^ zp8E^sG-07A$GB5WZcl4Oq`u0=H2E1Xj92?Aj#^@+I~H!5!oz0v^JX)Ixo-JieGs@r{frJNa(fkM##m&Ym8( z$6-adzi9Lc{*1pZ@1u%=Np!8 znlfj9T*8UJ+_M($&ohq|+_r@8b$!xhuH55)H1Ab?e13(y|PB2`xI4KOJeecV1|-A=IXQ(Z0rI`&w7!ocSxYcE!!$7mHs> z3hkL|JNccaP}XneE8=gM>N}MdPR`X@L3q2ARqO6}E8Rz7L;Q}6ZtCd&4DO;uI*G0Fbpk*a%~ z%uJ*Iu;ljDJ%5q?-*s|GyHnJ$$%PY5H`$0yiPg_o#=PUn`~$T<7xy)>3)-2sw@;jV z%y(1rl=tq8hoAU*RP5?srn#VF<9pN;oZwp*%EH9Ju!Dtx!3b36n$%AXzMp?7K;)mF zrU-X&!|f}UqJriU(pUFN_NWQ@`kY8>x_S7X-h~Z%Pp{o6bNjCzUvu#Y`+tW28jpAC z&c3VQIBUyu_x+#ezMpgZ-@nhF#T%HnqAI$fq8ket5e$cgf~3*TGbO)wHHT4JqI`Zc7oJz!RcKJ#>CQQ6v_Jq|+G zr1u(s^t9MFA$hsHrhlLHSz)Jp-1-WV3y(!T<>}iXbV6iytJ=ajKf+7qpUE^@{`OIQ zVcL#JXT=Haje7)sSKYJmey=$}^MthJrVZXVGIgF+Uc2a?TT|z?;y?eagzwG8rX}~Q zeqAw7Gsv~|6%_l#vihS|&b#f=Vo|Pd7Um?*-?05mj?Jz8Z)JGT-AQz@h^Twpa_iB< zbtc|@P3bc_GAdT>zxPUsZS$%9VSK+fCA<)AD5!5%Zr9y-_T9gRkG-c^{(W7>$PutX)bQrv_$j0Kll92rpuDgicAlx+BCgtQ$<62VWjCX`$N9lW}o;l zJ9o_tv+$h9@@BVndG(*7*W?9fBY5vJF)(CLHdx|Oe>zAwP{6i)lII}<2M&RctsNSk z94*uNSvF3%bV-YAtyAQN-73L_B}UG^YNzyn=<6-%a-Yg=e_*O~Jhyq?ofrBMW&X>Y zS^^aH?v&iWz5V>learLJ-q-K1Wl!MRZhBh?0 zZhhl+U%i(*$lU-ib zC)sbGJN?^X-}5DJ_CK+4yS+0zdC=Y&1DT0bN1^Bd3lL#M8>%=R=3&RNFV z=FhY&d##nIdHx;a%5Nu?Eg#po*UQ?zNG%R_7k^~6YvP543xkgfuq~Q#*|0x4@WSkQ zf1fW`G`K2qo8ih`g=x92DZj3oiF+lelwL~YF{@@_lHC-rWB1dYMZQs@x4xTJt>#_P zH|2;zE$i(U-jYsD>`tp$`cHf}QT-&SVPh8{dTVNixZ3^cg1-Zd7VqXr-L#t{{a9K3 z!o16kO)584LL6#ZwCo&(=U-Iaw;;UcsHWBF5Y7wz#tr))H64mC^gJ40Xsp;Z@9542 zCDUxuH6LEzY9-j$k#Dy?&X%`=^<1)o!!xEOvu-*+Iji{LyVZs$=6HqFRSzORohp1F zZ)XwdyW+0LQP=-&P4mkgHal3xD9yX6xV22+R=x9-IaLQ%7{6-O`GwQ`Igt zKWxaJE22^>c)BO;_&3FE{H0$H9zP#aoE3Yt!197+n|9+l!=4{jpS4;|K5CiBr%AiA z|5WVSB0O2{+5Xd#bC&7p8%EBVf0k!m`&P8EQh~*`>|#O;3^|$%3~HdU(#d7Z)$218 zVvbJy=QV4lc~#Z6)SH`Z6LKChzn*5eZNt-GI|fN_vuPVA@}G&Qn&c*TzGJ4~HVda6 zhXnfs`Vxeh8WY-Cns%meH{SH!aY*RIJE0qAHznR|wr${5%wafwyzcM4*%!~eknH>u zQ0`wIS{hn<_4-x+^|IC91R5egg~(Zb+?e&RKHPNw^^IclGk!Gl>DyiWsQGV2@h@ZE z|H~ix|NOygcYWbwZrREoL5CA%l|MeOkvVv==FM@#t1{PHM8dm&sJb7QIC=HR;^aLQ ze;))AKzP5% z#_5HtB-dNitF2I5z%pmalX+`qb$a=Czn@ZLqd)n^gB5C%ORsorR9pUPhIX*Y%vC2% zWIw0w>Wi}U4Lo;YiOcb%Do3x{zHbq_g@ziGP zjdJ0HRPUO`<4~E=5Ev?-O^l61Uy2)_$^);*G@9x;Tab4okYo?{IudR)^U9Z8h z<`qwz(3*FCEr+feZoYdbbg$Zs1z{6^HU$Po-&|_zDY^L43hAcUB`34Fwz@ZUzLU_6 znYeS;fq#;GZnswFGJXzsO@4dz?Z$-c8*B17+gHin4r^6fw)V{**D01(5`6CEW-Vni z*Y@pZIrYo%TFtS_!qhV+qOyjsuYU@#*`b?Lf2ngH>p~BWjUE%CgH9EH(dphc%d7s~ zl^c7LXG=ye=U{DJy-4@qhhGUgOX{pA&vS9_n6$j6b=S7dE7xrI?qx}zmLrvupSg{t zd#$N2pX!tCJb#v0>Lqn}YL{)Daq_}Vr5Vwa+(OTP4(j61w>}(n$&ORRN6vO&~gDd;yIgt$!raJ>RWZigk*y_khW=*G#0w#?( zaY>IEnX1h!J6qT1aYmi}lP#Ucv%6FB?xeXVZCk#msh&%mPe|}Q%N#Xh$2Mc5 zbTJVlKXG>2eL{ zomsF)p)A5;uI8gPPfRlF-O@CCpYBQg)l&Pe?}6UID>?SN+&*p5Y4&q4yMLC){7?DQ zdB$J%K0LJir0Xme)0=L4-u1Le6mWZ8V$tnxJDk=n%8+OHmMJK1(LSrUB`nc<*G_g4 zxfj{}@yg7U_XmwTXRi!8ynXHNwZ5|FS{$Wyw}xFQ%YD^!eorGii=IaCyvX`Dc@v{# zmIcOJFAbi#l07==OhwJDIWvt}FMGGSH3r39wA`J>S8y(LPC8F}aX{om5kvpZ5BdtT zYiGaqz4$JIJ6pN+#A7zkRY65Ocez|KMAf6^***IFDKH=vC8g+tQW! zpn8XYfQ`r-zDWnS7%uU>wX?ZoMcek6`m+2iCd7_W``lR zE!kka>26LbQ-7qT&%>Mj63+Y7zo*Oy67OcM7BMnbsn_b_-P2rekg`2Szd^D3Nu2XO z{qGq?^Bc{dvbWute{>#GwzFKo!)G()=F6Szu##rv{kbqE=S1@-f$uZ(WH0thxPE+; zbTr|_VXdRbb|%kNs}}uh7sisQDzI^ltwb8<&ArX#NvrmxW+u;$vq`S1aVyk_li@jj zCL!CuQ2YI@j+^ySOSk;kSoB%B?T^b+r?;CDRD^s**rTJn7iaEq{Ny&tSl7(gMzBY< ztGrD}_NcK|dWhr?v31vX>d*XSJe4o-;Ic$7oj$iiwnud@dMHVB1zcR$m(cR; zh?DM7U0IurVr>y~KCb+>Y1dlgRr`z*-X6aGq|o`BwyWB-oVc2w_0QIwesyR{_0eTl zRusLSwkgPY-URiRR}_;wRliSC>};#CJ1-q{q%-c);m-2!<=YajU9X?Z!`|Zm!EL^= zjgIV>6!|>6bo)E3qVdlwjbt{QulX{4{)~I7U%A*D4puFScy6b(*e}KKP1xkL36TQk zMw<(Kl1?#X7#7za+_BfpcClA|Vb{7#2aj$!ueJE3<-#RjTuLJzu!JsH_4@d3``J4; z)k>tEy1>7Aq5SOS(Yrp3tvgtCT6kk!kFI8^ zb`*CROZB#u(+hMa)=Uwdx?@VS^wsKrkKQF%%yXS!!zpxyzvx1I-o9hEw=Z>`n;cia zr#kvh=ha1%s;&!_wQxN*5jNX3{nA*n~-@->ih*9izVunW>x)} zwqupurn^2H=1B&`Z_i%1VP(N7aWmz&oqXCpFB|IrWGpe1@{~(xbe(CE+ z%)E`y#cu4}GgH#$?Z%Aq>unQmEjO@zeRVpMXu5HmUzWPkW(VcU*OA$Fd12yw^{kr= zY)hmjRAu&`^N9bwyYzED>7TX;)jd+{$$e#R3ouFm`DXu}$9_&U&9Aw$x8uiByIl9`6a zH7T3TZ}@zURWVn2+UqrW*}t2PCo)VQFPw36R+a5amiNz^t{r+&zh&P3_=%VG=6^2K zvf3!tAg;c0)%3+OU)|assAd1j{r7QaPH%o_?Ln5Wn;yRxT=GzQ*4y%**@8uukBV+G zR-F3vFxQUZzVV65Lyz_}uRSL>gPH%?BfmbL*>dF%^S*_D+*!-7Ib}`j8`0dj$e)fG zdq2GQ=lmGyqpidEI7i97LF#S&F}Zd3Pj77h`~Bx}a~sjc7w(v6B-tIU_%-qR9sa#L z-()`dq8MMmaE!4hVezc z8+Sk5*sy)W3h~EfixuAX;*ViAdmWW7y_!U$# zdH#_rwi-%bO@iJ#*4Z!ntl?MPsH3v#tLA3reRgL~EZlueGtw^I-P?N4(-Z5i>Uf=9 zxM$TSc~y~+sEBLbMXoXTy1B0UuldUUXYYzTy@%=>>@)R35Bg^9T6Hmca`=?xF=2ld zo?X)V7gQ#C{nbpRQuihEgd(q2T&N978>(*`F$A7u~lDFW?YZK4r+$qmV zOV#&Ve)0YL3;YrGu6NHm?SJ3{UqF@NG5qgj8z^poVe$@Y({EZd}ui)KvI z`X+xg6!kLx`4 znWtRuMQ+{KmEt#VVzb?ua|he9_xAk0ANnP+Z^6b(Y>GYWOAJ=HDF(ahpSx53r@4Mp zW5m2e!AyT2sz396wDN39{NWuI{m=I_KHoPnec6|}zGu}JUa&m-`Nwr{o-Z1!ck8VmpWprh+IZ=vnw^OB`)!4ECZ1$@bTapl9Dw&ypw?tWxlCL6f=&sXQ_I}!xDlOge zD?)!{+V`w;>vON!Hp5CaP4j4kfY*wMX(F5EIE4uanM8ZVDV(3UDXv#0=ep>xkZQRD zQyT8`&iPd!*82AFlg6iu4xT>#o$XI+y8IE#JFQw*v^VN2-=DOXJ?f#CUjgEmd*)!%lK1*+TxplH+k$Lfx`nqFx6_4G_myG}4 z^ZWzjyyM5`Se{9+Y@6TR7cbx)KZR+J%I1%obPj57;#u!yU8iaNan_x->rYkpD6W6x zTRFF)eEHNH%9_=dZ&gnf9(V7!bl!-)JZSg)$KpNr_zigVi%k2g=Qd5(*=4%q=4qJ^ zh4P1;JbHJ>bWHDTp2c-7C9a_Ui}#*m0p})*e>AU{8!0eh`A6+f&y%Lz={AqBs$B8$ zbH(Jy=UX?qJ)OPwDc-h24oBK`CW|C2wetAbOn^Ga08Z1pSKyEJj#)P((s zQH>RQn0`HAe*yf9pmzr*5mb0 zVrwOeMQ*)%CA=wkUhT1a$Lmt$B@O0HCyBx3evkmU9oSn6I`5VVL z*29^f+qg=_^8**(asA!5|L~8U1q_E*iCA2yv%mLfUViY!at{6dPj&zLAK6^qnZEz9 z(7kQmAN9BV|0^;tbc56%_e+&iu(U-KPEzOeYY!TDkZQs0KCEhps?^ScZyT15??UBvF^DIK{1r%lk=JhT=QGBZT zMr7cVnW3+@I^2Cd#lNvGCs%LJ2~XSn%Z@Dk3DVt0tophqzg~OuRXtHFf9uypwf)YQ zC;AqzZ7)CCTmN@OX4utFj4e`HIyb!cTd9REb2yUx^65&Cr1RBbrc<&j_qVy)eo#F2 zNcoU_5JF|D3;~Z}vN$RK6L1 z^55(?>pwmDu*JHN_vQN3dfAs@!kTd(pZ-M~TaxO2YIl;Ifq_A2a{hAB$?FaYPOjU< zQJ+~Zoi1AEcKgJqBi*l5%O;2TCPzN1q=(r+?*f_YRe5@j?voVIQX&?2~d7-xt=u{;_Z3XWqh}%XaKp`6!x8 z>g=AmhQ+PQ+Q!@Jr=DE8a^{`|`mdQ?ttZRQxb*oj*Q+$6mvi#Ob)65Me6?KpoYCs% zmzenud{~mXl>O4Qd8ee9xo@61FnL#~LD1u8mnO~g_Dw4~rdj#ugT_SZPtyVoincA* z3X!)L@wrZ!6ToZhyyKl0@xp^qywRvnmmMug={{XXASx*MF8 zXT}_p3%ww>-oPSJdRm=cHqZBSS{yyIHJvNYe^}P-{ha5u=0_jLl1nicHgDcFRWLg| z@_E5I*2V{8)A!2gx)aoUV2aH{nsV` zlP+%Q-58T~=nTiNy_er@H4Z7580xOk(IfJ<=3>}|z|9Xm3@7_aPE#-swwSh&YfI3% zuA1uB=aI9OZ*TkhWqV$r{*+Z~OyjaIdgsp)E8Q;SZ*A+=v?Et%d(f?$g6lJu6dKPq z6;r9dpH!ZF&BtHrwA;2jGjs19;}V+3zl~$h{og+CFPzU)S|xJ#+wWDDxi{R+eWzrs ztkO#ND(@}oW+;2Ha*E5GtD9Yuxqn5jJDB>sQueKPi~Z}w>i?hq+aJ0*r!dND{pvKP z$_1CNpXiC)BG!{EdGTAW>4)E~m! zE{FX;8nd$B{b(WbT1zGQs=mB?_}@06U0Mf%pX+UCF`aX0vQ%AP=)SydGsL-SPR?kH ze=uD}+*WFt!P-Qg`sXHpxWYqYE*tc3ma6N$U$7?4D!t z(~~WO!?uKe4LBLl<9TjwW|8*y4J(-~cdn3o%r|jM--h(l!OM4YUH-YH{zl-^6;Yez zDm&)fZhyS>!B#1Mey8WY*`Dgh7Pud_`+HA8`n`zleDk7}y%WQ24{fVk*&=>s&f0XB zFKgutIhdmNq-ikwb6f4&YgXBMGr;!4j`^FtEarLjrfwFQbLsfuKSsIF+lv_jFTM^i zI53s}{o`4>adGlbeqC5*8og)FKY>^EmG(W3r<@y%`0PWn?s?p4o3w-Z{-4|*`AQCk z9)=~tui7M*MYtOl34g84z98bGdVPcQLD4x&E-ZMkK4Z?lX0=-;{H(w76?e6?PQy|xvi{0~i!e6aGAdf4auhd*&KV}Fu}VwCKGH ztWVm`QQtEuV$Q>xOl$RTiTx73_53fV+v~mB899(%|#pJ0A8yDyMOR*zT%{wce`5e z7N2|}SNWPFY|Wp=t6$gq-#g@d{j}!|{ntyy6IBEjiWgo>oFrN?!I9rkG=K(dhqoH77tB;R^~msL=IqT2 z-^3d~mQcA* zJkuZVom7wSHsgwVZoE%ARxa-0oCzI^vR{6&lb@S2%j+Mn_4@_ccDH0Fq~254`e|16 zZ<2`Xlj(f!sY^7!Ephy5GdEVpI{Iz>qQk+=)-hk!`0o;HD-yTOv9OC&=sJAA;fXLu zSKO^TmN&c3aqjxy=fk%C`NXp1szYbjsyRpm-)Y||J^RwEboQ7v9;?I3!jmNyf9m1U z+tFcZzP5T*#4NF+Gp0P=Fx~x2{*T)VngWkkotU^y=e(x{$J63(Cjyswc=8y?ubr*p zm=yiKxaXSX@2=`^3Gta9rmfbB3k)q;TF=WVf0cL9ter1DcYgeRUixW|rRp~u^*7ul z&t3O9#Xa(V{Iuv=Suvmet7$h9ZeDbJ8RzQg8WF%57{E0x<;2eajNrNV$qR2vZk~UL zi)Bcc^@PqscF&Cup)#Q&7Vmjy!nW}nu*-l0V21#ZH27QQPFu9~r zmT~fdv!auI8AVJ~3?Zw_&^2c=>a3P$WnfU@Vqnk(Yl9F=8kL#BnqyDPt1}}aAtUf# z?IH#ShD+d+3n6MjeK5Y~jUSes6S`85j<*F))}w^?|4*ja+;%y_0vdOJG>4!f>+gF+T%C zgaQMDB1i`mFKO%$glgpAMG2J24QCWtmNc$Xgh@~4m&6QiMavqFZEOq-Ej*wFd{9Hd zo|&Zt)+l*a71;w5-n8gcGBGf;v7m?WLe0qs&Pq>iI4g;)erB?n`EpJM23|1+1}%i~ z3`-hQbtWG;YY0kN_w*zu^PJ;gS<)C{2DVf8oCvZRmN_Di!Z;Wh+JqPwlu*pDGY6}$ zMOA-;XOc<{69a=J8@d~>*hAHG*m>p^mn7!oIA^3LXQPB0JWD(&V=7oI!oZ-X%fO(3 zV(n}vurX)P34xsd@Ej4d8DKpP7f`Yc{Iqlt&=E!m4NDp) zW<%ApPqt6soBRRQ9@IlZk@dYPnJjZr3lx$MGDV#<5mF3G8huLP1s~yKL!qU?YNCOh2ZMplm)Izi7LSB^}cdq`<=-7YqGCR=zDl=~i@nLPK9 z-sFJGtf2DbH&~4I!sLTTZQu&)j!RCixdqDfH!n`^xaELsBWj}z<~~qDSaW&u`&()t qLmy;{`hwbHFxe%I|1QG|Dg3Ro0B=?{kTx?0Glo|}3=Ga!Ks*4X)2f;P delta 48251 zcmX?nj`__tX4U|2W)_jjfu*7orG$k=7#KJ>7#J8F83N{fpJLCzzz{mo!B;5h#G$RT zUPv;1{Zz!r0N23J!oa|gUzD!Tj1Zf6QG+GG|+S#gAMN*2D_W~>Yh`dkbQx|0_s zi%s@p6sgxs&PgmT?hT7Bzw9RPPwaG9k_*Q%P78-54}~&4v!zp}wJd8;RC&N6<-CG( zsm8Zkf+vEsPRCU3zwmo+?W3*wwYl*!QGPF9X8+dyrT>d%?$k98q~|<)vL?)Uv+?Iz zW9v`x{Poog4;bn=lv<1(-?&8`o73}Cp{mfVqqxGdgEgi8NRb_fydKNOj_#z&rOc6v zJFhgVN={GhVcjUX{?rbkBiTE&obPrROiO)YH9`E{jtH(K&9Vel4&Li2G4C7nwk=gC zJ2)ZHh@~&1EzRHXN76@EHqF#$mWQ8hN&E2AD|2S_^Q)ZK#qz8W{R zqh>13Gh3UqDPv{j++<#@Z*N306agLwc zc$C}f{7uhr_i1~3kKB#>dV<@0x2=(p>$lk*tM7cZEWK*DSSrwWuHM2$>w_Ll-d|NNfvx^!jLu#Y`jZD!Z&1Wg*M^HdbDVdl)DledV*H zZEcR?D#>{k>jNdXJni}*AbT%b&QIfq*!|8c`_d);&EGyL@%Q9k)AQ~nhsJKIyS-6^xdpLhPu`FvgR?>Sk8 z&1&9vX6wW)QJ*99c{Va`pT8kDvJMuR{ zB1g(JSHN<`O5fJF`ZJdz_N3lB(NYj6YP@IS>#vsg@9HczR=v86+flCi*2jv@1~H%R zo>>js6xZ@z_3RMnk36DOzT}Ka~Fkh)3q1`?YP6b@0(?oenAoJcLgDa(h|(`e?@&^+V-Hcg9~l ztgvbFoHySVPQGT>wXeD1%@K{iW)>ZFa}F{5{m}770mEjGMEiLQHP~O8pRZ@M@m|q-zPX}r4d2xr1*PXFzhj;BrP+2-!ls_X zM!QmdEdEb6>N`;}@k_AZH6Hyym0zc>Wc;7KiR;4WGqqpR+?{V<+pxFm#GM<>n)ek~ zy5IV$%yz7533Jm@tzS;ot8P?^H+KAgZY}itFXXYn?W$!Fptv#1)_q#3G zuJg>{UDJETLq=&5w?FDvCeA38dj6#zTp+^>?l8IKM;9|NFkEF|U{D5^wEH-unWD5O z-{z37uRK$2GvjC6`{Tj~q&S(AJ2*eyyceVPy>(j4$7^P8(G&H(3&mSbo=ds)>(GkD zYu1~kO9-Z2(_A;_#MURh!lA0N|NrWSu?S3RHoTO(Gl79ePcdQYqM>l+rhTxrq-z{CI&+n3uqN-jKz(qelaD#97cUAbMmBY2(n)lbn~ z=FShli@q;u`4oSmPQ>e8jD75aLmO@gRn5NiJIGXhgM%AScHG8)^Xebescf;I9kQ`t zIwQ~Odo$DXL+gDWZ#-<|{7^=zd9QNyD#bXqWq;3bh8P9Oq!{>{o||~o;QqB;!LMda zyIctimWC;rzI@H{g%iWl zT^hQzQ-n__+WV~wx{~noeaHS{;o~!kC$B5*xe^{@(e$@+)t%*?MLz>AnT&Us>3yG) zle4Dv?6pbKg2$qIwzs@KyhZz|;(s>1$)zW~7k7AXD4eRZY2|%b+JPjU*PPFCw(>DB z^vh0OAgEqHH>wd>{GExoc& ztMmEadP!g9TwwnG$Nk^$-~aWmdAeJF4@<)27@h=<^=ub<>-EDoeSf{`XIEC8v+4eo zVfCkvWHbITt2=(+J)6LR_pBd&|7d3TCs4m+)_Sd3_F-q|vlOuZyK>+VwX{o|^LYyxKm|1N$Gu z^ZuFLSQDpA(sNT>+jPQ$y?r9HP8l)3H&+pv@O0CmDbZI}YV$^>p2!M5v}}#xld$^WYit+v zU;9MnpUQo8=k`>Uugh`_mL8nq7Cg%*(`@O{DPg4tWZQB~QYI^wb17`FdR%z?ZO6@% zOD2o3RNp=F^WJ$~GG z`_@wN?VLP))o%>jl}hGrJb!bop|#y5sgHLuYFbV+>d6=1Nih)=ztXq6Q}DW{+U`Z3 z=Q~#)p6xBWPu)aVh9ef#xuhiUkvoyO9AoHeqYieCE`XiJq> z1tl-9m;Jt?)@oU)C(o^o$=jquAHP|0Ub^?v747H3GnLeyO?|^2_;#0&B& zqA!cn%66PS9y_HhQZQQ0?T%!~qM(LPE~kWbPOdJtc-p(%M(Xay<2z!+o_;&}^Xj=D zXBM3b-jjJE&H0^CN_V|tH1E#n^#8UZHktg^fAc~%WKFwhe#T5kSJ-q(uhWGeZ_A9V zEN*X<_WG5(&g@ik|BkN=f_ncAN ze*2@Fu*s`WOjg$=`zA(br}ciBwz#u+i(A?YvBSq6UQXZPxikLk-O?L(v+H+nT(KxB z#$jsz3Ymx3n4I>P8CrXDmu1X&bBViz|NmMsos=g2Wl7tfe|g?pn4LLaBzs-2`1J|t zeV^}iws^NTxgLLcLR4p!ex;McS=r)8&Rk1Y8#U{==*@{db^fRDNuEPtYLi+g@4oBE zR--VO;unLzdj{k0ft-u;O{|_8#pA z0h6RR-JK*`5q80dKVbn#A-d4B@CPGvyOp$66EsTU?GT4r`G?#UBvo2h!Z z;^ZX3t39U#y%()2cQZ}D`Qgrt*5@Ca7C8OX$~-wEpni(?@$&CqOTN9~|E?|>_K?}V z|67}>PfK^9(j1HDI})w^GAEx?(C_@fBhs?h#iIRWVjkD~>;L%pKXMfilRvlU(xsb%_vdvTEAjee{7Cb)icSsJ`6#1xTWUOF zyeA!MSs7X#eZs8%+NE`coj0>Qz0O_SYuw;GW&YIL(|k_+%y}Y`7eD=e;AF-*i#vOK zBEwoYB%fHK%70qfr1<~E+Os?xwx71{dQlYp+ACqA!kV=6+vmu4Z=KV3tUc=6jd^c< z`>a`#tQ_K9xsO*iOcz``w|tqk=ao5@Yx>Q@O3r9nd=AmOGv%Q754C#9c^y@YKmV|s z#dBOZ&SIvNynjI3LWAdOoDvV4kMAlyVdwSYluD(y*~w6;kC!y(y*bM?_tRZ#-AW(T zId1Ew6-UZ!-n3Z9PWJ@Q@wBuamrbh7vl+j2Ez9jq(Y~f0eO>+V*VmJ8f7#E=8tbih zVz-A8znWmU*P60(I_u}~Uod+%sotpDn&o{^xIJ(1uSvQrJr#_ViOb4GThCn#G&h{M z@@SaIA;%P>cQ>DNHzgFF>|SGGq#kKBDOz-L%LSjadpv9Bo?X33k0NT<&rPYT z=YIYC+WdvTF15~xTD@@BM<;ik`K4)rvEoa@YR@@qimf$n+qKu_YVfWr>lQ9^{TCax zAS+RH#>xp+UERU2&WX=Be|2iM>)(@QrfYP$I&%VN7fm%Se*DNv$=I9k>cy1jXLv&* z`oC$-Iq4k~o;2%^sYGG;%1Qn=|NP#U^upJ)XY$i}+1A^?%b?pbIwPc<3A?k z8R~dZed57D_k|M<{%dr(boxsbXaCK4YhzM3m8(3}XbJP&dVZ_>u@YbNf76mu-}yY} z-|qYJ!E)cX5k>XWR&P4G>D01k+e5adzfTN3RP{4E;N{9d*O?`U-^{9vR(sT)pl&i< zCpzl#zEiG5SX!q0Kh!LilRCZczSLWZ-ud2hmcD+knRtA% zs!#N*%tbuc>|U;n-=(9ubYayzvorF_l~2y^x%b-o+2^TU`(}!F)mzj*?7MkSN7O4~ zRSQ?7)|!I?yA%r^950%4F!Eb6!zqJfg?kd_I0V?r+~8lez4>3&P5pR*KWrY>jh}PW zEnm5_*8B-GGw}-kEb_#%_RQf~8+vjj)Na}zigRug$UkoVW&LL@Q{{`cM_2iL7uj5N z_R&S1?($;Szf1+8heb|FNv&VFr+(p2sTy9z`=%i#Cb7-)xsUPO4>h>4PIY^!O}=eb zfwb7evX+4UsW%p+-kf7;sDFCZ9-Y-&W~J_Wo)sD5@A>qx&VB#Lm3-NnjjoQLt+etN zJ!4~HHfmky0en!r$Lrs#h#?SK}?JVE4KXShGxtx=)w=mc@dC$7e^hcwv$NK)+ef`F@Z}zJn zUsI#n?DW@b!z};h+q#auUg4XZIQu_a6SH}Mxx=yUWgB*=Kk-lYoV|Xb;gi{if@al3 z&KCT{>a3{T`&2PrO8b_U*tN%>(`K)9+n&Q2l2^ZW)txBWRU9)j*T~!miu|T>Y+Z7w z)N1>tqw`%YcBu76=O?^%D7Y(fZU3GnRfSJgtFymO()znLDrhUm_TJFC2b?BmHGEGG z{xUI>xjy;aHLY_$@|9ND^>#B)pB7@@&t^Z%Iqm18QzlaLXV%TX=lt8WT`TVpPw0}1 zmuiH0&t`71t8d<#%k8yZI?Hy;gQw3+F6?c)p1JAzN8P_?cYIkc8Ft`qOuq8bvRU=) z%qi;3Z{w`0#OH33zJ1}`e%TjC;=UxwE8XZ%wm6{kCgqrHN{4KcM(Jfu+Z|^Db~&wD zUdVF(lIeb@SNfBFneseXZPB>?vC6*2;2&!5mWwd|FnfOQfak;DdPl8-{Sh0s{=V<; zne~C|UibHl3uk`_{A1C4P2srr56*S7DkjXVo4GU2Gq3-V`c3W$*Oh;0z6x>ed;Zb* zO=$4s@Q;i&0ZUhhJU`UAH^*Y*bk5~QD-S*XA#lpIwIt2Gb;b_^JEzkt4*XNnT3%VO zwNaa`?%Dx&-am61)p=|(A0)HY&ojEf`f=iUlj34Kt&1V|9ekl|2iqpUf7=DIyEXg??GQ~d zSu9?^%_s5o)tYm^zP1^&N^D@W_n&-j!w=RVyJr8i$Qmo|wbs&7%L~f=Kd=5^D_*~6 z`NTb!GIle0vwtvSD+n(5&HF}T#-Vc$_GZ4xQs8<2%)GZO?HP|)YJs7jrI5*03*MJW zn$9X`3hp?bnSJoZ+)AFCGmlT0`@_|0hFj8$|C5d#<(681`ksSm?G}yoN1}v2E}Y-! z**SUTeC_F(eSIe1O3YcmFWacUWB(sl8IQ%Am)C1n1oZO%w2;$S?;PH;Id@;0qGP#~ zZLX+d{EDX4cbT8|9z2}+WzvG@qB1*Atrgt*^~IXCiu0!^<$u2G@ZaIXjHdOE^@BYo zb6!8bUohzxYn^de)`DDzwZ3dWjoK=;MYENoz8P**@>yx@vy9tkdAE;h>c-z0&8bU% znAjZ_j#~MzUVroR$7hUUjuwA;C>dpGTt2bxzmD*oN;?K0md?Q@CEezMRphZ-122_O$N#$E|NfOIwwnp6flh{bScFKE4fa zGk0}fJ+f2uW``ofyH&Z~k6nt@lGYjR^NTxs{ESeof87MVnmL>5>pMEXBsSfd+7xkf z#`L^7-eDL9CU+zESs<@A#n;mZtgecw>zlyFmvtg#vX^ryMHYDrf*HxId(=n zYP*8s1MaBp0^bB)gwzV8$<=o5<(jvdb^ob(^QY`zW_ka}3cW?A49;XTY*o8b-{~g! zLk`^CoxEQ0JDZ-C-6i!IC&U`Xs7pLd-OPzZ^W`(Z_D?GC{z=Lx;)6!P6DcdewvNM>QnZ9Du zgT@am#x{pPh<~^t9yghbL@E8Xp?&z0}{{r&g8yZisVFRy3#z;Vy-f#RIZ zgUuGJr`79cSWI^id2VVm*Fh%z%E6G`FVjS>Y+j)eq$_^KXz{d2-Y{dmRc~XMWH$(h zgkE}Ja@aRvb<+K=BBuD3<#}41KUSDMo^;9le$VN(5eKFV{V>`$=|K3$trAz_e@{HT zwt_AG`UhU#^I1QZIUIk{x$yDx_Tt6v=b!uY^FN;_@19C zl&#zX(@{CoE=DV{f0c-1kLq<~F5c>^jFk@pB#t+8I+7 zq+s<#O!J0amSxeNs9DqQwOHnQr=HiH@omY=$X7AyZhs@Yql^}>GoL*3UrxIek}3#Xiqh~Y?!{p-TiTzgMfrjYhgs5+sCi%%U9*!oZ0kR zWYs)%S$pG@TiZ6>m>(zjwew~7rU%-opNejN5|enu5xeQ`p*aV>O}M!5-k~)wEiSEN zVUsvI$7@Q=OIhK~x41=TMlPHc`~SFnV_K?y$flheYwvt|F>`gys}DZQUramnquzPj z@9DX7ql(>2qwd~Lz5H59f{Xvj+o;${twoDUP!zp`Y0MSSJ4^(ymuq`sK0Pb6La{jX3U2b9$^%aGuTPjRxD4 z^3`z*GDV0n)u`V zA8bBeNf&=s@+Uy>*9T=;`(xZzb&IBne`Injj6S|{)#6)amhYL^+wQE2HIcb)&Na`Z zHgk&aRQJX8HyCCW9{kF~YX6w&uTjY!5vgA*`+`q!-zir=!RfN6Qr7 ziaRddGNmv6(Wtz(r-f84&XfyRw02cf+WN0* zuZwJHmfFue51|{I6YbXpx#T}yYU!kzvuk-%V^(O5T=d#gU6I%P+S!+DuZ#Wq)bsLu z(HpxaCSRGZ@Vtm`xAeuk^{G=b_iYzYD}64z^Y!B0$)VSlp8Rt}Yul7mv&bx$$oun7 z-PN@YuZI*g&X4n%g=bx=z`rbZklC9QdaqulGecW2d@|pc^%~ks&;+4Xa zJQR5w<>o1QEC}`$dS`vr;GyxU-F7KEo2EI;9DJn_DAo0)^nwvHE9 z_DLmmclgJ)AImM~)t$?!XSyY>-R|D$+c_qZYZtzik_$WUyM95a?d|mos|96)OK+Y# zE231M?)+_Dw34*&O$+Cnmp(_ktee4ZT0b$@bK4)u=B{f?_x{l0(@T0ClAnIP^v>*F z)nwB<(|gq)o2oD$Te@HMv3Wtg(Xm#oS?lf`*j7I6--?hg>rD2}HJjQgRaWxuN!@)d z^KbW$=r!gjc{T}ZED3M)v#Pl5VDvF=TWRvVYtfOltc&ZqfBt8;6M1_karcci^EA3T zJlLPt*S_-P3tj&_LR)}qHzzY|%i%SrEyIqaTqP2aimRo8NAUUc+l zyAp2r&#%5uz}5ASsB^^}`OWT{>-4?(fhdljWWi)-AP(}Rf55tEP2AbHANrsbXSaXk&p* z5MR<%u2(GU*?GmpflI_I+T)Utc!syWNM{pcXF(v-#7`nKQ$%@=^~tn%)rIN{El~Qp zk^k?qRj<|vYc$#)~#31JgP6crST@M*C#PI`*6aAOYF}! zuDrc0_}b=u>6TBw^C+7aw!S@cZQI0~C&jPz+BjdI^g5*W^2g$3v5$|`bLZzgdv)Q% zo~IH2n4GI^CMI*}?o|D?Kt0#8W^>t=<9lU`&p$iV9&Pe=&dbQ8yBTeNYFD3{;ITU{ zQolOwt8R;YVmk0>~ct3biLv6 z1##0wKbW)Z-x;iRFUjwyZ3YjsdHvDjvr?z;I4-brQTRtblcqJxUmenV_OZS(@l&6* z3*W!)oVT(c7Tv$H>b2Q+zg2ejNiTGY>u(o#-n37g(Q)6-qBAUA^A?wfx}s0X9m{1- zJ4(HHg3A}>yy?8be1GqjYWsUm()};;zFd;ca`(wG2sQi?sAh9D_scPXz1#SNCw1QU zDx6?tmFl)rxsvUhX~PkXw&pYuevMW2r3`HbK9)^_HaRtaEESlSZQWM9<@xn`$Gr|3 z{vopQTRvDWc{WXBpQBjnVZ#%i>_-zdTyD1qb|sfQJ-)t0Rb{36Gb!F9xBo5hKQx1F zrrUm*q-inT=`WZj{*e?}JNeBVr>na(<}CVconk1p+bqid=*NUR$NxhXGk_DOAZR6o z+QZ{wKe-qf_DC==Xn|*|-rf+epBuqmBYa)*zrD`yC!cRNwytrnaN#<<5OUrzBrO#S7VawFJ7Mw4AX1}|;tor@l+dcp8 z&sE8mc@SS8@%~-y``fQ;j|-o-`J&OVHL1I6?GEpwQG5LK)=xium+M_%pw_{q70pfc z=2ain^zZ4E=Ldca+jF*id-X>?*7qTX(Me~I?SArbcj%q&?;1P&U3;19)_3Jr%zyH; zZfA{yo_t85{W+})hl9;=H6BfNYmzwa7AY)EvQ!JvIku#!e^rF$&O80>B0iNLH*{Iq zEP50;XL5f3$*0LhKX-`F|L|zC)}9|z?$k#ed|a<(*L;3e1=IZCkCio!N5wy?vc`vf z5EY&MAyhQ}@b$ev+LruWCVoHYL+;OCvXwuU*!)?S@@0wm{mDK1-XG-``4e!fXnIWD zlcR4x{Y=)cTl8r8kC{#Lt3Psk{_z&we`x*FPtv0MkG>E2BUc~r!CjR3$7F}M-}b(p zyKtTJ?_ayW$=#~Ic>Qweiu~^m_!Lwi}uBBA(wbwUv#vUoA}%0LUOO05YuYsv>Fu)q5A9Xi`_n?#K_B= zKRWpKTiO22uP-VaNwL;)RKd^~(H5WwtBz%%#i)RZY*sh1VgA`aHq zR`0G<(@6J}+wi~S%q9QS-ifN$@?Snow*9qZ?%A^LAI6bOTlu9vww&Fqro3~3gTDob z-_(GEJ0==T{= z@Xm>8r5m#@e=z?ucb@hay~D@v%d~H?^gQz{Fs-kx{=s~%e@h?U|G{6_$2~>P-;HNi z!QKCX%ccHxFE_F2O&76QJ#l`*GvDyLe71(C?p!#c6S#=8U*qb81CqSUKgRHiy$f-f zsV4GJG~&ghef4=a_bd(!TY5Tid8Lt<>DNRvuIEpdw2419s|uX*e7COi#^~*Cw}m;A zdpf12SFDQBVtExaVSUnL?}$4mei$6jO>R}wnpwH?rDL(|scA3oY2FOeOxmXQtYhb_ z4~B~t&05tdb>~=IG4Em7c+G%`-b&9pe@5BsH8Y!!Q1`i`94=rF_lVWMp!%d0TeS5coXZF&D8 zP&p@aQJjfKXYZ_xNss|i@^Pd^L8EF~SXB&EjJQlMU`8I2*Bp;p<^!VC$ z(~C+?vv!2UsBM^Nb7`%*z~*Xy1;e}+Wp|}x1qwpe{Qt$a3Hz=&y7kRNy}NA_UmHwb za{7C~G4;$!-Agx0yCT+i@+K*t4vbmX;XCU_&ux*5TCX3cSv}ly)+K0rYLS8Lo%$ZD zpSDK+CmS#BsJt}Od{t!7vy-(OlMTZH;-3XYMcy}<+`adV&+Mw5uYVLWiq+1Pe#|7h zR{!jtq!9lt$K59-yPerJBP()W(K8DnNzY@Mk5?_~i_PiT6XgANW!kc9JNjfTQ_A)~ zS!$LPv2**orZacLZ8|hwT6#WMC3(ltGUi4|{cS0(Z$%#7QExXT{(8k-nE9rwyI(70 zTI!zt1w{o?cYiIKnC!OMe_twVc=E>UciV66Y~94U`(0Dd-FK7E%zaojtK9YmlgQz1 zP0QpRH*+8%27BvVXZ^FT6Ok=|k7OgCU)#99PY8~k&#OA#3+1oS6 z>87N$b))rK>yQhloO3*df1)&O+v3~zCKkTp@0a>kf4ryAW~KYf1(iF0 zoGZP3t)PKp%}2wzjkn)C`rE8$k~eYobEj-xE-S^92eT1~(41Kkzn zw$m?ZEvtT;S?4@|e)+ynOCPS#{9X6B^|Jo`AUkEzZ95|NTR=2YKh~f3xt-e75n4g>78@f<%GS8^xj-D;^wI_~!f|>s{Ky zIlmXq*?a15m!=f)*P35?hD%A z|5@hUZs}7WxB17K#p=rg%&)vyJ>TK5%8PrqOjc;Jo4lQ%rNvgVNGi7Eq}lBiKl!xp zIH)GAdCiuw}JO;d8g9o?V!)w|qL^P1eN) zZ`E@qTwuJCARnA=Klw#g*n7t4!wiMbKa_LNJ08p1{JmyR!<=agEP1OH>!)hG4F9lb zdBC~{*BFw|@@F0w*x2z=SGE3>0`JGtB^P$C{#Y1t>r|PgR9n8RubCtiRW-R`m%3}3Ky+Boaar=Agx66~? zL|IAKXfKbP`i5`onN6u@E>Au4Rn5xogg{Q3*A~O&=;btM%n1v!zEvd=ne)XlrIM{pJ$6{JBl0EHtx>Y5m5Halh@sow>=}Hzg-8 zNfw^mYPJ_??XUH1b(?y21_pBh1_mW?1KQyh`{X${IqK(z|16gd7yUQS^peJ>9ffz) zTzxM|y;9p06dgIM#e&=O?UY%k{IZT4dNP;j_%7)@Zk%LtDrnlKDbuzJYhoAO2-e3s z75Pl^^wjZOrm|7BzA))VOH-Hmae>y=izJ+RSS>$33D@j;Tx6pd?&nqHHK|&q(wnDp zk7?WXhi?P#XoufZ48JFNboY~q<;M%;?z=%t;37i zLGI<-ss-^$hR1$7W|*!1Rdv%(cgwEd3mPuHPm%n(H1o1qn|H8qTeZXd36(EAPH&O9 z5*vI@ySwX45ChY#1-Ze^OU1j{!q>$gnYoVlOY}kmwNsi)uN=Vjfo4%0za;Wg6-ifVy)RGJC-*>e;vDx~AXc@Tm7zed-&M>U{h}R~5d@vDlQnZ}M)9 zMY&fl8&7twI%t3BSLnx7(fGiRq0@ML*Z&L*`Dj{S70)|m{)SrN<2^klDJNIV++4c; zNzluAtvsb^0)J*sdM&kW`m6L8OE0N~9d(;KX|`cgN9NR)uU=+JN$clsoTD_+D5auO zef6WBw)KytrOFJDN9wl8m&Dy|vNu*Hn(y<7HTHrTHa%b4FO3}?ydJi}o3-TSyZF$9? ze*6BRHf!y&*@vu`9#IdqS^ALu$HF%Ghnb@G*FFf_EPlBB$IQ0*k0a9@4(orAxxC=v z^q_O=4IJn2NKAX^sdz-0`Sp(F8t<-G#2w|9s%yS)R4EmAKY!rG%$~p}x*O+xclp)zyI$D*S<==` zof~%ETYhSv`LkI$S2}-QcQ1c@R`R6R3+du(c@wUg`6pk!wah&G*2$-THk|WzUK*%d zKdtSDYOCR~X@}qF$B^{g^H&x z6_iLhfUyHfiy8YCbyWmcgWaa%|%Ijn5pR9e|zh~M{ zW~C$l@7_3kdHbhq`=|v)F_UA=nJ4b4WYax4PqJlFVJe%Kk=#5-3(5X73X^R3zZw>8 zTQJ|`(B}hHJQM1({(YBvbM)w-BTfW(fMR?hGz0f*CTv$-LnlY zpUQZ>qiade(&s-nJ<3|qlX^K~@4BA8%ry_1CUhS>c6IZPXE_C%9w)9iC8@D+?i}sS z5q5jBq$YR2iVVDbdHIp4M(bp!UrPVj#g*+ohsQQG#(kMl7~AaCOMcYvC}Ldg+@amL z<@NE^X=fj`+0{>axu%ZxTV)&6<@?A9qa?*(RsY~|lurCroDjWz^uy^j$0ai03}>}Qc{vactK z1t#YAD$1?9CHUx>l$-4ZQU3EvuJs#VAAkICv%sSGo({u*Ex|QDHzHpCckmUMeY@kV ziC|?*#u=f`%A}7b6MqP7tmyNoX^W_tC-GC-e_spZMycwfQFqiP?TG#In9s23@02-W zk0pfolOk-oY9AH$bSyX2ns=D-BNN}R8`h`fmo3+P&6gCva7pQvU9B(vSeLgO^cbkt z-)XHqQW^1RL(|2U3YPLo{tr4VIt6=#)<*^&V7w)}$oKyNiKp6Ew(&fE!u|NG=p6Ry z_7$%U!tdrRSROpC&%q`loARw(_6-|CzvbIC$KP zfx(gCbL!U|JrM?m6m13u1!%3!TR%6FJt5?&?EnA8k7N7TofHlj`lqA_nF)#TDtef( zsPHg{)_BHEYL@=^PF5vr_11_rvDZQ`TD>~t7#bpEz;vxq`gYdztx@S~cW+(SwQT?Y z@9*@cKM|NP;r;J>=Krc||_Vx?17VGxOg(3|_Kcs7U;D)Yj>3ABF1q^{4*3k`s5#G%oI(_8y6~S1P7X zPh%Fp<~Mm+*sQBeiMVv zm44`_Dt+BY3yvx3>x#YTws`Zfqh^bTas1=WdqNHe_9n+gDeir`G_P^@KK~K-(w_^D&EC7E zFWkF$V$Pq5$HcS$BS|5ZUNvofY(V7Zn#iYrL{Do^4_O}@wXH@l*zc-UeR6Z4kjWumRnssN zfxKC#uk5!G>Wg%{5tYgEcv-uCauK_-uW#Cv%#=`-TOpT3Or@IAP99rv@lukT_o^#O zepOOR(uWUrTs&Z+cKO&T*3Qy{my#mRrYabQh>M(fY$O{oYae^N+l;ke4_4@GI2a?r zF)Q`!*EF4NH#nrbwoUR8(5mOFVt8=pIO`$CY`M#lmG=)^H!m*A*z`Hv$nvx@uiE9n z(8djsviw(PUVO?X=E^*=N_oen4z?%OhA+3wV!m)^Mb8XZ^MeX2zF%|qJ!~Y-k|cI{ zPLIr*P1PD(3@?cEONA*2&6}OCZ7ZNDII~0R)#d9mKk-Y8SY$E$%2=SMcVBx^z2h=Q zvmYBWr>=(t%(GCFHkZ>Dkj)g#V6%}s}XHEnV2)jwVm`aW}+Wc!p)KkSw_L<*nb zX1XX6c-Q7N*UwiD-8IhBHVAKa?K^6+k16Y5QmqZg$7O;xdh6Av{PDT>IKwP@rbWYj zuZ&HBjpw-zs=D32ot#!{Bemg{m)K#k#EyDyCf~F(lP32r`f^94?^J>J9j2Je9EnpE z*~(-0Yz*|V%|2UG5gjYNB|m~K*lfZr5d+@$&R1(ny+mS@CBMEFm)1RXPC#Gaw&}j0 z$MIPu?29az)Yhy!x#iR$UhT6P3pVP;E;y|uC~<2_oYM>KX1i~uI(HewW^DYGvEb;n z)teOs>RHb-zZH()pBBP8#h~rmm+o!TmgN7aervlY_Se_R ziw@7MtmU**aV|*EP08loWcF(94#5zyiL%{C7Jpr~>33aPc6Vg{Ox~=c!dra#@BB2L z?Q6B&PgzQqKRxPlbji5|lE<9F685)B3EjM%EUVUzTk1)2xVXE~PLSaI}`*3Aayn#xzR4`y9yImsV4*)Z#Xph;E#Nm2g! zvJEE3(n>a$yxnnTgJ`a|rU$3IySKn)trXWLnJtsM6dwh9DtKRdrs~I4zoJ2e`|zcP z(3Z!F#-cA|yL8f2?y+{#HwC+5cm{ZRMq@cm?7?{a2_z0AfxE7Ek81-?l?G|TB$ zQg>I`;rlIIMQF?Yt{>8Z*Z-zz7gcUJYj3)BeXh}}iFtp#UtLR#dTzTXoaNhubNipp z^;s@IrGw?2M1aemh57D{=lDM>TgAFxc)$41jB~#gMDxN}BNxOSO|D;Zaeil;8#7my zMU_*9(+)ASS%vlfCo(>pOH2FI&&_Q6J54Za;*xjwB{s}b_vcvs%TDT3^x3x7V_*DF zMeOzewB1G7B4g`M#g}FWQ=_8_4_#7Izjkn2d{#oe0^38ER(FkMj(tCRH9WjsjBj)} zO}BWL-{a;~cR1hmvEjt&vFW~I$Ns!DT`9jbd}X~;j+2F?*xw+F`cso^=T54qUBsdj z+QlSMKXcXNUpg=T?1*?QY-NAaKl9I)bLTrA&42pWv>Tx}A4U|I!w*X}g|)U&VqM=ea$uv1>O~&4}GJrTnUSyOKtT%;xlSSAO=_Om_G= z`CR?8{R_e_{#>8b<7|9AeaDaV`V;HE%{r(5=|0Of?@NF7vd6Fd<@kLt7eQ+e%|1f2{0VZ1$LBNEsR`?Y}eQ=)(npJAxMkO5Si&&goozbfbHZ_Cr2xt%pyeRLm^v zdxHF)oB#0by?^QF{6E{y{eM)xVcW%Zze?(+-@p8`_8)_5#xX1R<^DgMuUJ{ttE~EO z{$G9N1iP;@&dEDB{)sp23EW${ZHfCrGaK7`%k(>U*$KX_UA1^a%9Svy`eWB${jtn< ze_&H_!2RRwIfC_WOU>V&$iL#r9N^^>{Psltj_b?nrG2YDnlDIaY*O0QpZ;Y+Wt8D5 z6P4i38_m0(p1pX&?f0RML$Rx#?m6Z4QeF1hWj3y`JI&Qa_6GXrCd0K_c3Hu|fdxf`MSNOIy zt*%aWMfY|SiD@B$GdB31yF1|nOM2YCJ-2yYNorlaoocVWX~l0&b@TN`i{I`je4V*z z)>L0^y@@kpQrw?S{eE|T)mKd`i}0D-s@Hf-;?osa&9OCNN6Ieg(E6x=@cDKJu6>!B z{Z7N%$A zI@>b7FHvw^x?e|!)%33Tql1#m6#K+}a-G^e^`=w+*H+OUebL~}PcORX1lq26^1brx zOYsg}k7<<(2QwPp^;v$YmI~mhXYqgPW+CLpD6wUx)U4?bRUKQcW)z2b8pTey>#udo zO*ujFtTKo8Yya*Ahc7ufoPU1&;Y|J4P5A}igC1piq}e_a4}JCb`3~hxGws%U2(^f* z$KUVbzdU2IzW2W7dqH{IcW-@Fs2ygz?!*iBjgc*}M8XomX) z>9-bhzFZctVl(MkZfL@|xbsW$8j%|YFV(*UE13$-is)@wrDH0zOJ>Gj$-gqjPG|i- zO=_!)OSG2VS}$?-z^kU;nG9^rUUTizt)EWWwM07R)v=oT`MW2#T@m|n$1XfDv5@`g zw#ygVGj7=KeQ}1ppS2-|C8|49#h2}Au*lr*oE%N7=NDDKa0fhDWLcsa%cc=G%W=B% zKE64+3$$No6_^Rt)u&U&y>bp{~9>){L>SxlNWC<+Z%Yr zFWKwh(;K(=K26W+i<}qJe}3FVyK3IWod5Fv?UKdbn`>{rH91$w{PlAt^YSg1 z4OiF9^68D=dh&4e?r*=hl+9A8Pb$>dsI$Z|!=L?T`h~zPV#^BELNYEytXk|D!tZE$ zVdE8+LY5aQQSPTRY|B_aiZ0r$;gmbWx_^;ZOK(De-+czf)XOJLCfE6zPja8(*ZI|H z7pGHG_Jb>DOSoH#MRFHJXKKGVxlrP6o3P&jj!SP#*pFE8N4!6BqPI>ickz7(-}-V! zKf|57Hk@61@vhX}#TUzZ-=+4xQSS^Nfh} zQpS*ntMu-<3QN9{x#u}KtN7EL-J1Ka1%_;%{6L_!dSg^eK~Zhe&K=)3C5!u>Thwya z@^Vg|@~yB9H`%Q1*~QBBrXDumUAx#ybxu}lz4sb7>y7%{>f#smsu&KvJhEmTi@Gs? zlG~99zLD%1d)#&(|B_J1|JHZI50(@Smk^Qni$66j;?vSB73;q5vvbz6!%LQ}J2i8e zrXN>!*4!C0;(}jmty@|8d(NTAm9OJwDT-NM-Z?of*MH_&i>24N8w!NKHV3sU%=;nW z-PgK)4o7}{q(itC-*d*F8yEamEO>nAoaL8jtMJ0uiH~+Q$%O@ayFGG@%=*&tY0K`A zn8*5z26Okjzud@D|KCx+FZ!D2=7$o;y_U?_+`4SB_FBDr#;0G-czUWe`>w~oM={s8 z1Z_Wm*ROc{gt#Zg?-xDZlyOx}{LZ7Pi}Kd?1~P1KIJ|n{)@+S>{uRp^-pcg&H+ZTq zc9n~HuJ-h!^NI=IEXX+v4g>Tgji#Q84<4y}nePfvQ!c=={c=a>KGaToY zPhMhmboUv%cL#eW8ct&eNin|?7j zY!iN1Eq>)@=Z8NEb!CU=ebYL+?SM!4LC^V%?>jC^SDN^D-am$%vnI3VwR=`IWJ>OJ zsBh`=ekt-x_^+hYPKoOOPW4Cch-Q6RWc0DNUUTdF#rrk4^1C%udCsiRd-1#a)Di6y zk6$vy`3K$qvEO;|bki!=#q}9qv@SAAHSg3rdGY1!j%V3lZk?3cyY4CT8|g1;O0&%$ zd)s8XoRhT9e7m+zz@oXYq+ziLxIYM}BLpshBTxEI`_+ ziFYpBh3HfD!L2F$ihKCPxi&rFwQnp{zaic|KX%2Q9HU)rNBb%lcTZT}rx#!rX;LNC zv#EK`q{kC1WpA5V9%0^Cnq}@;)=yu z{q4TTD9rqzWKyw=h4I9DOTUXSZw{`S;rm|OmV^24$&aGE^%q_+%l&0-NI7|5MQGk9mzUcaUgjRCV$b{& z>rlnMtCoL*orBMRfeCgFe?LzY`ebw>*=DZWf43c_53fZ0n(>d@m)|AtcZ(gX+X*ez zC*ChNyNKTQ|?SexYGeQfNW$jay&sc#4z{O};w!>zkT?hPV6`@176%_?JKQ{qzZE8>bjD zWq1h*TX47XuAay&G`YquOw^2T#w&xeRrNlF(?97xDRlY$n=e4GT-f%)VZAc-j&%n# zCvFJ~=&*VBQZM%|*HI7Gru+ApI&Y|Cyz$gb{eh4F!D69yZ{fyMYr8g_S^n1HiC^Kqg%RJwv+%oxa zvv5*eG}lWHi!Tmmc6eB9OK(Y;o;OcKgY35+=do=m4P1Cusor>HCum3Ao6~Cn4`JW#=^0>J%d^M8@ z;>e(uOnZh+j0_B6%#$6W?CXP~y`>#R{+&y^dv(Xv9bd!Vsz%8_3cIUR8_W{OqIkop zo8L}E?WBNuZ294o#Xr`I@Hol;Vf?4@a;D*wV_XN@=UQ%mZ`8iG{zol)g0TE?gQiv` z8=YA%)>_{C`QyQ2pAXWjCeL4CmbmDa&~v4*$eIO0JFn)y)%N}HDfnvSPoIc&^=Z2# z&9`Q#811{T=e|`RX+lkhO{P}q3+kLzj&F;K z{@LGhU(77^U;fE;%R?e-ckNa>|1r$>*vao}>Q}%1WXQ?xV#cHAAo!S(NrzS9a0Y|? zV!LUav-Q89$XhejWy#qe*=to_TP_SRT&=^Od|2qeq}+dF)|O+;?h6fBrg$A&^!9_= z$FB37=jskMp8j6)WhHx8-b0scTaiUy*6)9+eqjg4D+BCEsh|bhSjE{H7!vsy7}UTc$~G~g^_kAn*F|laC%JVnCQH6) zP@HP$+rqMM~y-kbaLdHuZ#;RBI(dJ7`*4@%Auj5*%Rv2+iQ zv{8f>*QVGhM=xu=;ZUlNm_B!sho401%zU>6kEZ41pW3kWk+7i5VRhvnQ}$Rl`?r6b z$zj)h-t_~Io&F{9kea|}w*}`M*=%I9{E@fTKAB_TN*xbZC)W5**{^rl{Ky4!*I!{0 z_ow~*X|PZDSh?~KxqbQ%^jkhQ8^leStiR&N!Y+AD3#-_O%bzEwo!of#>ZbZ+F&);Z zTbp>QmDW%9a`Qac*i(k&{=2~?5`q$Z2TI-{CUa{eg z*cr&0E6lq3$%|>5mpnh+*7WUk@#cOXU!5y{Tc79H&NdhGZmV6nK~ZX+DiA5lbQ~=D0**IzPv2;O#Kw|Fy3m%__NYY`cI~p+@7*^zhuER-%ao4 z>)qHng?;L-)YnHBB`(){eeRdU-dhWn`7T)e@$ZGEGL>|T-;Xy6<)^$h%wM+s`k9!U z*Idg>KI8_n-xDh6ym>25n@eg|CdUeeJ*%eoNX9Zrp1ZV0ecP>8rn?*VPSw)i@oA}c zTHwK)KlN*GR*Tn}o!Aq#?ep|6m#kEeU6}kXyW!G@g4=C@S}!e=FP)K8b$6V{+7VwEOXy*|R7AJDeP{UzpL;nE#yksc*9sXRrBRJJnQ4-K6J{Bd`3iN>Tf3 z295JGDwzDUB95(TGg(%-_j}Z}55arZB=SbaeQDM?b~?>2`-W7Vnw9-=eTgYk+Tu@T ziR{1hA$ww7^K{WUwcktY_08e}KSuK!&v+Vp-p6jiqjIUbetQEqsec{znLmuTiI(g- zVwRz2n)mF|wB#o(S644G=-SV*c)ym#HHH6NRj+mzr=B)6@3GadR_A(JW0od5=Z4j3 z)3m6gn}k1erMcwnck9>O)7RCe^)BPb?1~uC9evHYfrq7UB>wwbcl>okT79?l$ywXF z_GkZSS4j}b-=w7a`FZl1bu%KnrmmF^dnk7D$UVK5BWtXUcURqwDE^jv_IGRDf9pL* zZDizaA{HO#+p@oK`x~pryxD&jY`UA#7}`rsvZ`R_~ZoMUK8LqZA5$}nY6?a>>reCaU`QEwfDt0BN3H9!(u1!z8t9NIT*$b;%r~GYC zruUw`nVqzWvHaKlAg%T9zFm6!u_QU><)1oH3IFL|YhE_kuFr92U;k$Powbvab1EG7 zOOgSeWONzXJNE|z$#!*;BenLjwVL^(-eVvVeCsrK6?tp5^N zJvOucUAOe{ylwfODhpLr)C^wU{-ZxJdaVWL>7M&UoszdV%h(a|^8xENoH^Et$jr?v>o#<by`^CfcureYbOH zN#6B4FC9CQ=d9y-#Gzcppb-l_Z+3W5e6FGc1>f!zuuFn>AF3$^kEpxbt zNzC5ixx_5awoig>3iTe=xfN4_I%fT`_<2yHNc4ft1ck%TxOT0wunYcvMA`n$#QSy= z4jB8~iJTsNXmj9Wvj?97Vlq$pE^4cuP`K0dr1=T=`qt-9o_KsYB70}DV#4<`0vD^w z3W_Wp-1dfkDdh<%cwd&rzVYb`&9qhj*Jb|{3H~Q{YxVKGp2rqZFN@hH*WdMja`}i@ zo&19TieDZX*}44*JC@G(*`|8dCnmAje7CGO?i-$Ls_!Y{IJK&)KR9{kv0qmHUN1}4 z7BAP9s95n`m1Xknlh5vP-P`^4p4dZ?Qrqe&k+apj+Ahv7-FalsX45TxF@+aHvSN-t zcKKBJzt!wt@k#yG{@*S1&)dfL*(yOTw|lv0U5p@lzqavwG9TH2%AV99?zc;rnj?=asW29`IFL z{E>?--o@gh)U0ijFShJ{HDR})?>)v~vpu>uKcCjJI#g7Yt-ZBc^IrLPhL6WNf3bMl zoD8vAyP@NY?e^+TZZ$$~x`9tF-8=gI`W>aShEIc*{mI+pbF=LqS~dFix19O|76yh5 zljkN|)<*{ihl~6(^R!TuadEg35z-ZQNOz<7YE_SD(JT!XFO819H=Hfh+z(s6JlW}x z|E+Gl|J-vo+V_>d@mX&CO_eWonO)g3`;%5%@7r}Ma$dBWxn}S8sQYo%Z}ZpgowWb| z-^cz8{tu%V?#>AKP{hDHgCjvGnClVak0nJ`46MdQAG_-3oYnHsm=XLTi$QnBhvc|E z?w~o7lMER|pR4}anzpCUeAY)bJ&%vmY*H@r>o%yWERC4vH2p&NSr5gv2LcK_7uar` zF++OxE(2q0TW3QvIcxW)PgLJ_iJiPs&fe66TU_1yk^%hDdbxsjf_#_Mmk#Y~?Pr=I(Sg-u=8TGaFA zts=MnHMgS7R^Og@r0U$o@U)z6?&BAV(@iI*%~mW~QnLJ-R)IkX&-D#TkKNq*zllz- zJbuDu*%qDeKY1r#zpz!bF+tQUE$y@4MVA=~33F4cbE>{b2!%Vxi&h=aFT5CCtr_Ozw%x0TeU9UE<&hqXkb<>@>X0Mw< zbm8l}qR({A7F`NB`n~F#-SgwCWczabKb4(b;Zt+y;-u+24}V?!U{e#1_q4045{|A7 z2wtF>xWwn|$=fy=Zys`1K51s=)XuM0|Ed%n%dgSB;m)c@2J-|mZd*NHGtK+6PTQ(O zOfT<*_Ukp;@@ufa{Fp0hR-`5Ka`$4tSdKThxoXVvt&VlYCEf|HUL9Piym`%SruJhw zw>Rw$zr5?_+>KjOZ|&MX>2~eJjdMaK9v9UN3tf{K%l4(OtNi1PJ0?{N}2n)TTpRc7Y!??SemA?hE*+x-aOX>Au8wAvN9aS$@g?z03J#&DxS{E}?F$ zSG=U&Pk#DthWG7jSu2He>cw-E-CkO5=$(_!m7VRrP0VxRfqS~aPj^q{h&M`pn&Lmn z+^|!YD_4KzzT8zoc8g4ZTq>@Uxc5H7Rg_zMi>!xBef?YxwbvIO9lL+x-J}b$m48ni zcM9Fol`a0*{M3`T>zcw%q*d2Gee_G}V%%lfRf~1Z*Ua5&`047#lehiy4i;R>Y5!W0 zGE2&M*UU)_X}ZU*&p)mI)a$pk^Tu5*6+uQnl>a-ISQ_yg>l7^F`!iAIL7~i(e1!wM z9`0#>thi1};7Rz2`ZCALmRTI`2QOZ)=YCW!e#!gh3$133z*Vjczb>5L$jL0B(lz^N z{0AYG(_-o|vRJ#XRTZwZXM%`RvP$lp4U*ZA7v@JYGG`o#PT(Fg8* zOJMxHE_uVAiZu=E65}r%zv=%%hT~Vv<+>>If&R}xZ>P$+OVRvRom`*)XzZ%*us(Iu^o{bS_Aj?8rv2}qm&PNdw&SzJ+9lI& zJ(l_VLsI>NOt9dQ?>45VM0%!73f?mJNzRqO{ZIFIo3Wn1|5!1ORli`>16S7N3L|l1_7eM@{U7H&ieJ>e`JK);dDNc7J8x?q^ z<9r52*R@?++6#hM=X+MH=vtYy!r_s0QR`+I&G4e~t4I8ocJ_Aa|6!=pc>Lxr)7xFX zHO9u)#{X~LKeu)N|380N7c{wN#vH2Q;&%2p?D0_Ud-t7?9XrpTWzL&6DZ=lOVslwW z^}cL#t9^INB;2x&KU2S4pmYDm&3iScCe*)OyME@pqZ9b6qn2GZc@y)3y0# zQ3vn7W!}6sdzYDgcgh+2O}1@CYu}pnF3XnNrt^4n_Plvf>o$u2`nv7&#k{hZ$(sf8 zmSz5wuC3QUKkd|~+s5v8146GHu ze$%NrBpu;3`PJc@&poR5wr>#P6BjL9vEBMzcSk^ z9~w>n6&qNTYLr|B>#84YKJ>ihJa;_D9|MW!>ehbCZBH40y8MgZz*hdH(yHglu}7LM z1dp7|Z~S9)v+&5tJ|(xnSw@jQK_;!7r?MU@obs8NzN2aNBcW!S^+&(H_o%g%pC-`6 zUHB))rZ?MZkJDYjduz|vmrmT};K_bdDKn2v_}F1R!$$Y04`FSucPwP+Jf&dlH9@I2 zyul@Pf>GudMuk6zKXm77IzBQwu}A31HYpXoW}QjPj2Kk39nz*KI2)aqB=n?DD#e4X z(r1=BvqKS6N*L#)36Ar$9lf$9wD4^5nzfZtp^`ButVtzx!YUz`@Me`%%?ZAj_Q){= z2`CgdK6@9Bnp7h$ymr;+WMHroVPMdhyfH&|^2uz0`k(cepGp4L+NkW_!NA8T%8SS>+V=RfPhHd@ zn|%isocE{@o32_T7|-?aG?Uc#^5tyoyR6&TcK`nE*3MStHktYF$#snf6B!@QTYRc; zsqN|~YPW)yEqtn0#vO5E<#VoOlZ^Q_Z!XeWu##s%a{Q{(%>jNs@1$*BD6Z2`UdH!M z`tGLO-x*me!Vi3!`0hzY)`t28tLud>Ix5eZ0%DsBcwf@&2?6E2J+oZF4()Fu(0aX^^k@OQ}XytFJtn+g7-rURir|rQubH zkosd0*9-dRg>7mVaelnF_(Yj?(aGgY+L>ppF(^qq6>{l#)zm%3>(lzDT|Tpy=~{Tk z%lEr@+gUhD)*hTJ603eW>)uC)19PsN__%g^(xTYLkjg0!MON=w_)OIK?s`#;lgGMv zEK)L<#N5qq94cCM)6V3=*@K!dT$N+FZkuwY+EpI9TEAT3k#@?)g<6u_q4GwXO4L_t z&s?JJ?G)AbDJpbX%;pp9cX!rY+|tkaZMD)qwMSg8$xfzwr6yIC1WjXSdUWx>dZx?O zB96#nm8vJdqCPvndUoq{T5YE6uDnTgUi-omcZ(bj;nmJzJUT-m`*m%~1ff~HnhSoW zF|q2%em=P0aq5ryRZfhXZt}efPWjAKG+&rUYijAm*HdplSib&^$cK{ohcv8f-rdy- za+3}3x|!XZ^ITW4_lHv}&)0uSS8Lm{Qd}H9SU7j>@Tzp(xmG%DeVB$o_Q^QSRMkzf zv%IyrQk1&|E_~YW-MQw&wRH^{to!%o7H^aGzUzNXVV~ckzg=@P@7F&_^f*@hL+$Iw zNoSdl&ROZZGH)fPhlQ1^*Mo_LL28@oauaJ+7GE}7K3njsO6Ykvt=U3h|0T@zK27e) ze|THxgY}iZyp0VhdpPu`6*A~gDHOPCbS(1j^u&;3S|e{ip-_nb z)DJ~(t;Zf(&zAJa8y@eUdEkqcX8!f!Iynd3f_17e`WXrDIAx~QR{dsFoeR}Ek?aKO;6*;fhOa3tbv9{;_ z$5-Damc~uh%w8H9RuOef(pbT-`qyC}s66Fkx?h)$n``|a z*JJS?%?0bHf8_rYd|;oQZPL@4CoO4yZhb2+mwn)_G+o=9ou#(uX^ro$X=+o%wfA-{ zT~@rT=+fi)Rr9~aJUe~R)7d_8e~#+CI{rhCPVExiaP0e2?QEGVcB>cLT#NV_yCtUey|Ra9RnT|u zO~qfU;(nL7vaXL7cG0>sLFM9FLEZfB$z1n(eK#JI?b_RUcaQMyiQD!BcpI$zvgB0% zL8rQ)7v4(gx6WSp+n`Z<*L24lO>6VZC5?w9OiDjxpS<`^U3&lgn29N=SH4R(S~k60 zbI#24?hjVgdg;qY@}uTkhTXdJs{K%@*^g3>{o>QVXw8^bx^~}vanZIU)4$~r4*w@+ zUF_JqV|JPTf>=?ri*@tU_s{tzJMXX8t@5gG+b`DbPrvWVVVKzL} zu~;%!E|T+j&y=IuCYN3Em+OY?XxC$Tk)meSZp9Sma-ds3$y29L@L|LsrB{!aoQ<5* zsjiop`GzU**#(2{)N4k2=F~5bTrg(7c-qbPulIH$zCPf*%ht@3G zIdzWsd&PdWbw&3A&c!(V)w%T|MfvGDom=UTmQH9}d!po${gb~B{5!=a&EKMGG;MLX z!1l*>8cW2pg_}OuM7i`R`tD|!o7NFsYP$2fReiH)Q$fXL9kcjW5$^n1ho>F>yd(KW zRNmaf+fJQ%r7HR>z@KZ1QTEowO_L+P%FPt2|6pM>UqLB)Q9K+A+QLvfH~U{z1zCmMXLAxy_#Ka(y0vEhac;%q+)PVD z&+WYb?hgN_zo$+M&pYk-eN*3_$Ln<@MV|an&w07Kob}eD-YK%x=XQIP1@ujvzd6FG zNwRQt?dh}E4c;w3BfKV*aoJSUM3KTd@4S|L<1C6eQ0g${#h1PHPbD@SKY1fSM~`Ji zhIa0WY9qrZUOW#OS5G#&)XaB@(P`DTi9&TA%hWrrD}Q|Tbjzwu2J%G)^OwY4Sfzd{ zNo(HO-AuiW+AA`7&Zw+Ym@y-=RBY=;3)QbZ0bWnU4lynCNO`Jsh+p`V(V>{e@F1hT zT`!i~)a8_xW`a=3!>iiSFT{Rt?9998YgRPLb48t8q98wecIWFUug|KKM((?sW4d{F zlb^9PU%}t_?6;zIl}8>wObef$<}S{-e%p`u&uC4o$E_FQwo-1mL! zK9`R&wzc2vFD<^dbM^$aoF$sapFF8MGq?Z#nL9IQ-~a#fsX4>@htZtQJ5-Yb4=Ln* zPV_t^Tch$&?^4Zg!}ze-@_vvDThzl$oLzp6Lu z7^9$R_OyD%kPCe?`NF;X@}zi}H&&#DTLuKV9@SW~sc)$?Ym)4@4fn3exawzBwp}z! z--Z(j7_JXyV(|mVSC^V^-pEdYcRQJg2^)kQ5>lBsq0@t=S zJet&y}wSDv;h?PkzcYpe4yi#Gq7_iR_np1#Dkf0L_H_jDRc zK9&%6^vPFNcbYn}T`jq3e$HZrr1tqQl*&@yEYwJfZ)2QXq_?$3dtUa#g`%@0W1SUG!&%@M-I=TAuDlHj=MB3iUm=Zn;16#($QJ!74n(b6zIUxio8I1uUk{2kKJ)Wl7dg}n6K4O zSbW9x?uqQFS99Autk+-uqpC6a$JZI*yXp_;UCN#QbE#UbOsUn~Z>oJqZe46G{1t7; z@=x$!#nsC{*xm-21m`Lld=%drLCJqaRv@?zQM9A|Y9sK_pO{_&U1!SqL! z+>=X}sy_O5xyDfNhv+`v{~@CP-Yj#NJYlWUhB<4LcFb9_Hp2D#G49og9437N7Xp9H zbDyG9RL_!Znrq7PPRq;Qt)})$W0K0*iq8sqd4DY<`7iC6`k-v}i*-&`PW*>YEmc0j zb3eIL?776egXPW=Vu$vIemTpc)F?0Db!ppw4n=#jc?m6L|2!6Seb^wt$MVr|`* zKhK{8Z&KK?LO;O6@nT1i$}&x^>6(1pE%}ot*eb=`X|AkyGU;Who!p|=rM<(Yno;r2 zVv#+Me{H||A)ovGrTae5*69ha=MR^zd@x0FQB3h?fXu6T|MIXgFwB|E+n`_XS$;W8`3K+aV`jcpTC+b&fu`#jCJTvu9b>GA`fmdlr~*83&C>-G5; zFE#(pTXW)5NYSp2lKYo;-~an=@BP|y@Bjb#!`<-wqc4YaVcfA+ff|eZO}rIrS;Y%I zBUV+MX`kq1#Z%9_zT4gHn3IH+-sv4mhdCB*eX>D_wTYddX%Ee2)Po|{tdS%SKWE^=_Yu2omw^QTW zy}X^zrcDZ-wldwg`S6#35aZyOE1Rx;IcqaFtlF)Re3GM;mdOEY-; zNso>zhrBsn-V7;>+qz?t!r6)O$Igg;-n?t8!ovNt;?JE?FzKvE4$wH$bP1vJ|{QubEWQVx$9i4ric5~l6lXczj{nimUD`L#mnx~3TvOl zI2QTqzB<(TF$klkM?DeAwrPu1`+|msYeRC-KO0DG~&#fB{XmFV& zZtmGGx~KUq*S1dg^*44deGt3nxMT1KyK@>p805V&*5|eL^o!K=_}|!N^kqieg1SY# zPZlJw&kHo@^A}YSNDe$d_5ChxuDD|}n&vL$e_B0NKJRf$)AD(*wxCd2 z-eMuMBX0jr8#+kMk+{bh*W34mr#YlWfK@t9rh8|$)V5FTb;|#{>p2vZwy=I{*OvcY z>lF8HS9^U(Q|{)wHSR5+?z}Jjr~2k^*}Jz+^4E9o{Kf41;q%|1KY~ksB>y;P=X9C* z$7B0NKN*>x%35x0S3lB7 zr=6XvHEvyK^;@I<{;Y(`^2b};>MI{b&g=MmMBz|H-=Enh3bp^Izf!l~bckDmAtzh- z+k~HSx47;vom;!*+vRr+?>S{>r^rk=C|%0&qubGI<^B`Shb>;H%z5Iq!<_q?{SEd> zWwl42@y+(<+<&t(mdWzS-oqA;8s<&?uMZ{EgP9nW2H?vkN7@6F7p zdQ0AommhD-Ji=Ez#a}Q@zx>F|X+NY|rZfMvX)L>J`|{zPM=X;H*65vBRi*IPY=4!) z@xnulJI{*UOqX9gwJJk8`RlFv=1BtY+aqkH#luuKJrlfkE6sh$m&tH5# zhuyal9B- z@4nHwd;00fsN!v<=p&D(1h%FuV_;x-!2lk4tdpIb@Q{6Sb(;`V6!+x*Hu?IRXZ3bx z_FVt{k!6FMj1rHa;G)etZ_e31HR+I!v9EIJ#`Pximz3sA-@3>9P|4!r)R?8GnYV`r zx6BZDc5K?BEt>*#ib6Z*KR?>V;I!xRtlVWwir;W}wu^YZ3X;(`eXgtc*WD}V{L6>d zwfaBA5*`>IxbXW%{*(L_*(YB>?gJ8nFAUnGQ~NoPnStT;WV?2sdYv3@k(RFVBV8A` z_jWe8ZVB1xu`ppO%m3WlTlJ>IZo1pG{z35%rWqLlo<0A4YDDHAlz9F|Ok>*xCyzhH z&*sduydP7R_U+G~&tIh*I4&t!3FIwSRazvRC>VIBG(qG$OAn{S^GUyzSdOsxaLo{U zctBZD=@HX1Ruze;p6gy0g_G(fJhH0nW?WwyD+PdAE z+_g#~m}j%|*Q@`p8r9s8b#-gx3X zdCBw2N2@-(IGwr7&N5UmYSkI*m$##>Y#cUCx*IWN+Zq4FYu9<0CCtt(6?^3_WA^&! zH?t$t4dRt}=DEEy?8scZB>kymtN6s-Ug<6A^=CTsVhRqm>M?HiJChi9AXr^&LduKv z(-qn}clGTFFb~O%UK=P{d%Sbbj;7UjHi}Fwj%DUPeqeXMFpHFq@#>xx2eta|tWDjw z#-L~3%F9xnCpSslpH}iS!{<1s((-)SR}H^HOOga5yh750%(TV3=Y13i&D_#>Ok&%t zttlF<3SaBR-fvds$$GUX$ABm7TyIEP>^Z65<=T-<^Dcg|61ufJO8B|Vt&K%rOm6Mr z=Jnn0cCl`5;)gjg57k#rXMgzLYwmxO6)%>{*Q?tK&NzLPUFz+ugvXzIpOx~@efHvx z%axa3Yn#r#{``K?OXj(`FP3g?K7B)H)=e3i9J#zlJ3ZZg?dYgK-LP}8?3A-k zwf$i?I*;v@PyEfZ`#<-r+#h|@mLA|QdG8qUdE%0*r^_yG+st0r`}*y{jn6&{pO(BK zzU}=CzT)s*mI~1>;?Yj}-Uknd`IPUOwvf5}(T+~WqUQH`7tgslwm&$Sdq`3xPy0rG z1z(&DbW134g=^pKNMibjgIr&O%B{s7B1>A6s+Mm z=^~sW7&jwko7JkjYhQLfa{sXVhm+7$7h(Gb`BN2n;qG_cxQ>~;w0(Z3xc>Q^>hrmf zySHqnnXH&`Wx}x#ea~H8nY^B7vJ4EDFItf_PcgXgb*bJe)#wPG#j4j=&ou21mpxs- z#$wygDb>8IcNM+Zd}P9|WbWJhPaD`tzPAfa^H{edwCVYh#N6%sax2gO*ycR#;H2n> zelx4LU2#snbbq5X&&_K6+SApaj%|-syc(*glYjJKZ=36?n{t*y#vX^HyVosW^SSh2 z-R-FFJD;2P@;Fak8vaMuTvjjZ*{=6D7i}}ydUQhlgE(Kc>xL&UJn!OgI%?Y1xa>}k z*JQh^8?LtAQ4OmRl+D@sKW|3;G12UGKZ1Rqt>>Ax`>L3{zLe+DQZ|D%a*t;`K6!M3 z=#;&dKedc{WYamDx4nB;CHi`yZgldF!|7pSGhNvtf9{&-s&697&C|W{3-8CM9q(PH zUzWDa@;bI-<)ivAvF;sb4T=}ZrOdE9`OWyu{5{q$*p9!~I_z@1Q?4|w)xy4w|8CV^ zdlR26qW?|r_U$NXuH5=7;r#cCnby0n3CcGbaeX=JBSLswpnW77N(*1uogxi^K`x%1y{Iks(r^6i4lvXyg~m^_mt>ur}Cia3d9Oo{V) zl-xbFX-|v363^130Vj&o5_%rgoT%{8*03tNKk<&qm-8Mcc&hETGHNq!xKNVISgaV} zCGHXAv9IH_VwL5Z$jKp(wS#^shE6ulVb4r+54swavext5=|k?$_i8^){208ekYU^X zX%F304u^D4J~TDq_7an}j|vWpS06mZX{G6~yf`Q^p<&OtOBH&W^$l!#7b6x3{xtc^ z%zMV+H!o^}US7Rcjh%&oVF@<_gAF`E|Lv8ne;ah$O~h84+a+b9g!ttP)2=L3Yp^%4 zP&p_uiRo;3p~2e8Th#teNx$~Pzcxy_GohfEVZK+y^ohrHC7W+d2$&#vEM3TMdO*sHayg0K8#;$8?rmEA za@E?ftg5Khk}pkH$AzEux@Yj!_iEmYvc5gjc`g^|8OO~3R9=7guxa?MKSh_zC6Ab{ zUSvGyQCn}?-Zi(kUoGm@dAMik%B{Os<$fqUtx>dtXJY8zeW~@Yuk-AFC^GwLm=D|2 zWtp$OMfv8MloUmOV3m9=)lnvOh5Hv0C+3M9#7;)oaILgC}42#+bYe zShIHJALp;trm?|ivv$3>(H42OG-}!3h2=-oco?s)D|%)1=;F=Db@mgVlasg#K%ZCyTCbF%{wuf9BDCp2wbrb-CfH1eW(+KbjOvb&7sI(ifewLG|Ihru838 zov-vqu-<rFTo#* zHYc~}B+siS^j~QjT3KG4F(;AZ?doj-bt|&_SbQB>te>my=v}^n~FL-?Cl$)+n z|MBc97yX7kQ?&a-qwP6fZ0J1malP$bv-+KKnlk4*6ZbB^bmjHZNuj=%rF(B2(urO7 z+4j!!O#Sf7hFO`bxb`^77z9+Ve#LiqXW5MUc|mb&bIso>pD1Dx-m9>n`&&cTf5x)< z7spOTYuLV>x;xy@dA;(&U4EC=takC<#(l2Z-FR#GVddCspK9v&J4$~0nfT+smZSeNSM{4%=1RQj&jgJdXFab95F zLi?XGlN#_=wSw`j<3-WD1X#397~{>-_3mB#sde*gU4-p^q6QGr{yeDjQp-dx|mY|2}- zK%6nbS!fVR{%p}j$?O1Gf&3i6$-I?6>-OkodX6njM&7M}cH-5R( zcFma4!up;{YCZGL{pSy8s9)!;`2Us9zRPv~>Tiq66@EDu8wKUfzLDV2F@M#zi&qYt z-@77t?H}ve2`^7AJl#C;+WxQ0+uRyU-o!iKo^@r9Z^+Gc=0UX|eX>fAb{0unopchL zu5)8WbVkFiGynZk6Zt-?Wt8>*|NeYlazBgVnfN6giKV}`NIZMAx_;B^t?lcUx2!wA zq2S=wi_=w#+tMOty7gPxu8{n7R zs7|Bgu(!GkB*L^FXjQU(O?W7kzfSmk(v^#vs?X;K{FN^J+g>tFVfN|}d&SVj?^#}c zjCXmmsHpM+OWskH{u5FkS#BH^)^Kas92XpMjBBoXf%TE~kNh&O7pT6uzo0OD#VMt{ zNv?Iz)KSx3KdZIA1Um!6FF^(dTWH!-uD=`cvRpV+yw@%qEXHvc%~`l{Za zQHd4ucfRG61=YVy(wF8|LTdRo#ee_P(G+b5#`z>`yd(+h8*xM?4{ z8glroc4dCCnwF=cvd3%6*2x-QZstnNx;ix^H+nN`lyd#DsTsZzSvD)T9-CB^J>Ak^ zfz-#2ybSXd)7D0sPJXH{uJKKWV@^F=pnuyA?_}X4GD_<@f2cSLX>O9edQs(#Qs(*A zI5mzfPrjE5+3&Vmq840pYSW3dQjc6;%c@PLi*ED1o%-b!r*mnLnC7~f+xA}i?YGKp z(N+6$_SMC|N_Q`NTYpCVyG_Eosk;_h%QD$td!9Z&RpgWMeEAnQ8*g4v7kFXxxaC^p z86jWZoJ(tFU-k7|G{ybQj9G7jb?5G{O=`F(v?3;X#^JW-SEppGJMrEjFYu6AiqzaN zCDR3xeFv_7z4t3CTZ<&-iNcNlJ4>Mr}m-+X%V!YIFx+pi{Q*E8jQ-Mr1x ze4*v)(CSAjtzUV!?`&5-d2q=w4bh#NIspr=bLh;Nvixpe+RDC@GsCj1{?6KZP2aon z0&nRrW9^@tj1Hcc;9T!{LpQOXf#u&HdzIX}cT4k<#B*{VCu;J)wb6N;Xvr`B@vQ-~ zsmQiC}f*Qy)VT$^G{W9=bw(~?&xvuI90(O$oZZtW{&tLxx3pmSMNEqQ2F0G_!**?tg^saKsi{Az@|b&$z>X*OahsUl8n1b$ z>GZki!mRXCUk;PA%Z{T|iTJl)UpcXmr&fmFBV9cHcA7urQz zmhnz}nd*91%l-Ju6IZWAR0bIf`R&hMJ$u%PE6cejUahE^RdS2Rbb8S%%eg0)SkB3` zzOq>LZrst(nqyl&ovYW}kjR#h^8L+BrifL?l4j*z*NMI7R$g?yCpYz19iPf_c`a?{ z7p5KymVSP6PUgV#_py<8|CiKGi*wsnr+<4%z?Yx=S3dn}d!wFJsuuS0cWTg?rYf~| z?d2T)RT3V5SDob-G0NO=x#?Hin=J_!9)Ii%@9;@mzxm9S2Uc@0=iC!{TfbL|`^-!y z1wn6VgLb2-Vb#kvEdBVZ*~z~1(3i=pC7#}Skr8@s@42}v@9s1%wJBeg=dpg$>5SNh z)2C1EXx%l5^-f^sbFE*uTAda#_&z))DAICNg6pulK!knUB0-V%*=`E0v)u)F!dcw{ zgw`o#y_m6jsNI)dy0+HvlSE11KD&libotSdF@*?7U$)l^yGUYiQv#P9DPITcFCKH}JQ z^!K}ZPA%KlGlg9?O5J^O`|B3I1qmmUqSiYe`Cg`c@r7ka)FyEm*Q0VF8=n@2aJ@M= zM>t}~yhOX-FGAFx83{ZReq_bvTJuV3nyu@;hp%Jf779$9XS{D~*{qqGFQR`N2+vMh zHhCeZt7H7c2gjS$^@Cb;AODk1-pyV*Ip%A_np2!9ob~nc?pxDK1CIz>x8I9cY;ip{ zheyWCd4q-Q6xE&0Mtf4_ytx8atbdb>sE&qv;;j^}Hvy8lS;qioyJ?>98-7L@<)zoB1u%=07n zKJopJ)IZMd4rgDuy?*kh4{TkzHg^;K?1A^|d6+ce);3-5YRMJ7IFRVw;$_?yxEuC@i=T&px6eLSQ0u~_r7 zoa$-Hk7guGR6RVczq7#BMJXjgQu&`*2i8ik$kqQFK3F>r0cnxx1>fd4PAco z$)dQeEs{Tc=QZdAPZ9NwxM$ne8e`w^$I3b9>dIid=2Hc^%Xem;3a`1mZ1TfZn~%ON z)ze+t-fsAQt?SD^o9!{zg?bq(b##8myNObY#S<#0*lagEaL+kiDE(!QiNSHpNe{faPQS3~-zcz4 z#A&Njq5Q^t-Fa+Vuk6m1SzCYfVgaLgEnlwZiAuMRn#@bM?FH^0cPOlqzx6$NhrgYk zw8XZ8mjcUG<}Tql8Ezog^uCQ#O>{<4k9>Pw-f6>|O={7WX@$Bjx<9Hq7Rki_&!4~U z&P{QZ8{zWlENzT>%(D)qa8!CsySN~cJ)!#eq|9xhH|}kCUH5ou33G6rtL1%jV}Da- z;f{+1S_Vn4)WZ&PT+v_Cw0epE1>u=T>`_~Td)IFKxPgg*;S?LJHMrmr?_`tt67{+M zmjguV-i2LTtDUEGM!e>rVM@+{1g{C=@eLh{ekL;`o9@5cW~CkNoo9V<{v-Vl-SQ@a zrjvd!{|P)+?0srzMZ5GE&UhGf|e=KFYNlI

?13_hycR&h3O>yFTR{h8AaPSCr#C@_N~E?=rO>avc_(?f=@ zvg-}Jc?7>NeVLM0wZOXIo}1#u)5}tKl}pN{H9tJ~Nm!IE_3XOfjhvD#%T9R^F^vx`RRIlnsDmwoHnDLwIhQ8%CJJ^jji+UQ8sWa~c19jynnjQ7rb z5j$D;-?sX!3F>#4c@76``_i@lS*zN1sn$)}KC3sHe4L|r#?@Ku&eSE-Zd_ZID=T!Q zUv&4aZoM6k9;bf0ylC6s8Sg99pY%3{ZM(fFZO!aYM}lHmE(e9UGkMCU8?Ik0pI&n3 z*oH1v+3tv-jcXqBtvFlUcy!I40^W^zT*q~{udbVwxFI}Z)!q8!8CH_d4^9l^|LPZB zbSHg=eQLC%+W)5&p=%5p5^XAO8E?L4;_mx=!*ylH$NqaCfBn^LzV3nOy&UQKnd`mG zL#JDPopU{_?QzPpv=@5)b03tQ+Ijb%{`MbB(l=jRT2{5L#K2E-VgE9}`IiOQo^~*w zTq0A|)w1w{3~xaC`HA65F7-2VjHcgbKD}{0$5XZM0{@=8XMMZW#@ji0vBw6UHjQbE zWZo)P3w{U-Qg)d$-QbO}{v`dti824Ur|`Si2%gw@s_cVHUxm_+9_=aVJGuntr;FFh zt(x(>#~|?Q#MJu&mF-vTuIRoz$rCD9+keC^DSF@P+AsIQva%*M`YN7UW?jwP@k)PtHl4l7RZrZG3N(>7Fu4gGPXFH(9qC z=saj`GD#Ep((NvvmU>2Wg2DO)9jubwM$<%8j@osmN@_Fxb2+xE$5hhFx&HjF%-R3g zoNd;>GxAVPpKr_);xjwnT)O&BZStGQC6cQwOb_2OjR}6^y!6R_W81bf=N9H$m7UC# zky`iATF-e^&h0z8k!{Zlopi!vwy(Pyn|%LK)LA3bLuNeH@hz3PJLJlXr(0^6@4R*^ za6$M_Z4M@XTd9T9IxlCQbZtAC(av4}gK6&8M6UGOIV>|z zZI>+n##eFny0vLm;edC1-2q zJgm1od+%wPL5^FSj-;IaZMp5Xm(BYt(%*D)xNtqzFuc>fYSw{N$*%vlf9qv+UdSBw z*naJzf_p#f)^+FpDsaReKe*?X8C&SP*WvS26A~qI`|~5G1UrZ?|G0e9bM3ot?y~!Z zTdRM*#LAT)zT8bWdEULGza`CVFJv_o)!h2ZoVQ%A&sci8^~e{^Bzez{#2NE!olfpc zYYQT!`LY$)mKduX-M8I9Z?1#o zzK(1C7J~K14SqLje%mZss+qvInCqoj-gcwNW3rQ4o-^M$%JS3i;=y+lRZ_QU?Ealt zrk$b~w`6(xxr>SB-v5P{^sTo@vf`K~xIe~YlUKIR8vfUD^EWaSOw45B|JdDdZK28LzK3=9^~l+HWZ zbE!~$P^`DKqloS1$jvX+j;UPr*q?JnWO2vpN8L*}%mSh~qC7q>%%7Zc!|%qKQ*W01 z5dULYtM%oe{DXd>_c=_CN=M$<%&{&%Z#%vE-5vWs`XHRo@e zLoUrROp)3h&XcG8j=OE@wvb0jCU3a@PA*qI6>_Vv-@QIO#=CmHO6=!oHJ+!Zvz3#- zHotax(f6>ePIRBPYKitEPo<8cOMRshEwjEW3w}|O-16w*gw^}r8n0V@zQaVaYvZDT z+1!Q6=Sp8Bb}Rm0ay~J+eBYPgK>M&Irczv~68lVUG5>347Yt9lU>LP(!_Ey!h9b|T z{g zA79Nd5c6NWy<+;bz5YMtSJ-MyU-((D^7?VE#Lj}b0!!~Gqn2HEbneFAv??anbzE!=(k zjh>tQQS}e{DomYfb`9^B6u!ILlrWpYzUb)8762_4%)QgQZUSBI#hM&P-m( zDJ_(kb`H$J{9 zXH@c|_ryorATinVopQ!LVo{HyY>)D`r5s&GFMa*HYun#E;Jsgz8+da2j@<{D z-Ea7&8{H~%VypEP>q$IO^RTikps-TnR!R1{AC70&u{$IN+^V)UX}8<%>&khx6-T8f^>wlHygbprJ~V(qA}(&l z*Uy^Mo>olp-|RG{bw=`uc$NNz-O&-X3dER&9umks@ z9*>KKtdX*oU${1|Sj--o6sL7@MTrg5-kyX17fvsi-JZp6H7~*QI7gdgM7`(nQl8Zn zrvi3~l(xOG|Fd1~E6Ajzi^sTh3m%pSJVp_b(qR7bjMS zF1oF^;ONyiGnZLa$qDvc@}IF#K4M|#B@55fotl?tPTCh&Ra~2rJ89~I&BraA4$ZJ~ zxHQ9#;r8^Ee~olK-%tLhxNN~>)d`87JoOXmP5cfktYZukPMvYZMX|NymfL0@jogHb zKiX3CN;~@WCH^s%e&)zbESog{Vj;&{?Y2JsUFTxn1lBnfy%LDczNMzXXiNQ!1gZpPcyD3oXVcWE#)O8COPT#w(NFk9xuK9rx%3P z@2TxhT#>f>+U08(=RLI-ujZ?4%Z_ul*nMdG(z}JL9yZDvq?GkJ-!6W=Fn{;iuJRI{ z8o?^N=D^a})9WpiICKuJy=t>R)2w#m`-rr|8+{MSahAu6Rjd6u@M-z_^C4*$q$aw$ zrWbE@E>!Yy-{EWQHf^`6M?aS=(OLI~sqv{&t!6p=mNlf6eFE>U7(% z{#^dv-G6z#mR{dG?f!;sxi@2%t-iB|$0$J|H9@l9bd5pIwZ+7(Zfj+JM*G=g7^OCyd`|RX!b+LFGU$Q-+k{o z$Yg6f_ghkf+$t_TcJFHnk!qe%k}6!{58it`lvre}IXA{}R*5p(12#8>>D|XJbN=IL z{c|AfqfFN?wpqW#R&6r;zIyATH2;PDtI|C_lzsDAwcKOHTmFFf`VHJFT`hjwG&_Yv z<(BKSS1>i(bn09;IQ)CUV=J#325%ct!Kl9OG7itTVtMW=+Y8!F{GLoRXxlx-xI6QX zvac$y$XpY%o8b~Vc3;1UZ8g4^nLhOc*U6BDKR9p6{5^N^`oGgYL58hcwy0ZsUi0{L z&f(@)=Cel{y#I0fJY>A9eZ)NUk$jTcq|G}#i+cY2)kv7Jg>#a}_ds*jGl_4kQOoC@ z>?#}BnHU&$voJ6ifoojQ$|k!ff|G65^47C%Us)V@Cm1X`cM|Iqz$p&$)fSzV07W0mF4SF>AA; z8z&cMJ?5MjwIVu0ph&;=T?>_To^Xc!ExmFh-&FUF=*Ip@ ztzwD!Gr#TFUC(UwYJPR|jDih+o^amop1nIv=PuiK1F??}eBvLRQexSBs6L$U*T#ew zf**wPHa^|-q*r10Z{}n5=3zWH{+!KJx764W=ffPaj!DhfQIkh(kwsA zKD#b$kj;6Gg~@K6y@L{u|NxI&upqEwS}`w7qclQ#GTSpu=66#csUik$D?iCjaLS@Rnp|L7XAh z!;m@cArk{b9yj%5V^?!-$RGURBI;~KV+f#D>%a`iQ zpLcDp{Qvu{HACf{FoDB6n)rN5E@-KrSz-|UNMU_~lyP88?<1+^m~T6lyBi)CsINbA zchkFdoea&t4s0tezxn9trns~j5rr|z={xphyxiH8`fS?Vpw8PzMK51ly z-E7W9PbKRQ7K?4~y)*0itZk0&9}g)`OZ=g+`F!x2$Lby_2elYX1I+VWg;}9DM+W^U zeLJtCV?(~(`Y2o83dwWH1`f}dmaKWJ{OK9Tk80V7b&dKHj6y%iRK8UCz%M^%mD-g! zmB)+zE2$l`UJ$uNrqI>twrc&>GQnH!Q|8p1SivFoO}Oye>UB$8rcSlG)P0)qI-91) zFQsL@smJ*bl=X#tJ$U?lNO4x^(E`;AmTeauo=aTXcP?q_M{DK8GwG)nP5xux`e;V0 zl-U0nn=O1pBXSv6v6Dm>dDZY5OGBDrw3cxObcVdM}6M0SqrZ% zWzEjcG`*Vj+KplH4Xt(OukE|O@A}iw+I>g2Z+Tx@S-Un!;eGjgbK{wwY{I|Y-|a1a zZ~1&)@jJ`?)$gWnKfk9y=73J6ZoRm5ftTs>(Bfl9QeT*|sM)+QbyYcjgs)KYk=c>S z>T!lXGaeaF)ZW=PL#@p_ZeE0uj(^)}j;lQ;DN{P5Rqv}W_U)Nw*d{VVLOr?G$nUS* zda3=3ERMS@pYwV$XI9#xEVY$0PugiN(JPwgzf8jDs*7RO)pM?GBC|Cd*ZZGK*S}mJ z61>R5D>Qf+%M|UMqN`Rena6kki_OYOlB*=sPWT94H99?k+vm*Gn{8(dm)ts1v-5&W z@0n1S&pay)H%3$@?(2-&8l=n36Pb~;Q)q`r+K-ftpH2yF4SMbD@^({*>1m%xz0$0b ziHhRS6Su}Znk?G3Cgia9)oH71g4Tb@`*1SrYju6EVz#e|=E3PF4f>W$bYE~LYm$)j zwVzLlQmFpvMkFIo`JD>8@p4*%vidsAQceJNP8EamHRHnazhcCfHQ; z-ktAZaOt7n^ZIPjp8Ym^jAd@hmWf?wS!8H^OM?GMuJf%OkC&!La&x(*&b+6nv4a0t z(w$q8YkRl7QoR+l+cwXA?#&sB)~v~2&bS`T(7AVGV{g@4u9j$xgq3@3g|_}aD=p+@ zxuC3EAuIjOZtn@x4F#XIy}T#X6Sp_*Zr4@bXz8riueYsR8M}R5{ku(UjrCXi4wyEs z>Z>pa5#1X7);2VosW3})p1y=&;gr~0Gp86T_3pB};5X~ev4m_3f%hGk4(&Q~mG#{D z0EIhIPdR4n*AmKIo7Kw}M{@eLYuWjxuWM33GZ<}>W`_100 zck}UnturD>eOy=8NF#8b}cNN@>!3^MvKK{0&whJ~FUPbW8q$!)X$ z+mUtq_DoK{Z-VJ-JlLM~b-F~q$uPP(Cvs_g^_6?;&Z}4&8~N@JJvbxi=GM#aRQALO zbCebY_siDzxnF&6wOs$iky}c(Yj-Hg7K*NjG)-CdDedM`M!Vo6t|v1u@thBsb*j>- zguD9sx&v|tul!qgM(UaCUmh#&n}2fBQg&NxDmpLu=g`SR=^Xk0xOo&OoikB6SJck9 zQ&}kGgRX|>~sR znBU$QadD2MG0Rca=EW|W>wnF$HU4GsT zPIG#{ky*tzyh!KGaXaqvhxK{f@d1mgKdL5$-4~nAl9YSr*aSZBbrbK3?Q2@k$;ICM zl+kF0Ymb}vHxG65iP@pWa~D)yxUHGJaK(=G=1j6Y zyVEys`EG4(-Jf&rD6Wtxx%|Z_>}{#~!yTK7E>Gp&J|((n`klO!cRy8nzniEZQNPLm zo3Ou^*l{mm5$@&FBR{$B3>U0DIqCP4x};@s;it1i&>51z4s}x>sYRk`8eUt_9v@9ZBUJ${9E^@)r#ZF zpLiebQEi{H7ZxMic8xv%SD%=4{AnjoaMt3B4$GZ#oRpatFS>AO|D*dlKl_Rv zO#U=Q_5M_Ko}cqt<4;_kW^=jUmi5szo7GC^Vr8`X(ply)cTBTU-yZd8kIXZ*qrax? zlJwYk$mwW8{Yk;8*~y!o=PSC4{xuZi&fF^GxYkr4$@kXA?()=CacR6yX2e;nwJ=+2 zAfe6EvZ!pq(#;!M%L{Jg&0M#o!g1%$A#-4(5gL`2XYm07`aF;*ubB^2eWXGPI6W>GK-iYQ%Ejm(v$iw1FdV~{4D*uxpU3_1~Xr?tZ}YOIH~P5kyCZHc>MmIe|Oyy zczSPxrs=9XyOyrGGAaBi%Ur7rosDhrMj96vy#H9)++}h5a*f8vd4C`3&G>qAzO{4X zqs=zIp7ZefvDYw5WZ8ZHFI2Cv;)hQDtc4G1pM|%4+I%_PbMK$Veye>AMz7q(PTtJA z%45V^c-WZxl*+O%jbh%~`3le0h^9}`?vz?nk}&b@)u*PG$EQ!3w^rx#{G}QpU;piR z^S)r+8yTm)MnAaoK8U~a*&F@OK{w((OR$~%?8LZR%(pYRk4U|-E&RK%rFFXXn)>=4 zP0h1mhx_h`zPPh&-ua6apZ10YOj@dUXN8?W%w0i_qrU`I{F_*`*(_eHH^2Yj?d?0u z&Ka6t+o(IO<7(3+(a7wZiCS|m``nmuv}OOZ+Sy;7PkuO(cIxD>=94{&HamXTmK!uZ z6szv9s@$Dn_>6*UVUZfZH=;(Ree>=R?eN$k*V{S@-3E# zx0zHWGCd`cZO%)wTvZ;Yn=n$PM$yS>nr7^uFaXv>ZM9bzZ=~?UAvqemlr0@ zRm-)>z}BZ;YC=_G|0$37=abt$T`#h}Cc~??f7#a6%m3feQRBbJd2epna~G;_NdFAm<{Y_Ga} z^PhT#=ZWlk%nuG)u6p%U!`*h8;*ULY_Yd3eoBg$7|10;t@P6xma&A&~%WmE~9`F6| zQOD_2_Xm2f8<)T2*wa4ob5H%VJ@eld1ThppI2O}$qVOT(zfCf7HXZt#@1NfOoiRwe zlKbZK4d->W?YS09?^_<+v}e{zKW>TF0;()4E;`yA`MSR7P1=8h|34Nyzb5kPm*v?r zizUkWi)L3Pm`%0qpObt-Sf;U*8WEFI}x(#NEBJd&%nA5$~NoCRAxE z1+W3aPy-~Sw*dR^ITbPZ;eg+F4y(Ix*_>rdAd`2^{IJ!xMSxwajgR(L~C_@Y*8#^j(k6Sy}9 zO9@W$y`gF?FtKdQY2F=C@7zME+c=iGQs2(>8Ca{iCv< z-0vnB@6c9nf4MSgzx2;5r@Plb7Tm_4V6?B%S;n?Yu_qmbpM-7t)L(c% z3pL`mwCZ?o@cr27{0}PglIo}VP38X>Thl-DM~Tr#)2qfZwx?&ZN>s8vWt(UGVNc`X zRgVzpB48HPKMQmO7ioI0E2S)Mg0pbi^Mu2>a%l&Ciyk*{zYy^9 zfZ(xEwF@hv5<^_g_1?VtyJC(0s^uT{IPCxNVzQ^p0m(P3E4#8KRi!IlNlUVN-9Kyd z(X&V8d5rI~L*6a{;tzMR9QS;FOhe>z3;)IXLtB?r%#7Z}d0zPI%H3O9RDR{9*=c7H*YBCuZN_?Bq*+Z`*TSd!Faf zS6h1=1k{TRjy(s)rlyt5K~pVeo2Woh@lPm9?2 zq^fpoUs`x=f~QseJO!@ppN{=7{MT2Utr>WJg zpB||l2HtXq&UgOFi~1&1xA1dd>h+v&ee?GFy!_dJ#3OxueBrr?g-WWAZL4BaAI_Dy z=iNG2r{?|vb}PaEoiEvyYGuzfaSo3@Gme#i`ghv%OyG;$RqHR;cOH7rQ(eWXU47xmg6Hg4>=6|&*nACCWi{=Y5#?v$+&{Kx!%WnsSRzi#!l z0eSVBb-nj9x~Cb~eOr3JY}UW}lD&-Aq~2YYNPV!qh^wuP{qFbO{wpRH*Z-Yo?k=7m z{ruUE>C0Et6z$ow@6ivX@U6QK*nSi!3m4guezoFD=|j&c8UN&Ra!>8onz&}(vBexR z2hGIlxF*b+{95<#_4%!9|7_bUy_Q|rB=>J-Uh!wKU90QaullZ1vTsVLZDl+4#XB=7 zm8<<_ zzUa{LBdh#pyi^bVepO=2%ipJ*{qL@Mzgng*|HAjF-OCHs?puH7iR`lC3unz80$=U3 znzw6xpZdGiwKla=_n)l4ebRz?{=P|m3%e9;f2u62<2j!x^5RFjfWPd^#k1;tuCRr^ zxyrbDae?j4_j8TZ*J^!u@c+uWlz+my(kJFz{y%Z@+@FuvSf3UsTb6I&eAGZU$o5CnXG4>QZDA4?Hj!| z>V3KI+Uu(-I%i#B@%s49x4!Os^!~5&1L}XW&M!_YyOG+?w*SnY=VyM~J+Gbry{PPe z<@>k$87w;NT`xAViq7v*YG}<;DGWWDB$8O4{&7x)&H6{dfg#q``d1!Y-VxR;{&7;p zo;8n*wd|x_WyKcV=nT*LU>Otq@uyS`<9fFbuA=c>m)@KXGfY=B>xJw>;gR{XsTH`1E_OhW9If)UjM&{Ng~i=?}&@aVvX~e)-PhueIvdBrG@0 zpB-jaU!PNW>D&~V)yK; ze9vv1G(zUAR7lvSouTv5PcALmvhMOT)%ku4xE|eJI=e7p-PwO<&FXF`R$n{w`$gD; z;P9OXf{kim=T zYjPdCTikM1-{9~4n73ahGn{K$E>C*!;%Sh!6O$)6Qk1TE3Xm&Y5=eHx!}{a`+n$?N{XSZJ5y zB~M%X(|y-3bTf;}S6F9M*z;vs^fYtH-S}ZO=k&|&rUYL31MHUSCVLv^7e{3LV69u3 z$hkjAVE6p{XKs9pxcDLakK57wn*y_Uh8H>?e*dAGwf)XaOM%xX)RUiXpSn4`ZfWOU zqXWj`_4=D9nA)^1H~qtCUTL3eXkD>TC0Q!(p>JQG9&ftg%0!lBZT640by-Wv9dqcMO@pItoc}IvA?W<7qe@U1X#>|`3AAg6DukCCHb>8GTQE2#`#WF8ULki z#*$oqFO%i#Pi^}!y}pctchTd83;I_x+&gY6eK%VE(XS87Kn(jPseSzm=6_;X;G@Vf z)q1^J*aDSn0yE+qKkzw;92Qyq&f%_rvdC&pxAzN{rHjsL`uIevOk+piWsxk=KfKoJ z*8<$<{%Q<(ZzL7=v7xE4Ap6GEZca}vGrkbjJmo7tDauS-Zc|o6S<= ze@I5nw!*7N>{-rEiTd%oR@}KxVDXJ!&o_;|dn+XQABrCNVO%fYcj=J|^QORVcf%H~ z7zc5=!|gxZQzmsBws6}M_^AIuVcS2Bc~jz)uu6>8$DcQei!xy%`mmp$mHkrx4m^f z$?KBb!l&*AXFV3h%s+1IbHz=o<(m855EI1;eqJrRWfOkv?pV3wgZ!3Vck1VO&3UHx zefbXMO)>LdM7rg83HT>{V=XwGY@sFEvb?|EbN*~u=JWfj#Lfyl6p5+fztLg;MkCSx zK6@FPrh4z5ZstjI@|xc2XKvn>G~3iqUSlF4=mmENZdMedLi$@-2o@Rz3Ww)|J3~6LOo@D zL352YF7@S?|9)e*yH?u&pX}~y7Yy%SkesyizVfPS*4TRAu0vd2*QHa=XntGg_*3Za zys3G|Wey05%O13`R}xQ;|<7ktsJxT(@qelE`PlZa-o$NcO-bxxsemQU_(zF%GjP?5- zseW}0uL_^YQLsDgimA9Qqv5jurKeBN2+lcQC}i(n9`_)$xOe*L?s?VK7VG7w9u<3f zLqjZj|MQ~#C0mwkS)?Pdwnam?^1tKI`kHyUFyTu?Yi1fHyk_ zOZ)yLn0*1>j7%a7BH;52g*Kq@A4UFDJjDcT2> zOD{@H$w@_4!Y>SxhvS!%7bc78KrMkgQ^~?t+l-ZgL7$6(K^LwT#E@Z}{PC)ZI>_wo+)NB2lh-Rs^1x&n7_Ldc?aok!yX9+1}zjzW++c?)X`yw2LEL4n~E$93^(<_HoM*wK{mwtwz^F{ zI|GBc00V;(iXn&f!Rj4uu}_|JlNVXf=hUw`dLj%ADcTGS3MhJ-%%OUOK%vzbE;%{( z76%Ih!#i)Vc;78SWOESLyfH9XpqMku53JrMhIjIdTPU%Ga+4T}o<#vrJ;E3v3%@so zlYzkiMbqDKu%_+FvKX2WHw~aihjuJjliwZo$>%aKZ9_Tt9mO{G1gJ(SFi zhMLUD{dcrLK^a&os=<#e#c(?ll1-smF*zp_o*n(~g5sMiYx09q0UYg$n?&4X&< znSB2-iUU#B5TfWgv=FSv?ui((hfr3Mp{SQ!0#;wYUJl(eC@XGI^n@>;{BVlWWUi;& z$acU-D})#r)KJtr?3(=Hhz7hY&wdKZmyL%ePk3q!%9BUI{G~@HD_*bxUoTpNNUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From 975a994581c08291e2a85764539175eacdac75b1 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 13 Feb 2021 12:48:59 +0000 Subject: [PATCH 451/711] Fix missing method usages Maybe one should do a full gradle build when doing major build c hanges :D:. --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 6d5f6b279..dfb988a53 100644 --- a/build.gradle +++ b/build.gradle @@ -482,8 +482,8 @@ tasks.register('jacocoTestInGameReport', JacocoReport.class).configure { it.dependsOn('testInGame') it.executionData(new File(buildDir, 'jacoco/testInGame.exec')) - it.setSourceDirectories(project.files(sourceSets.main.allJava.srcDirs)) - it.setClassDirectories(project.files(new File(buildDir, 'jacocoClassDump/testInGame'))) + it.sourceDirectories.from(sourceSets.main.allJava.srcDirs) + it.classDirectories.from(new File(buildDir, 'jacocoClassDump/testInGame')) it.reports { xml.enabled true From 1825f67eee86b74542adc374b83ed55ba1c5ab68 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 13 Feb 2021 13:02:24 +0000 Subject: [PATCH 452/711] Lazily load models in data generators Fixes #701 (well, hopefully). Our BlockModelProvider is created when running other mods' data generators (thought not run), which causes issues as none of the models are considered as "existing files". --- .../dan200/computercraft/data/BlockModelProvider.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/src/main/java/dan200/computercraft/data/BlockModelProvider.java index e0091c24e..788d5631f 100644 --- a/src/main/java/dan200/computercraft/data/BlockModelProvider.java +++ b/src/main/java/dan200/computercraft/data/BlockModelProvider.java @@ -21,14 +21,12 @@ import javax.annotation.Nonnull; public class BlockModelProvider extends BlockStateProvider { - private final ModelFile monitorBase; - private final ModelFile orientable; + private ModelFile monitorBase; + private ModelFile orientable; public BlockModelProvider( DataGenerator generator, ExistingFileHelper existingFileHelper ) { super( generator, ComputerCraft.MOD_ID, existingFileHelper ); - monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) ); - orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) ); } @Nonnull @@ -41,6 +39,9 @@ public class BlockModelProvider extends BlockStateProvider @Override protected void registerStatesAndModels() { + monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) ); + orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) ); + registerMonitors( Registry.ModBlocks.MONITOR_NORMAL.get() ); registerMonitors( Registry.ModBlocks.MONITOR_ADVANCED.get() ); From eb722a74cd77851bddc73147b413eb5129406d83 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 20 Feb 2021 20:19:22 +0000 Subject: [PATCH 453/711] Clarify the turtle.place docs a little Closes #714 --- .../dan200/computercraft/shared/turtle/apis/TurtleAPI.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index e1d35ce49..671c9a3b7 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -182,6 +182,10 @@ public class TurtleAPI implements ILuaAPI /** * Place a block or item into the world in front of the turtle. * + * "Placing" an item allows it to interact with blocks and entities in front of the turtle. For instance, buckets + * can pick up and place down fluids, and wheat can be used to breed cows. However, you cannot use {@link #place} to + * perform arbitrary block interactions, such as clicking buttons or flipping levers. + * * @param args Arguments to place. * @return The turtle command result. * @cc.tparam [opt] string text When placing a sign, set its contents to this text. @@ -202,6 +206,7 @@ public class TurtleAPI implements ILuaAPI * @cc.tparam [opt] string text When placing a sign, set its contents to this text. * @cc.treturn boolean Whether the block could be placed. * @cc.treturn string|nil The reason the block was not placed. + * @see #place For more information about placing items. */ @LuaFunction public final MethodResult placeUp( IArguments args ) @@ -217,6 +222,7 @@ public class TurtleAPI implements ILuaAPI * @cc.tparam [opt] string text When placing a sign, set its contents to this text. * @cc.treturn boolean Whether the block could be placed. * @cc.treturn string|nil The reason the block was not placed. + * @see #place For more information about placing items. */ @LuaFunction public final MethodResult placeDown( IArguments args ) From 8f3ea60c74ca6abebfdb79a4e35a9fb282651cd3 Mon Sep 17 00:00:00 2001 From: Weblate Date: Sun, 21 Feb 2021 13:42:57 +0000 Subject: [PATCH 454/711] Translations for Portuguese (Brazil) Co-authored-by: Matheus Medeiros Souza --- .../assets/computercraft/lang/pt_br.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/resources/assets/computercraft/lang/pt_br.json b/src/main/resources/assets/computercraft/lang/pt_br.json index 0f7df3362..f5ec8017a 100644 --- a/src/main/resources/assets/computercraft/lang/pt_br.json +++ b/src/main/resources/assets/computercraft/lang/pt_br.json @@ -38,5 +38,21 @@ "upgrade.computercraft.speaker.adjective": "(Alto-Falante)", "chat.computercraft.wired_modem.peripheral_connected": "Periférico \"%s\" conectado à rede", "chat.computercraft.wired_modem.peripheral_disconnected": "Periférico \"%s\" desconectado da rede", - "gui.computercraft.tooltip.copy": "Copiar para a área de transferência" + "gui.computercraft.tooltip.copy": "Copiar para a área de transferência", + "commands.computercraft.tp.synopsis": "Teleprota para um computador específico.", + "commands.computercraft.turn_on.done": "Ligou %s/%s computadores", + "commands.computercraft.turn_on.desc": "Liga os computadores em escuta. Você pode especificar o id de instância do computador (ex.: 123), id do computador (ex.: #123) ou o rótulo (ex.: \"@MeuComputador\").", + "commands.computercraft.turn_on.synopsis": "Liga computadores remotamente.", + "commands.computercraft.shutdown.done": "Desliga %s/%s computadores", + "commands.computercraft.shutdown.desc": "Desliga os computadores em escuta ou todos caso não tenha sido especificado. Você pode especificar o id de instância do computador (ex.: 123), id do computador (ex.: #123) ou o rótulo (ex.: \"@MeuComputador\").", + "commands.computercraft.shutdown.synopsis": "Desliga computadores remotamente.", + "commands.computercraft.dump.action": "Ver mais informação sobre este computador", + "commands.computercraft.dump.desc": "Mostra o status de todos os computadores ou uma informação específica sobre um computador. Você pode especificar o id de instância do computador (ex.: 123), id do computador (ex.: #123) ou o rótulo (ex.: \"@MeuComputador\").", + "commands.computercraft.dump.synopsis": "Mostra status de computadores.", + "commands.computercraft.help.no_command": "Comando '%s' não existe", + "commands.computercraft.help.no_children": "%s não tem sub-comandos", + "commands.computercraft.help.desc": "Mostra essa mensagem de ajuda", + "commands.computercraft.help.synopsis": "Providencia ajuda para um comando específico", + "commands.computercraft.desc": "O comando /computercraft providencia várias ferramentas de depuração e administração para controle e interação com computadores.", + "commands.computercraft.synopsis": "Vários comandos para controlar computadores." } From 1f70ed69854de12356681f4036458894a5848c0d Mon Sep 17 00:00:00 2001 From: Wojbie Date: Tue, 23 Feb 2021 21:50:19 +0100 Subject: [PATCH 455/711] Make edit display errors/results of execution and handle require. (#723) --- .../computercraft/lua/rom/programs/edit.lua | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua index 78c6f5ca9..f67bd0ede 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua @@ -47,6 +47,30 @@ else stringColour = colours.white end +local runHandler = [[multishell.setTitle(multishell.getCurrent(), %q) +local current = term.current() +local ok, err = load(%q, %q, nil, _ENV) +if ok then ok, err = pcall(ok, ...) end +term.redirect(current) +term.setTextColor(term.isColour() and colours.yellow or colours.white) +term.setBackgroundColor(colours.black) +term.setCursorBlink(false) +local _, y = term.getCursorPos() +local _, h = term.getSize() +if not ok then + printError(err) +end +if ok and y >= h then + term.scroll(1) +end +term.setCursorPos(1, h) +if ok then + write("Program finished. ") +end +write("Press any key to continue") +os.pullEvent('key') +]] + -- Menus local bMenu = false local nMenuItem = 1 @@ -89,7 +113,7 @@ local function load(_sPath) end end -local function save(_sPath) +local function save(_sPath, fWrite) -- Create intervening folder local sDir = _sPath:sub(1, _sPath:len() - fs.getName(_sPath):len()) if not fs.exists(sDir) then @@ -101,8 +125,8 @@ local function save(_sPath) local function innerSave() file, fileerr = fs.open(_sPath, "w") if file then - for _, sLine in ipairs(tLines) do - file.write(sLine .. "\n") + if file then + fWrite(file) end else error("Failed to open " .. _sPath) @@ -293,7 +317,11 @@ local tMenuFuncs = { if bReadOnly then sStatus = "Access denied" else - local ok, _, fileerr = save(sPath) + local ok, _, fileerr = save(sPath, function(file) + for _, sLine in ipairs(tLines) do + file.write(sLine .. "\n") + end + end) if ok then sStatus = "Saved to " .. sPath else @@ -390,8 +418,18 @@ local tMenuFuncs = { bRunning = false end, Run = function() - local sTempPath = "/.temp" - local ok = save(sTempPath) + local sTitle = fs.getName(sPath) + if sTitle:sub(-4) == ".lua" then + sTitle = sTitle:sub(1, -5) + end + local sTempPath = bReadOnly and ".temp." .. sTitle or fs.combine(fs.getDir(sPath), ".temp." .. sTitle) + if fs.exists(sTempPath) then + sStatus = "Error saving to " .. sTempPath + return + end + local ok = save(sTempPath, function(file) + file.write(runHandler:format(sTitle, table.concat(tLines, "\n"), "@" .. fs.getName(sPath))) + end) if ok then local nTask = shell.openTab(sTempPath) if nTask then From ed0afc4068f180bf73a94b756dfed725a9d77ca3 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 12 Mar 2021 08:59:31 +0000 Subject: [PATCH 456/711] Bump ForgeGradle version Fixes #686 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index dfb988a53..7230d002b 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { classpath 'com.google.code.gson:gson:2.8.1' - classpath 'net.minecraftforge.gradle:ForgeGradle:4.0.16' + classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.3' classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' } } From 0ee3d10fda6414bada437a9931807e0fa0ffa1f1 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 12 Mar 2021 09:14:52 +0000 Subject: [PATCH 457/711] Add User-Agent to Websockets I think, haven't actually tested this :D:. Closes #730. --- src/main/java/dan200/computercraft/core/apis/HTTPAPI.java | 8 +++++++- .../core/apis/http/request/HttpRequestHandler.java | 4 ---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 0494066ce..396232e92 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -14,6 +14,7 @@ import dan200.computercraft.core.apis.http.*; import dan200.computercraft.core.apis.http.request.HttpRequest; import dan200.computercraft.core.apis.http.websocket.Websocket; import io.netty.handler.codec.http.DefaultHttpHeaders; +import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; @@ -179,7 +180,7 @@ public class HTTPAPI implements ILuaAPI } @Nonnull - private static HttpHeaders getHeaders( @Nonnull Map headerTable ) throws LuaException + private HttpHeaders getHeaders( @Nonnull Map headerTable ) throws LuaException { HttpHeaders headers = new DefaultHttpHeaders(); for( Map.Entry entry : headerTable.entrySet() ) @@ -197,6 +198,11 @@ public class HTTPAPI implements ILuaAPI } } } + + if( !headers.contains( HttpHeaderNames.USER_AGENT ) ) + { + headers.set( HttpHeaderNames.USER_AGENT, apiEnvironment.getComputerEnvironment().getUserAgent() ); + } return headers; } } diff --git a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java index db83124e6..e4e6445b4 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java +++ b/src/main/java/dan200/computercraft/core/apis/http/request/HttpRequestHandler.java @@ -80,10 +80,6 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler Date: Fri, 12 Mar 2021 09:19:16 +0000 Subject: [PATCH 458/711] Bump version to 1.95.3 --- gradle.properties | 2 +- .../computercraft/lua/rom/help/changelog.txt | 9 +++++++++ .../data/computercraft/lua/rom/help/whatsnew.txt | 16 ++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/gradle.properties b/gradle.properties index 03dc1afd4..95f07ec8f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # Mod properties -mod_version=1.95.2 +mod_version=1.95.3 # Minecraft properties (update mods.toml when changing) mc_version=1.15.2 diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt index 28d5d109e..bd9ec247f 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/changelog.txt @@ -1,3 +1,12 @@ +# New features in CC: Tweaked 1.95.3 + +Several bug fixes: +* Correctly serialise sparse arrays into JSON (livegamer999) +* Fix hasAudio/playAudio failing on record discs. +* Fix rs.getBundledInput returning the output instead (SkyTheCodeMaster) +* Programs run via edit are now a little better behaved (Wojbie) +* Add User-Agent to a websocket's headers. + # New features in CC: Tweaked 1.95.2 * Add `isReadOnly` to `fs.attributes` (Lupus590) diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt index e4fbc7a53..e3425e255 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt @@ -1,14 +1,10 @@ -New features in CC: Tweaked 1.95.2 - -* Add `isReadOnly` to `fs.attributes` (Lupus590) -* Many more programs now support numpad enter (Wojbie) +New features in CC: Tweaked 1.95.3 Several bug fixes: -* Fix some commands failing to parse on dedicated servers. -* Fix all disk recipes appearing to produce a white disk in JEI/recipe book. -* Hopefully improve edit's behaviour with AltGr on some European keyboards. -* Prevent files being usable after their mount was removed. -* Fix the `id` program crashing on non-disk items (Wojbie). -* Preserve registration order of turtle/pocket upgrades when displaying in JEI. +* Correctly serialise sparse arrays into JSON (livegamer999) +* Fix hasAudio/playAudio failing on record discs. +* Fix rs.getBundledInput returning the output instead (SkyTheCodeMaster) +* Programs run via edit are now a little better behaved (Wojbie) +* Add User-Agent to a websocket's headers. Type "help changelog" to see the full version history. From 3a147c78a82eeffccac9413a9f2497f6fa438283 Mon Sep 17 00:00:00 2001 From: Ronan Hanley Date: Tue, 16 Mar 2021 21:19:54 +0000 Subject: [PATCH 459/711] Refactor and add tests for TextBuffer (#738) --- .../core/terminal/TextBuffer.java | 135 +--------------- .../core/terminal/TextBufferTest.java | 150 ++++++++++++++++++ 2 files changed, 157 insertions(+), 128 deletions(-) create mode 100644 src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java diff --git a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java index e855ff5d1..d042a2b34 100644 --- a/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java +++ b/src/main/java/dan200/computercraft/core/terminal/TextBuffer.java @@ -12,46 +12,12 @@ public class TextBuffer public TextBuffer( char c, int length ) { text = new char[length]; - for( int i = 0; i < length; i++ ) - { - text[i] = c; - } + this.fill( c ); } public TextBuffer( String text ) { - this( text, 1 ); - } - - public TextBuffer( String text, int repetitions ) - { - int textLength = text.length(); - this.text = new char[textLength * repetitions]; - for( int i = 0; i < repetitions; i++ ) - { - for( int j = 0; j < textLength; j++ ) - { - this.text[j + i * textLength] = text.charAt( j ); - } - } - } - - public TextBuffer( TextBuffer text ) - { - this( text, 1 ); - } - - public TextBuffer( TextBuffer text, int repetitions ) - { - int textLength = text.length(); - this.text = new char[textLength * repetitions]; - for( int i = 0; i < repetitions; i++ ) - { - for( int j = 0; j < textLength; j++ ) - { - this.text[j + i * textLength] = text.charAt( j ); - } - } + this.text = text.toCharArray(); } public int length() @@ -59,39 +25,16 @@ public class TextBuffer return text.length; } - public String read() - { - return read( 0, text.length ); - } - - public String read( int start ) - { - return read( start, text.length ); - } - - public String read( int start, int end ) - { - start = Math.max( start, 0 ); - end = Math.min( end, text.length ); - int textLength = Math.max( end - start, 0 ); - return new String( text, start, textLength ); - } - public void write( String text ) { - write( text, 0, text.length() ); + write( text, 0 ); } public void write( String text, int start ) - { - write( text, start, start + text.length() ); - } - - public void write( String text, int start, int end ) { int pos = start; start = Math.max( start, 0 ); - end = Math.min( end, pos + text.length() ); + int end = Math.min( start + text.length(), pos + text.length() ); end = Math.min( end, this.text.length ); for( int i = start; i < end; i++ ) { @@ -101,23 +44,10 @@ public class TextBuffer public void write( TextBuffer text ) { - write( text, 0, text.length() ); - } - - public void write( TextBuffer text, int start ) - { - write( text, start, start + text.length() ); - } - - public void write( TextBuffer text, int start, int end ) - { - int pos = start; - start = Math.max( start, 0 ); - end = Math.min( end, pos + text.length() ); - end = Math.min( end, this.text.length ); - for( int i = start; i < end; i++ ) + int end = Math.min( text.length(), this.text.length ); + for( int i = 0; i < end; i++ ) { - this.text[i] = text.charAt( i - pos ); + this.text[i] = text.charAt( i ); } } @@ -126,11 +56,6 @@ public class TextBuffer fill( c, 0, text.length ); } - public void fill( char c, int start ) - { - fill( c, start, text.length ); - } - public void fill( char c, int start, int end ) { start = Math.max( start, 0 ); @@ -141,52 +66,6 @@ public class TextBuffer } } - public void fill( String text ) - { - fill( text, 0, this.text.length ); - } - - public void fill( String text, int start ) - { - fill( text, start, this.text.length ); - } - - public void fill( String text, int start, int end ) - { - int pos = start; - start = Math.max( start, 0 ); - end = Math.min( end, this.text.length ); - - int textLength = text.length(); - for( int i = start; i < end; i++ ) - { - this.text[i] = text.charAt( (i - pos) % textLength ); - } - } - - public void fill( TextBuffer text ) - { - fill( text, 0, this.text.length ); - } - - public void fill( TextBuffer text, int start ) - { - fill( text, start, this.text.length ); - } - - public void fill( TextBuffer text, int start, int end ) - { - int pos = start; - start = Math.max( start, 0 ); - end = Math.min( end, this.text.length ); - - int textLength = text.length(); - for( int i = start; i < end; i++ ) - { - this.text[i] = text.charAt( (i - pos) % textLength ); - } - } - public char charAt( int i ) { return text[i]; diff --git a/src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java b/src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java new file mode 100644 index 000000000..286e62ad6 --- /dev/null +++ b/src/test/java/dan200/computercraft/core/terminal/TextBufferTest.java @@ -0,0 +1,150 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.terminal; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class TextBufferTest +{ + @Test + void testStringConstructor() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + assertEquals( "test", textBuffer.toString() ); + } + + @Test + void testCharRepetitionConstructor() + { + TextBuffer textBuffer = new TextBuffer( 'a', 5 ); + assertEquals( "aaaaa", textBuffer.toString() ); + } + + @Test + void testLength() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + assertEquals( 4, textBuffer.length() ); + } + + @Test + void testWrite() + { + TextBuffer textBuffer = new TextBuffer( ' ', 4 ); + textBuffer.write( "test" ); + assertEquals( "test", textBuffer.toString() ); + } + + @Test + void testWriteTextBuffer() + { + TextBuffer source = new TextBuffer( "test" ); + TextBuffer target = new TextBuffer( " " ); + target.write( source ); + assertEquals( "test", target.toString() ); + } + + @Test + void testWriteFromPos() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.write( "il", 1 ); + assertEquals( "tilt", textBuffer.toString() ); + } + + @Test + void testWriteOutOfBounds() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.write( "abcdefghijklmnop", -5 ); + assertEquals( "fghi", textBuffer.toString() ); + } + + @Test + void testWriteOutOfBounds2() + { + TextBuffer textBuffer = new TextBuffer( " " ); + textBuffer.write( "Hello, world!", -3 ); + assertEquals( "lo, world! ", textBuffer.toString() ); + } + + @Test + void testFill() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.fill( 'c' ); + assertEquals( "cccc", textBuffer.toString() ); + } + + @Test + void testFillSubstring() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.fill( 'c', 1, 3 ); + assertEquals( "tcct", textBuffer.toString() ); + } + + @Test + void testFillOutOfBounds() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.fill( 'c', -5, 5 ); + assertEquals( "cccc", textBuffer.toString() ); + } + + @Test + void testCharAt() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + assertEquals( 'e', textBuffer.charAt( 1 ) ); + } + + @Test + void testSetChar() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.setChar( 2, 'n' ); + assertEquals( "tent", textBuffer.toString() ); + } + + @Test + void testSetCharWithNegativeIndex() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.setChar( -5, 'n' ); + assertEquals( "test", textBuffer.toString(), "Buffer should not change after setting char with negative index." ); + } + + @Test + void testSetCharWithIndexBeyondBufferEnd() + { + TextBuffer textBuffer = new TextBuffer( "test" ); + textBuffer.setChar( 10, 'n' ); + assertEquals( "test", textBuffer.toString(), "Buffer should not change after setting char beyond buffer end." ); + } + + @Test + void testMultipleOperations() + { + TextBuffer textBuffer = new TextBuffer( ' ', 5 ); + textBuffer.setChar( 0, 'H' ); + textBuffer.setChar( 1, 'e' ); + textBuffer.setChar( 2, 'l' ); + textBuffer.write( "lo", 3 ); + assertEquals( "Hello", textBuffer.toString(), "TextBuffer failed to persist over multiple operations." ); + } + + @Test + void testEmptyBuffer() + { + TextBuffer textBuffer = new TextBuffer( "" ); + // exception on writing to empty buffer would fail the test + textBuffer.write( "test" ); + assertEquals( "", textBuffer.toString() ); + } +} From 32d956bbe7d2bb32f06cc25ceaf69f59ddace631 Mon Sep 17 00:00:00 2001 From: Wojbie Date: Fri, 19 Mar 2021 16:07:20 +0100 Subject: [PATCH 460/711] Fix missing `term.setCursorBlink(true)` in edit.lua --- src/main/resources/data/computercraft/lua/rom/programs/edit.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua index f67bd0ede..c913aa234 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/edit.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/edit.lua @@ -801,6 +801,7 @@ while bRunning do end else bMenu = false + term.setCursorBlink(true) redrawMenu() end end From e48427dbbcb9c0c2211564733e69dd66135b2b25 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 28 Mar 2021 19:38:25 +0100 Subject: [PATCH 461/711] Add documentation for io.setvbuf Fixes #746. Love how "good first issue" guarantees that nobody will do it. Not actually true, and thank you for those people who have contributed! --- .../resources/data/computercraft/lua/rom/apis/io.lua | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/io.lua b/src/main/resources/data/computercraft/lua/rom/apis/io.lua index 5ecbdf652..4898df308 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/io.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/io.lua @@ -137,6 +137,15 @@ handleMetatable = { return handle.seek(whence, offset) end, + --[[- Sets the buffering mode for an output file. + + This has no effect under ComputerCraft, and exists with compatility + with base Lua. + @tparam string mode The buffering mode. + @tparam[opt] number size The size of the buffer. + @see file:setvbuf Lua's documentation for `setvbuf`. + @deprecated This has no effect in CC. + ]] setvbuf = function(self, mode, size) end, --- Write one or more values to the file From 9708dd67864143d1588697d81cdeae97c66fbb26 Mon Sep 17 00:00:00 2001 From: lily <56274881+lilyzeiset@users.noreply.github.com> Date: Fri, 2 Apr 2021 10:30:28 -0400 Subject: [PATCH 462/711] Fixed sortCoords for draw functions (#749) --- .../data/computercraft/lua/rom/apis/paintutils.lua | 12 +++++++++++- .../test-rom/spec/apis/paintutils_spec.lua | 13 +++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua index b920341c3..f6f1efaac 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua @@ -132,7 +132,17 @@ function drawLine(startX, startY, endX, endY, colour) return end - local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) + local minX = math.min(startX, endX) + local maxX, minY, maxY + if minX == startX then + minY = startY + maxX = endX + maxY = endY + else + minY = endY + maxX = startX + maxY = startY + end -- TODO: clip to screen rectangle? diff --git a/src/test/resources/test-rom/spec/apis/paintutils_spec.lua b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua index fc2b6008c..f13bbcfd2 100644 --- a/src/test/resources/test-rom/spec/apis/paintutils_spec.lua +++ b/src/test/resources/test-rom/spec/apis/paintutils_spec.lua @@ -67,6 +67,19 @@ describe("The paintutils library", function() { " ", "000", "ffe" }, }) end) + + it("draws a line going diagonally from bottom left", function() + local w = with_window(3, 3, function() + term.setBackgroundColour(colours.red) + paintutils.drawLine(1, 3, 3, 1) + end) + + window_eq(w, { + { " ", "000", "ffe" }, + { " ", "000", "fef" }, + { " ", "000", "eff" }, + }) + end) end) describe("paintutils.drawBox", function() From 51d3b091da4e4083f3616e5ed65fdfceaaf90cd0 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 3 Apr 2021 12:44:22 +0100 Subject: [PATCH 463/711] "Finish" documentation for several modules - Add remaining docs for the turtle API - Add documentation for the fluid storage peripheral. - Enforce undocumented warning for most modules (only io and window remaining). "Finish" in quotes, because these are clearly a long way from perfect. I'm bad at writing docs, OK! --- doc/stub/turtle.lua | 12 ++ illuaminate.sexp | 21 +--- .../generic/methods/FluidMethods.java | 45 +++++++ .../generic/methods/InventoryMethods.java | 4 +- .../shared/turtle/apis/TurtleAPI.java | 118 ++++++++++++++++++ .../lua/rom/apis/turtle/turtle.lua | 1 + 6 files changed, 183 insertions(+), 18 deletions(-) diff --git a/doc/stub/turtle.lua b/doc/stub/turtle.lua index f5668f1ae..a2c0eef55 100644 --- a/doc/stub/turtle.lua +++ b/doc/stub/turtle.lua @@ -1 +1,13 @@ +--[[- Craft a recipe based on the turtle's inventory. + +The turtle's inventory should set up like a crafting grid. For instance, to +craft sticks, slots 1 and 5 should contain sticks. _All_ other slots should be +empty, including those outside the crafting "grid". + +@tparam[opt=64] number limit The maximum number of crafting steps to run. +@throws When limit is less than 1 or greater than 64. +@treturn[1] true If crafting succeeds. +@treturn[2] false If crafting fails. +@treturn string A string describing why crafting failed. +]] function craft(limit) end diff --git a/illuaminate.sexp b/illuaminate.sexp index 61f671582..22d222f7e 100644 --- a/illuaminate.sexp +++ b/illuaminate.sexp @@ -88,27 +88,16 @@ ;; Suppress warnings for currently undocumented modules. (at - (; Java APIs - /doc/stub/http.lua - /doc/stub/os.lua - /doc/stub/turtle.lua - /doc/stub/global.lua - ; Java generated APIs - /build/docs/luaJavadoc/turtle.lua - ; Peripherals - /build/docs/luaJavadoc/drive.lua - /build/docs/luaJavadoc/speaker.lua - /build/docs/luaJavadoc/printer.lua - ; Generic peripherals - /build/docs/luaJavadoc/fluid_storage.lua - ; Lua APIs + (; Lua APIs /src/main/resources/*/computercraft/lua/rom/apis/io.lua /src/main/resources/*/computercraft/lua/rom/apis/window.lua) (linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return)) -;; Suppress warnings for the BIOS using its own deprecated members for now. -(at /src/main/resources/*/computercraft/lua/bios.lua +;; Suppress warnings for various APIs using its own deprecated members. +(at + (/src/main/resources/*/computercraft/lua/bios.lua + /src/main/resources/*/computercraft/lua/rom/apis/turtle/turtle.lua) (linters -var:deprecated)) (at /src/test/resources/test-rom diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java index a9d206f5a..9c994aa6e 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -45,6 +45,19 @@ public class FluidMethods implements GenericSource return new ResourceLocation( ForgeVersion.MOD_ID, "fluid" ); } + /** + * Get all "tanks" in this fluid storage. + * + * Each tank either contains some amount of fluid or is empty. Tanks with fluids inside will return some basic + * information about the fluid, including its name and amount. + * + * The returned table is sparse, and so empty tanks will be `nil` - it is recommended to loop over using `pairs` + * rather than `ipairs`. + * + * @param fluids The current fluid handler. + * @return All tanks. + * @cc.treturn { (table|nil)... } All tanks in this fluid storage. + */ @LuaFunction( mainThread = true ) public static Map> tanks( IFluidHandler fluids ) { @@ -59,6 +72,22 @@ public class FluidMethods implements GenericSource return result; } + /** + * Move a fluid from one fluid container to another connected one. + * + * This allows you to pull fluid in the current fluid container to another container on the same wired + * network. Both containers must attached to wired modems which are connected via a cable. + * + * @param from Container to move fluid from. + * @param computer The current computer. + * @param toName The name of the peripheral/container to push to. This is the string given to @{peripheral.wrap}, + * and displayed by the wired modem. + * @param limit The maximum amount of fluid to move. + * @param fluidName The fluid to move. If not given, an arbitrary fluid will be chosen. + * @return The amount of moved fluid. + * @throws LuaException If the peripheral to transfer to doesn't exist or isn't an fluid container. + * @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral. + */ @LuaFunction( mainThread = true ) public static int pushFluid( IFluidHandler from, IComputerAccess computer, @@ -84,6 +113,22 @@ public class FluidMethods implements GenericSource : moveFluid( from, new FluidStack( fluid, actualLimit ), to ); } + /** + * Move a fluid from a connected fluid container into this oneone. + * + * This allows you to pull fluid in the current fluid container from another container on the same wired + * network. Both containers must attached to wired modems which are connected via a cable. + * + * @param to Container to move fluid to. + * @param computer The current computer. + * @param fromName The name of the peripheral/container to push to. This is the string given to @{peripheral.wrap}, + * and displayed by the wired modem. + * @param limit The maximum amount of fluid to move. + * @param fluidName The fluid to move. If not given, an arbitrary fluid will be chosen. + * @return The amount of moved fluid. + * @throws LuaException If the peripheral to transfer to doesn't exist or isn't an fluid container. + * @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral. + */ @LuaFunction( mainThread = true ) public static int pullFluid( IFluidHandler to, IComputerAccess computer, diff --git a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 0663d66ad..64e342b30 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -65,8 +65,8 @@ public class InventoryMethods implements GenericSource * {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched * with {@link #getItemDetail}. * - * The table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` rather than - * `ipairs`. + * The returned table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` + * rather than `ipairs`. * * @param inventory The current inventory. * @return All items in this inventory. diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index 671c9a3b7..cd3862b07 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -371,18 +371,36 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleDetectCommand( InteractDirection.DOWN ) ); } + /** + * Check if the block in front of the turtle is equal to the item in the currently selected slot. + * + * @return If the block and item are equal. + * @cc.treturn boolean If the block and item are equal. + */ @LuaFunction public final MethodResult compare() { return trackCommand( new TurtleCompareCommand( InteractDirection.FORWARD ) ); } + /** + * Check if the block above the turtle is equal to the item in the currently selected slot. + * + * @return If the block and item are equal. + * @cc.treturn boolean If the block and item are equal. + */ @LuaFunction public final MethodResult compareUp() { return trackCommand( new TurtleCompareCommand( InteractDirection.UP ) ); } + /** + * Check if the block below the turtle is equal to the item in the currently selected slot. + * + * @return If the block and item are equal. + * @cc.treturn boolean If the block and item are equal. + */ @LuaFunction public final MethodResult compareDown() { @@ -478,12 +496,57 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleSuckCommand( InteractDirection.DOWN, checkCount( count ) ) ); } + /** + * Get the maximum amount of fuel this turtle currently holds. + * + * @return The fuel level, or "unlimited". + * @cc.treturn[1] number The current amount of fuel a turtle this turtle has. + * @cc.treturn[2] "unlimited" If turtles do not consume fuel when moving. + * @see #getFuelLimit() + * @see #refuel(Optional) + */ @LuaFunction public final Object getFuelLevel() { return turtle.isFuelNeeded() ? turtle.getFuelLevel() : "unlimited"; } + /** + * Refuel this turtle. + * + * While most actions a turtle can perform (such as digging or placing blocks), moving consumes fuel from the + * turtle's internal buffer. If a turtle has no fuel, it will not move. + * + * {@link #refuel} refuels the turtle, consuming fuel items (such as coal or lava buckets) from the currently + * selected slot and converting them into energy. This finishes once the turtle is fully refuelled or all items have + * been consumed. + * + * @param countA The maximum number of items to consume. One can pass `0` to check if an item is combustable or not. + * @return If this turtle could be refuelled. + * @throws LuaException If the refuel count is out of range. + * @cc.treturn[1] true If the turtle was refuelled. + * @cc.treturn[2] false If the turtle was not refuelled. + * @cc.treturn[2] string The reason the turtle was not refuelled ( + * @cc.usage Refuel a turtle from the currently selected slot. + *

{@code
+     * local level = turtle.getFuelLevel()
+     * if new_level == "unlimited" then error("Turtle does not need fuel", 0) end
+     *
+     * local ok, err = turtle.refuel()
+     * if ok then
+     *   local new_level = turtle.getFuelLevel()
+     *   print(("Refuelled %d, current level is %d"):format(new_level - level, new_level))
+     * else
+     *   printError(err)
+     * end}
+ * @cc.usage Check if the current item is a valid fuel source. + *
{@code
+     * local is_fuel, reason = turtle.refuel(0)
+     * if not is_fuel then printError(reason) end
+     * }
+ * @see #getFuelLevel() + * @see #getFuelLimit() + */ @LuaFunction public final MethodResult refuel( Optional countA ) throws LuaException { @@ -492,12 +555,30 @@ public class TurtleAPI implements ILuaAPI return trackCommand( new TurtleRefuelCommand( count ) ); } + /** + * Compare the item in the currently selected slot to the item in another slot. + * + * @param slot The slot to compare to. + * @return If the items are the same. + * @throws LuaException If the slot is out of range. + * @cc.treturn boolean If the two items are equal. + */ @LuaFunction public final MethodResult compareTo( int slot ) throws LuaException { return trackCommand( new TurtleCompareToCommand( checkSlot( slot ) ) ); } + /** + * Move an item from the selected slot to another one. + * + * @param slotArg The slot to move this item to. + * @param countArg The maximum number of items to move. + * @return If the item was moved or not. + * @throws LuaException If the slot is out of range. + * @throws LuaException If the number of items is out of range. + * @cc.treturn boolean If some items were successfully moved. + */ @LuaFunction public final MethodResult transferTo( int slotArg, Optional countArg ) throws LuaException { @@ -518,18 +599,55 @@ public class TurtleAPI implements ILuaAPI return turtle.getSelectedSlot() + 1; } + /** + * Get the maximum amount of fuel this turtle can hold. + * + * By default, normal turtles have a limit of 20,000 and advanced turtles of 100,000. + * + * @return The limit, or "unlimited". + * @cc.treturn[1] number The maximum amount of fuel a turtle can hold. + * @cc.treturn[2] "unlimited" If turtles do not consume fuel when moving. + * @see #getFuelLevel() + * @see #refuel(Optional) + */ @LuaFunction public final Object getFuelLimit() { return turtle.isFuelNeeded() ? turtle.getFuelLimit() : "unlimited"; } + /** + * Equip (or unequip) an item on the left side of this turtle. + * + * This finds the item in the currently selected slot and attempts to equip it to the left side of the turtle. The + * previous upgrade is removed and placed into the turtle's inventory. If there is no item in the slot, the previous + * upgrade is removed, but no new one is equipped. + * + * @return Whether an item was equiped or not. + * @cc.treturn[1] true If the item was equipped. + * @cc.treturn[2] false If we could not equip the item. + * @cc.treturn[2] string The reason equipping this item failed. + * @see #equipRight() + */ @LuaFunction public final MethodResult equipLeft() { return trackCommand( new TurtleEquipCommand( TurtleSide.LEFT ) ); } + /** + * Equip (or unequip) an item on the right side of this turtle. + * + * This finds the item in the currently selected slot and attempts to equip it to the right side of the turtle. The + * previous upgrade is removed and placed into the turtle's inventory. If there is no item in the slot, the previous + * upgrade is removed, but no new one is equipped. + * + * @return Whether an item was equiped or not. + * @cc.treturn[1] true If the item was equipped. + * @cc.treturn[2] false If we could not equip the item. + * @cc.treturn[2] string The reason equipping this item failed. + * @see #equipRight() + */ @LuaFunction public final MethodResult equipRight() { diff --git a/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua b/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua index c9d57bf12..0a66add16 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua @@ -10,6 +10,7 @@ end -- -- Generally you should not need to use this table - it only exists for -- backwards compatibility reasons. +-- @deprecated native = turtle.native or turtle local function addCraftMethod(object) From e8f5531a8c45718baf7d56d828278727782f7de6 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 3 Apr 2021 12:55:20 +0100 Subject: [PATCH 464/711] Fix checkstyle --- .../shared/turtle/apis/TurtleAPI.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java index cd3862b07..6c87be3d2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -500,8 +500,8 @@ public class TurtleAPI implements ILuaAPI * Get the maximum amount of fuel this turtle currently holds. * * @return The fuel level, or "unlimited". - * @cc.treturn[1] number The current amount of fuel a turtle this turtle has. - * @cc.treturn[2] "unlimited" If turtles do not consume fuel when moving. + * @cc.treturn [1] number The current amount of fuel a turtle this turtle has. + * @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving. * @see #getFuelLimit() * @see #refuel(Optional) */ @@ -524,9 +524,9 @@ public class TurtleAPI implements ILuaAPI * @param countA The maximum number of items to consume. One can pass `0` to check if an item is combustable or not. * @return If this turtle could be refuelled. * @throws LuaException If the refuel count is out of range. - * @cc.treturn[1] true If the turtle was refuelled. - * @cc.treturn[2] false If the turtle was not refuelled. - * @cc.treturn[2] string The reason the turtle was not refuelled ( + * @cc.treturn [1] true If the turtle was refuelled. + * @cc.treturn [2] false If the turtle was not refuelled. + * @cc.treturn [2] string The reason the turtle was not refuelled ( * @cc.usage Refuel a turtle from the currently selected slot. *
{@code
      * local level = turtle.getFuelLevel()
@@ -605,8 +605,8 @@ public class TurtleAPI implements ILuaAPI
      * By default, normal turtles have a limit of 20,000 and advanced turtles of 100,000.
      *
      * @return The limit, or "unlimited".
-     * @cc.treturn[1] number The maximum amount of fuel a turtle can hold.
-     * @cc.treturn[2] "unlimited" If turtles do not consume fuel when moving.
+     * @cc.treturn [1] number The maximum amount of fuel a turtle can hold.
+     * @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
      * @see #getFuelLevel()
      * @see #refuel(Optional)
      */
@@ -624,9 +624,9 @@ public class TurtleAPI implements ILuaAPI
      * upgrade is removed, but no new one is equipped.
      *
      * @return Whether an item was equiped or not.
-     * @cc.treturn[1] true If the item was equipped.
-     * @cc.treturn[2] false If we could not equip the item.
-     * @cc.treturn[2] string The reason equipping this item failed.
+     * @cc.treturn [1] true If the item was equipped.
+     * @cc.treturn [2] false If we could not equip the item.
+     * @cc.treturn [2] string The reason equipping this item failed.
      * @see #equipRight()
      */
     @LuaFunction
@@ -643,9 +643,9 @@ public class TurtleAPI implements ILuaAPI
      * upgrade is removed, but no new one is equipped.
      *
      * @return Whether an item was equiped or not.
-     * @cc.treturn[1] true If the item was equipped.
-     * @cc.treturn[2] false If we could not equip the item.
-     * @cc.treturn[2] string The reason equipping this item failed.
+     * @cc.treturn [1] true If the item was equipped.
+     * @cc.treturn [2] false If we could not equip the item.
+     * @cc.treturn [2] string The reason equipping this item failed.
      * @see #equipRight()
      */
     @LuaFunction

From b17ff6daf03e0be2b919a2cab3846ac6b0b6cd45 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 3 Apr 2021 14:08:58 +0100
Subject: [PATCH 465/711] Fix a couple of JEI issues

 - Don't treat turtles/pocket computers with no upgrades as an "any"
   turtle. Otherwise getting the recipe of a crafty turtle shows the
   recipe of a normal turtle too.
 - Fix "get usage" of upgrade items not returning their recipes.
 - Fix NPEs inside JEI (closes #719)
---
 .../shared/integration/jei/JEIComputerCraft.java     | 12 ++++++------
 .../shared/integration/jei/RecipeResolver.java       |  9 +--------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java
index a6ea2fc91..cb4ca8e81 100644
--- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java
+++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java
@@ -114,10 +114,10 @@ public class JEIComputerCraft implements IModPlugin
      */
     private static final ISubtypeInterpreter turtleSubtype = stack -> {
         Item item = stack.getItem();
-        if( !(item instanceof ITurtleItem) ) return "";
+        if( !(item instanceof ITurtleItem) ) return ISubtypeInterpreter.NONE;
 
         ITurtleItem turtle = (ITurtleItem) item;
-        StringBuilder name = new StringBuilder();
+        StringBuilder name = new StringBuilder("turtle:");
 
         // Add left and right upgrades to the identifier
         ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT );
@@ -134,9 +134,9 @@ public class JEIComputerCraft implements IModPlugin
      */
     private static final ISubtypeInterpreter pocketSubtype = stack -> {
         Item item = stack.getItem();
-        if( !(item instanceof ItemPocketComputer) ) return "";
+        if( !(item instanceof ItemPocketComputer) ) return ISubtypeInterpreter.NONE;
 
-        StringBuilder name = new StringBuilder();
+        StringBuilder name = new StringBuilder("pocket:");
 
         // Add the upgrade to the identifier
         IPocketUpgrade upgrade = ItemPocketComputer.getUpgrade( stack );
@@ -150,11 +150,11 @@ public class JEIComputerCraft implements IModPlugin
      */
     private static final ISubtypeInterpreter diskSubtype = stack -> {
         Item item = stack.getItem();
-        if( !(item instanceof ItemDisk) ) return "";
+        if( !(item instanceof ItemDisk) ) return ISubtypeInterpreter.NONE;
 
         ItemDisk disk = (ItemDisk) item;
 
         int colour = disk.getColour( stack );
-        return colour == -1 ? "" : String.format( "%06x", colour );
+        return colour == -1 ? ISubtypeInterpreter.NONE : String.format( "%06x", colour );
     };
 }
diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java
index a3a4810d6..2050a83e7 100644
--- a/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java
+++ b/src/main/java/dan200/computercraft/shared/integration/jei/RecipeResolver.java
@@ -200,7 +200,7 @@ class RecipeResolver implements IRecipeManagerPlugin
             for( UpgradeInfo upgrade : upgrades )
             {
                 ItemStack craftingStack = upgrade.stack;
-                if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.upgrade.isItemSuitable( stack ) )
+                if( craftingStack.isEmpty() || craftingStack.getItem() != stack.getItem() || !upgrade.upgrade.isItemSuitable( stack ) )
                 {
                     continue;
                 }
@@ -319,13 +319,6 @@ class RecipeResolver implements IRecipeManagerPlugin
             super( ID, null, width, height, input, output );
         }
 
-        @Nonnull
-        @Override
-        public ResourceLocation getId()
-        {
-            return null;
-        }
-
         @Nonnull
         @Override
         public IRecipeSerializer getSerializer()

From c3f57004943aa515a5ff83329c20a5bc72ba50b2 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 3 Apr 2021 14:13:55 +0100
Subject: [PATCH 466/711] Fix checkstyle

Today is not a good day apparently :D:.
---
 .../shared/integration/jei/JEIComputerCraft.java              | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java
index cb4ca8e81..ae8f9589f 100644
--- a/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java
+++ b/src/main/java/dan200/computercraft/shared/integration/jei/JEIComputerCraft.java
@@ -117,7 +117,7 @@ public class JEIComputerCraft implements IModPlugin
         if( !(item instanceof ITurtleItem) ) return ISubtypeInterpreter.NONE;
 
         ITurtleItem turtle = (ITurtleItem) item;
-        StringBuilder name = new StringBuilder("turtle:");
+        StringBuilder name = new StringBuilder( "turtle:" );
 
         // Add left and right upgrades to the identifier
         ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT );
@@ -136,7 +136,7 @@ public class JEIComputerCraft implements IModPlugin
         Item item = stack.getItem();
         if( !(item instanceof ItemPocketComputer) ) return ISubtypeInterpreter.NONE;
 
-        StringBuilder name = new StringBuilder("pocket:");
+        StringBuilder name = new StringBuilder( "pocket:" );
 
         // Add the upgrade to the identifier
         IPocketUpgrade upgrade = ItemPocketComputer.getUpgrade( stack );

From 17b5bca4434fc84dd7321f9d50300f17497c6dde Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 7 Apr 2021 18:34:55 +0100
Subject: [PATCH 467/711] Make the peripheral API examples a little clearer

---
 .../computercraft/lua/rom/apis/peripheral.lua | 33 ++++++++++++-------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua
index c284d0691..0f3478046 100644
--- a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua
+++ b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua
@@ -161,7 +161,9 @@ end
 -- @tparam string name The name of the peripheral to wrap.
 -- @treturn table|nil The table containing the peripheral's methods, or `nil` if
 -- there is no peripheral present with the given name.
--- @usage peripheral.wrap("top").open(1)
+-- @usage Open the modem on the top of this computer.
+--
+--     peripheral.wrap("top").open(1)
 function wrap(name)
     expect(1, name, "string")
 
@@ -183,16 +185,25 @@ function wrap(name)
     return result
 end
 
---- Find all peripherals of a specific type, and return the
--- @{peripheral.wrap|wrapped} peripherals.
---
--- @tparam string ty The type of peripheral to look for.
--- @tparam[opt] function(name:string, wrapped:table):boolean filter A
--- filter function, which takes the peripheral's name and wrapped table
--- and returns if it should be included in the result.
--- @treturn table... 0 or more wrapped peripherals matching the given filters.
--- @usage { peripheral.find("monitor") }
--- @usage peripheral.find("modem", rednet.open)
+--[[- Find all peripherals of a specific type, and return the
+@{peripheral.wrap|wrapped} peripherals.
+
+@tparam string ty The type of peripheral to look for.
+@tparam[opt] function(name:string, wrapped:table):boolean filter A
+filter function, which takes the peripheral's name and wrapped table
+and returns if it should be included in the result.
+@treturn table... 0 or more wrapped peripherals matching the given filters.
+@usage Find all monitors and store them in a table, writing "Hello" on each one.
+
+    local monitors = { peripheral.find("monitor") }
+    for _, monitor in pairs(monitors) do
+      monitor.write("Hello")
+    end
+
+@usage This abuses the `filter` argument to call @{rednet.open} on every modem.
+
+    peripheral.find("modem", rednet.open)
+]]
 function find(ty, filter)
     expect(1, ty, "string")
     expect(2, filter, "function", "nil")

From 058d63e77ffe45fea917dde8a641277c68b53be2 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sun, 11 Apr 2021 18:43:24 +0100
Subject: [PATCH 468/711] Add citation to cc.pretty

ust to look extra pretentious.
---
 .../lua/rom/modules/main/cc/pretty.lua        | 45 ++++++++++---------
 1 file changed, 25 insertions(+), 20 deletions(-)

diff --git a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua
index 9a3aa7b0a..f202c204e 100644
--- a/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua
+++ b/src/main/resources/data/computercraft/lua/rom/modules/main/cc/pretty.lua
@@ -1,23 +1,28 @@
---- Provides a "pretty printer", for rendering data structures in an
--- aesthetically pleasing manner.
---
--- In order to display something using @{cc.pretty}, you build up a series of
--- @{Doc|documents}. These behave a little bit like strings; you can concatenate
--- them together and then print them to the screen.
---
--- However, documents also allow you to control how they should be printed. There
--- are several functions (such as @{nest} and @{group}) which allow you to control
--- the "layout" of the document. When you come to display the document, the 'best'
--- (most compact) layout is used.
---
--- @module cc.pretty
--- @usage Print a table to the terminal
---     local pretty = require "cc.pretty"
---     pretty.print(pretty.pretty({ 1, 2, 3 }))
---
--- @usage Build a custom document and display it
---     local pretty = require "cc.pretty"
---     pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
+--[[- Provides a "pretty printer", for rendering data structures in an
+aesthetically pleasing manner.
+
+In order to display something using @{cc.pretty}, you build up a series of
+@{Doc|documents}. These behave a little bit like strings; you can concatenate
+them together and then print them to the screen.
+
+However, documents also allow you to control how they should be printed. There
+are several functions (such as @{nest} and @{group}) which allow you to control
+the "layout" of the document. When you come to display the document, the 'best'
+(most compact) layout is used.
+
+The structure of this module is based on [A Prettier Printer][prettier].
+
+[prettier]: https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf "A Prettier Printer"
+
+@module cc.pretty
+@usage Print a table to the terminal
+    local pretty = require "cc.pretty"
+    pretty.print(pretty.pretty({ 1, 2, 3 }))
+
+@usage Build a custom document and display it
+    local pretty = require "cc.pretty"
+    pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
+]]
 
 local expect = require "cc.expect"
 local expect, field = expect.expect, expect.field

From 8494ba8ce29cd8d7b9105eef497fe3fe3f89d350 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Tue, 13 Apr 2021 13:01:28 +0100
Subject: [PATCH 469/711] Improve UX when a resource mount cannot be found

 - Add a full example of the docs. Hopefully is a little more explicit.
 - Print a warning when the mount is empty.

Closes #762
---
 .../dan200/computercraft/api/ComputerCraftAPI.java  |  4 +++-
 .../core/filesystem/ResourceMount.java              | 13 +++++++++++++
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
index f429ca946..2c4223725 100644
--- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
+++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java
@@ -98,7 +98,9 @@ public final class ComputerCraftAPI
      * resource folder onto a computer's file system.
      *
      * The files in this mount will be a combination of files in all mod jar, and data packs that contain
-     * resources with the same domain and path.
+     * resources with the same domain and path. For instance, ComputerCraft's resources are stored in
+     * "/data/computercraft/lua/rom". We construct a mount for that with
+     * {@code createResourceMount("computercraft", "lua/rom")}.
      *
      * @param domain  The domain under which to look for resources. eg: "mymod".
      * @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
index ed21df789..afaa3dbb9 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
@@ -103,9 +103,13 @@ public final class ResourceMount implements IMount
     private void load()
     {
         boolean hasAny = false;
+        String existingNamespace = null;
+
         FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
         for( ResourceLocation file : manager.listResources( subPath, s -> true ) )
         {
+            existingNamespace = file.getNamespace();
+
             if( !file.getNamespace().equals( namespace ) ) continue;
 
             String localPath = FileSystem.toLocal( file.getPath(), subPath );
@@ -114,6 +118,15 @@ public final class ResourceMount implements IMount
         }
 
         root = hasAny ? newRoot : null;
+
+        if( !hasAny )
+        {
+            ComputerCraft.log.warn("Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath);
+            if( newRoot != null )
+            {
+                ComputerCraft.log.warn("There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath);
+            }
+        }
     }
 
     private FileEntry get( String path )

From c45221a2d0e91eaebabc495a817c009e6dc6b321 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Tue, 13 Apr 2021 13:03:26 +0100
Subject: [PATCH 470/711] Fix checkstyle

This is gonna be 50% of my commits at this rate.
---
 .../dan200/computercraft/core/filesystem/ResourceMount.java   | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
index afaa3dbb9..279871e50 100644
--- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
+++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java
@@ -121,10 +121,10 @@ public final class ResourceMount implements IMount
 
         if( !hasAny )
         {
-            ComputerCraft.log.warn("Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath);
+            ComputerCraft.log.warn( "Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath );
             if( newRoot != null )
             {
-                ComputerCraft.log.warn("There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath);
+                ComputerCraft.log.warn( "There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath );
             }
         }
     }

From 003c7ec2e87235d093b7e82de0383c21293d767e Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Fri, 23 Apr 2021 22:26:00 +0100
Subject: [PATCH 471/711] Fix Forge maven location

1.16 is going to be sad for a while, as I need to work out FG 4 woes.
---
 build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/build.gradle b/build.gradle
index 7230d002b..416675f2e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,12 +4,12 @@ buildscript {
         mavenCentral()
         maven {
             name = "forge"
-            url = "https://files.minecraftforge.net/maven"
+            url = "https://maven.minecraftforge.net"
         }
     }
     dependencies {
         classpath 'com.google.code.gson:gson:2.8.1'
-        classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.3'
+        classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.9'
         classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
     }
 }

From 92b45b18682e3e9f588bce5472cd1490ca764808 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Sat, 24 Apr 2021 11:26:04 +0100
Subject: [PATCH 472/711] Switch to using maven-publish

The old maven package is removed in Gradle 7.0. Instead, we publish to
squiddev.cc using WebDAV (ewww).
---
 build.gradle | 87 +++++++++++++++++++++-------------------------------
 1 file changed, 35 insertions(+), 52 deletions(-)

diff --git a/build.gradle b/build.gradle
index 416675f2e..2ede63c40 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,6 +17,7 @@ buildscript {
 plugins {
     id "checkstyle"
     id "jacoco"
+    id "maven-publish"
     id "com.github.hierynomus.license" version "0.15.0"
     id "com.matthewprenger.cursegradle" version "1.4.0"
     id "com.github.breadmoirai.github-release" version "2.2.12"
@@ -24,8 +25,6 @@ plugins {
 }
 
 apply plugin: 'net.minecraftforge.gradle'
-apply plugin: 'maven-publish'
-apply plugin: 'maven'
 
 version = mod_version
 
@@ -36,6 +35,9 @@ java {
     toolchain {
         languageVersion = JavaLanguageVersion.of(8)
     }
+
+    withSourcesJar()
+    withJavadocJar()
 }
 
 minecraft {
@@ -112,7 +114,6 @@ repositories {
 configurations {
     shade
     compile.extendsFrom shade
-    deployerJars
     cctJavadoc
 }
 
@@ -139,8 +140,6 @@ dependencies {
     testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72'
     testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
 
-    deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
-
     cctJavadoc 'cc.tweaked:cct-javadoc:1.3.0'
 }
 
@@ -168,8 +167,6 @@ task luaJavadoc(type: Javadoc) {
 }
 
 jar {
-    dependsOn javadoc
-
     manifest {
         attributes(["Specification-Title": "computercraft",
                     "Specification-Vendor": "SquidDev",
@@ -180,10 +177,6 @@ jar {
                     "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
     }
 
-    from (sourceSets.main.allSource) {
-        include "dan200/computercraft/api/**/*.java"
-    }
-
     from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
 }
 
@@ -550,51 +543,41 @@ curseforge {
 
 publishing {
     publications {
-        mavenJava(MavenPublication) {
+        maven(MavenPublication) {
             from components.java
-            // artifact sourceJar
+
+            pom {
+                name = 'CC: Tweaked'
+                description = 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
+                url = 'https://github.com/SquidDev-CC/CC-Tweaked'
+
+                scm {
+                    url = 'https://github.com/SquidDev-CC/CC-Tweaked.git'
+                }
+
+                issueManagement {
+                    system = 'github'
+                    url = 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
+                }
+
+                licenses {
+                    license {
+                        name = 'ComputerCraft Public License, Version 1.0'
+                        url = 'https://github.com/SquidDev-CC/CC-Tweaked/blob/mc-1.15.x/LICENSE'
+                    }
+                }
+            }
         }
     }
-}
 
-uploadArchives {
     repositories {
-        if(project.hasProperty('mavenUploadUrl')) {
-            mavenDeployer {
-                configuration = configurations.deployerJars
-
-                repository(url: project.property('mavenUploadUrl')) {
-                    authentication(
-                        userName: project.property('mavenUploadUser'),
-                        privateKey: project.property('mavenUploadKey'))
-                }
-
-                pom.project {
-                    name 'CC: Tweaked'
-                    packaging 'jar'
-                    description 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
-                    url 'https://github.com/SquidDev-CC/CC-Tweaked'
-
-                    scm {
-                        url 'https://github.com/SquidDev-CC/CC-Tweaked.git'
-                    }
-
-                    issueManagement {
-                        system 'github'
-                        url 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
-                    }
-
-                    licenses {
-                        license {
-                            name 'ComputerCraft Public License, Version 1.0'
-                            url 'https://github.com/SquidDev-CC/CC-Tweaked/blob/master/LICENSE'
-                            distribution 'repo'
-                        }
-                    }
-                }
-
-                pom.whenConfigured { pom ->
-                    pom.dependencies.clear()
+        if (project.hasProperty("mavenUser")) {
+            maven {
+                name = "SquidDev"
+                url = "https://squiddev.cc/maven"
+                credentials {
+                    username = project.property("mavenUser") as String
+                    password = project.property("mavenPass") as String
                 }
             }
         }
@@ -625,7 +608,7 @@ githubRelease {
     prerelease false
 }
 
-def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]
+def uploadTasks = ["publish", "curseforge", "githubRelease"]
 uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
 
 task uploadAll(dependsOn: uploadTasks) {

From 3cb25b3525cdad7486ce1e0222ceb7365f68c9d6 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Tue, 27 Apr 2021 22:24:28 +0100
Subject: [PATCH 473/711] Various VM tests

These are largely copied across from Cobalt's test suite, with some
minor tweaks. It actually exposed one bug in Cobalt, which is pretty
nice.

One interesting thing from the coroutine tests, is that Lua 5.4 (and
one assumes 5.2/5.3) doesn't allow yielding from within the error
handler of xpcall - I rather thought it might.

This doesn't add any of the PUC Lua tests yet - I got a little
distracted.

Also:
 - Allow skipping "keyword" tests, in the style of busted. This is
   implemented on the Java side for now.
 - Fix a bug with os.date("%I", _) not being 2 characters wide.
---
 build.gradle                                  |   1 +
 .../computercraft/core/apis/LuaDateTime.java  |   2 +-
 .../core/ComputerTestDelegate.java            |  33 +-
 src/test/resources/test-rom/mcfly.lua         |   3 +
 .../resources/test-rom/spec/apis/os_spec.lua  |   5 +
 .../resources/test-rom/spec/lua/README.md     |  19 +
 .../test-rom/spec/lua/coroutine_spec.lua      | 330 ++++++++++++++++++
 .../test-rom/spec/lua/timeout_spec.lua        |  17 +
 .../resources/test-rom/spec/lua/vm_spec.lua   |   9 +
 9 files changed, 409 insertions(+), 10 deletions(-)
 create mode 100644 src/test/resources/test-rom/spec/lua/README.md
 create mode 100644 src/test/resources/test-rom/spec/lua/coroutine_spec.lua
 create mode 100644 src/test/resources/test-rom/spec/lua/timeout_spec.lua
 create mode 100644 src/test/resources/test-rom/spec/lua/vm_spec.lua

diff --git a/build.gradle b/build.gradle
index 2ede63c40..6611a8eb7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -104,6 +104,7 @@ sourceSets {
 }
 
 repositories {
+    mavenLocal()
     mavenCentral()
     maven {
         name "SquidDev"
diff --git a/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java b/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java
index 9ad29ad4c..3293d2b7c 100644
--- a/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java
+++ b/src/main/java/dan200/computercraft/core/apis/LuaDateTime.java
@@ -89,7 +89,7 @@ final class LuaDateTime
                             formatter.appendValue( ChronoField.HOUR_OF_DAY, 2 );
                             break;
                         case 'I':
-                            formatter.appendValue( ChronoField.HOUR_OF_AMPM );
+                            formatter.appendValue( ChronoField.HOUR_OF_AMPM, 2 );
                             break;
                         case 'j':
                             formatter.appendValue( ChronoField.DAY_OF_YEAR, 3 );
diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java
index 16eab74da..de5b621bf 100644
--- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java
+++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java
@@ -42,6 +42,8 @@ import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
 import static dan200.computercraft.api.lua.LuaValues.getType;
@@ -67,6 +69,12 @@ public class ComputerTestDelegate
 
     private static final long TIMEOUT = TimeUnit.SECONDS.toNanos( 10 );
 
+    private static final Set SKIP_KEYWORDS = new HashSet<>(
+        Arrays.asList( System.getProperty( "cc.skip_keywords", "" ).split( "," ) )
+    );
+
+    private static final Pattern KEYWORD = Pattern.compile( ":([a-z_]+)" );
+
     private final ReentrantLock lock = new ReentrantLock();
     private Computer computer;
 
@@ -212,18 +220,23 @@ public class ComputerTestDelegate
 
         void runs( String name, Executable executor )
         {
-            DynamicNodeBuilder child = children.get( name );
-            int id = 0;
-            while( child != null )
-            {
-                id++;
-                String subName = name + "_" + id;
-                child = children.get( subName );
-            }
+            if( this.executor != null ) throw new IllegalStateException( name + " is leaf node" );
+            if( children.containsKey( name ) ) throw new IllegalStateException( "Duplicate key for " + name );
 
             children.put( name, new DynamicNodeBuilder( name, executor ) );
         }
 
+        boolean isActive()
+        {
+            Matcher matcher = KEYWORD.matcher( name );
+            while( matcher.find() )
+            {
+                if( SKIP_KEYWORDS.contains( matcher.group( 1 ) ) ) return false;
+            }
+
+            return true;
+        }
+
         DynamicNode build()
         {
             return executor == null
@@ -233,7 +246,9 @@ public class ComputerTestDelegate
 
         Stream buildChildren()
         {
-            return children.values().stream().map( DynamicNodeBuilder::build );
+            return children.values().stream()
+                .filter( DynamicNodeBuilder::isActive )
+                .map( DynamicNodeBuilder::build );
         }
     }
 
diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua
index ddd4f46b3..6c3bbc1df 100644
--- a/src/test/resources/test-rom/mcfly.lua
+++ b/src/test/resources/test-rom/mcfly.lua
@@ -612,6 +612,9 @@ local function do_run(test)
     elseif test.action then
         local state = push_state()
 
+        -- Flush the event queue and ensure we're running with 0 timeout.
+        os.queueEvent("start_test") os.pullEvent("start_test")
+
         local ok
         ok, err = try(test.action)
         status = ok and "pass" or (err.fail and "fail" or "error")
diff --git a/src/test/resources/test-rom/spec/apis/os_spec.lua b/src/test/resources/test-rom/spec/apis/os_spec.lua
index 7fc1add53..c04c22a48 100644
--- a/src/test/resources/test-rom/spec/apis/os_spec.lua
+++ b/src/test/resources/test-rom/spec/apis/os_spec.lua
@@ -108,6 +108,11 @@ describe("The os library", function()
                     error("Non letter character in zone: " .. zone)
                 end
             end)
+
+            local t2 = os.time { year = 2000, month = 10, day = 1, hour = 3, min = 12, sec = 17 }
+            it("for code '%I' #2", function()
+                expect(os.date("%I", t2)):eq("03")
+            end)
         end)
     end)
 
diff --git a/src/test/resources/test-rom/spec/lua/README.md b/src/test/resources/test-rom/spec/lua/README.md
new file mode 100644
index 000000000..9bd6c61a0
--- /dev/null
+++ b/src/test/resources/test-rom/spec/lua/README.md
@@ -0,0 +1,19 @@
+# Lua VM tests
+
+Unlike the rest of the test suites, the code in this folder doesn't test any
+(well, much) CC code. Instead, it ensures that the Lua VM behaves in a way that
+we expect.
+
+The VM that CC uses (LuaJ and later Cobalt) does not really conform to any one
+version of Lua, instead supporting a myriad of features from Lua 5.1 to 5.3 (and
+not always accurately). These tests attempt to pin down what behaviour is
+required for a well behaved emulator.
+
+
+These tests are split into several folders:
+ - `/` Tests for CC specific functionality, based on Cobalt/Lua quirks or needs
+   of CC.
+ - `puc`: Tests derived from the [PUC Lua test suite][puc-tests].
+
+
+[puc-tests]: https://www.lua.org/tests/ "Lua: test suites"
diff --git a/src/test/resources/test-rom/spec/lua/coroutine_spec.lua b/src/test/resources/test-rom/spec/lua/coroutine_spec.lua
new file mode 100644
index 000000000..6be0826c8
--- /dev/null
+++ b/src/test/resources/test-rom/spec/lua/coroutine_spec.lua
@@ -0,0 +1,330 @@
+describe("Coroutines", function()
+    local function assert_resume(ok, ...)
+        if ok then return table.pack(...) end
+        error(..., 0)
+    end
+
+    --- Run a function in a coroutine, "echoing" the yielded value back as the resumption value.
+    local function coroutine_echo(f)
+        local co = coroutine.create(f)
+        local result = {n = 0}
+        while coroutine.status(co) ~= "dead" do
+            result = assert_resume(coroutine.resume(co, table.unpack(result, 1, result.n)))
+        end
+
+        return table.unpack(result, 1, result.n)
+    end
+
+    describe("allow yielding", function()
+        --[[
+        Tests for some non-standard yield locations. I'm not saying that users
+        /should/ use this, but it's useful for us to allow it in order to suspend the
+        VM in arbitrary locations.
+
+        Cobalt does support this within load too, but that's unlikely to be supported
+        in the future.
+
+        These tests were split over about 7 files in Cobalt and are in one massive one
+        in this test suite. Sorry.
+        ]]
+
+        it("within debug hooks", function()
+            coroutine_echo(function()
+                local counts = { call = 0, ['return'] = 0, count = 0, line = 0 }
+
+                debug.sethook(function(kind)
+                    counts[kind] = (counts[kind] or 0) + 1
+                    expect(coroutine.yield(kind)):eq(kind)
+                end, "crl", 1)
+
+                expect(string.gsub("xyz", "x", "z")):eq("zyz")
+                expect(pcall(function()
+                    local x = 0
+                    for i = 1, 5 do x = x + i end
+                end)):eq(true)
+
+                debug.sethook(nil)
+
+                -- These numbers are going to vary beyond the different VMs a
+                -- little. As long as they're non-0, it's all fine.
+                expect(counts.call):ne(0)
+                expect(counts['return']):ne(0)
+                expect(counts.count):ne(0)
+                expect(counts.line):ne(0)
+            end)
+        end)
+
+        it("within string.gsub", function()
+            local result, count = coroutine_echo(function()
+                return ("hello world"):gsub("%w", function(entry)
+                    local x = coroutine.yield(entry)
+                    return x:upper()
+                end)
+            end)
+
+            expect(result):eq("HELLO WORLD")
+            expect(count):eq(10)
+        end)
+
+        describe("within pcall", function()
+            it("with no error", function()
+                local ok, a, b, c = coroutine_echo(function()
+                    return pcall(function()
+                        local a, b, c = coroutine.yield(1, 2, 3)
+                        return a, b, c
+                    end)
+                end)
+
+                expect(ok):eq(true)
+                expect({ a, b, c }):same { 1, 2, 3 }
+            end)
+
+            it("with an error", function()
+                local ok, msg = coroutine_echo(function()
+                    return pcall(function()
+                        local a, b, c = coroutine.yield(1, 2, 3)
+                        expect({ a, b, c }):same { 1, 2, 3 }
+                        error("Error message", 0)
+                    end)
+                end)
+
+                expect(ok):eq(false)
+                expect(msg):eq("Error message")
+            end)
+        end)
+
+        it("within table.foreach", function()
+            coroutine_echo(function()
+                local x = { 3, "foo", 4, 1 }
+                local idx = 1
+                table.foreach(x, function(key, val)
+                    expect(key):eq(idx)
+                    expect(val):eq(x[idx])
+                    expect(coroutine.yield(val)):eq(val)
+
+                    idx = idx + 1
+                end)
+            end)
+        end)
+
+        it("within table.foreachi", function()
+            coroutine_echo(function()
+                local x = { 3, "foo", 4, 1 }
+                local idx = 1
+                table.foreachi(x, function(key, val)
+                    expect(key):eq(idx)
+                    expect(val):eq(x[idx])
+                    expect(coroutine.yield(val)):eq(val)
+
+                    idx = idx + 1
+                end)
+            end)
+        end)
+
+        describe("within table.sort", function()
+            it("with a yielding comparator", function()
+                coroutine_echo(function()
+                    local x = { 32, 2, 4, 13 }
+                    table.sort(x, function(a, b)
+                        local x, y = coroutine.yield(a, b)
+                        expect(x):eq(a)
+                        expect(y):eq(b)
+
+                        return a < b
+                    end)
+
+                    expect(x[1]):eq(2)
+                    expect(x[2]):eq(4)
+                    expect(x[3]):eq(13)
+                    expect(x[4]):eq(32)
+                end)
+            end)
+
+            it("within a yielding metatable comparator", function()
+                local meta = {
+                    __lt = function(a, b)
+                        local x, y = coroutine.yield(a, b)
+                        expect(x):eq(a)
+                        expect(y):eq(b)
+
+                        return a.x < b.x
+                    end
+                }
+
+                local function create(val) return setmetatable({ x = val }, meta) end
+
+                coroutine_echo(function()
+                    local x = { create(32), create(2), create(4), create(13) }
+                    table.sort(x)
+
+                    expect(x[1].x):eq(2)
+                    expect(x[2].x):eq(4)
+                    expect(x[3].x):eq(13)
+                    expect(x[4].x):eq(32)
+                end)
+            end)
+        end)
+
+        describe("within xpcall", function()
+            it("within the main function", function()
+                -- Ensure that yielding within a xpcall works as expected
+                coroutine_echo(function()
+                    local ok, a, b, c = xpcall(function()
+                        return coroutine.yield(1, 2, 3)
+                    end, function(msg) return msg .. "!" end)
+
+                    expect(true):eq(ok)
+                    expect(1):eq(a)
+                    expect(2):eq(b)
+                    expect(3):eq(c)
+                end)
+            end)
+
+            it("within the main function (with an error)", function()
+                coroutine_echo(function()
+                    local ok, msg = xpcall(function()
+                        local a, b, c = coroutine.yield(1, 2, 3)
+                        expect(1):eq(a)
+                        expect(2):eq(b)
+                        expect(3):eq(c)
+
+                        error("Error message", 0)
+                    end, function(msg) return msg .. "!" end)
+
+                    expect(false):eq(ok)
+                    expect("Error message!"):eq(msg)
+                end)
+            end)
+
+            it("with an error in the error handler", function()
+                coroutine_echo(function()
+                    local ok, msg = xpcall(function()
+                        local a, b, c = coroutine.yield(1, 2, 3)
+                        expect(1):eq(a)
+                        expect(2):eq(b)
+                        expect(3):eq(c)
+
+                        error("Error message")
+                    end, function(msg) error(msg) end)
+
+                    expect(false):eq(ok)
+                    expect("error in error handling"):eq(msg)
+                end)
+            end)
+
+            it("within the error handler", function()
+                coroutine_echo(function()
+                    local ok, msg = xpcall(function()
+                        local a, b, c = coroutine.yield(1, 2, 3)
+                        expect(1):eq(a)
+                        expect(2):eq(b)
+                        expect(3):eq(c)
+
+                        error("Error message", 0)
+                    end, function(msg)
+                        return coroutine.yield(msg) .. "!"
+                    end)
+
+                    expect(false):eq(ok)
+                    expect("Error message!"):eq(msg)
+                end)
+            end)
+
+            it("within the error handler with an error", function()
+                coroutine_echo(function()
+                    local ok, msg = xpcall(function()
+                        local a, b, c = coroutine.yield(1, 2, 3)
+                        expect(1):eq(a)
+                        expect(2):eq(b)
+                        expect(3):eq(c)
+
+                        error("Error message", 0)
+                    end, function(msg)
+                        coroutine.yield(msg)
+                        error("nope")
+                    end)
+
+                    expect(false):eq(ok)
+                    expect("error in error handling"):eq(msg)
+                end)
+            end)
+        end)
+
+        it("within metamethods", function()
+            local create, ops
+            create = function(val) return setmetatable({ x = val }, ops) end
+            ops = {
+                __add = function(x, y)
+                    local a, b = coroutine.yield(x, y)
+                    return create(a.x + b.x)
+                end,
+                __div = function(x, y)
+                    local a, b = coroutine.yield(x, y)
+                    return create(a.x / b.x)
+                end,
+                __concat = function(x, y)
+                    local a, b = coroutine.yield(x, y)
+                    return create(a.x .. b.x)
+                end,
+                __eq = function(x, y)
+                    local a, b = coroutine.yield(x, y)
+                    return a.x == b.x
+                end,
+                __lt = function(x, y)
+                    local a, b = coroutine.yield(x, y)
+                    return a.x < b.x
+                end,
+                __index = function(tbl, key)
+                    local res = coroutine.yield(key)
+                    return res:upper()
+                end,
+                __newindex = function(tbl, key, val)
+                    local rKey, rVal = coroutine.yield(key, val)
+                    rawset(tbl, rKey, rVal .. "!")
+                end,
+            }
+
+            local varA = create(2)
+            local varB = create(3)
+
+            coroutine_echo(function()
+                expect(5):eq((varA + varB).x)
+                expect(5):eq((varB + varA).x)
+                expect(4):eq((varA + varA).x)
+                expect(6):eq((varB + varB).x)
+
+                expect(2 / 3):eq((varA / varB).x)
+                expect(3 / 2):eq((varB / varA).x)
+                expect(1):eq((varA / varA).x)
+                expect(1):eq((varB / varB).x)
+
+                expect("23"):eq((varA .. varB).x)
+                expect("32"):eq((varB .. varA).x)
+                expect("22"):eq((varA .. varA).x)
+                expect("33"):eq((varB .. varB).x)
+                expect("33333"):eq((varB .. varB .. varB .. varB .. varB).x)
+
+                expect(false):eq(varA == varB)
+                expect(false):eq(varB == varA)
+                expect(true):eq(varA == varA)
+                expect(true):eq(varB == varB)
+
+                expect(true):eq(varA < varB)
+                expect(false):eq(varB < varA)
+                expect(false):eq(varA < varA)
+                expect(false):eq(varB < varB)
+
+                expect(true):eq(varA <= varB)
+                expect(false):eq(varB <= varA)
+                expect(true):eq(varA <= varA)
+                expect(true):eq(varB <= varB)
+
+                expect("HELLO"):eq(varA.hello)
+                varA.hello = "bar"
+                expect("bar!"):eq(varA.hello)
+            end)
+
+
+        end)
+    end)
+end)
diff --git a/src/test/resources/test-rom/spec/lua/timeout_spec.lua b/src/test/resources/test-rom/spec/lua/timeout_spec.lua
new file mode 100644
index 000000000..159130d4c
--- /dev/null
+++ b/src/test/resources/test-rom/spec/lua/timeout_spec.lua
@@ -0,0 +1,17 @@
+describe("The VM terminates long running code :slow", function()
+    it("in loops", function()
+        expect.error(function() while true do end end)
+            :str_match("^.+:%d+: Too long without yielding$")
+    end)
+
+    describe("in string pattern matching", function()
+        local str, pat = ("a"):rep(1e4), ".-.-.-.-b$"
+
+        it("string.find", function()
+            expect.error(string.find, str, pat):eq("Too long without yielding")
+        end)
+        it("string.match", function()
+            expect.error(string.match, str, pat):eq("Too long without yielding")
+        end)
+    end)
+end)
diff --git a/src/test/resources/test-rom/spec/lua/vm_spec.lua b/src/test/resources/test-rom/spec/lua/vm_spec.lua
new file mode 100644
index 000000000..7f97c6fa1
--- /dev/null
+++ b/src/test/resources/test-rom/spec/lua/vm_spec.lua
@@ -0,0 +1,9 @@
+describe("The VM", function()
+    it("allows unpacking a large number of values", function()
+        -- We don't allow arbitrarily many values, half a meg is probably fine.
+        -- I don't actually have any numbers on this - maybe we do need more?
+        local len = 2^19
+        local tbl = { (" "):rep(len):byte(1, -1) }
+        expect(#tbl):eq(len)
+    end)
+end)

From abbc46877b6c82ef7d059daa16f921d764be05a4 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 28 Apr 2021 07:59:52 +0100
Subject: [PATCH 474/711] Remove mavenLocal() repository

Hopefully should bump to the latest Cobalt version too
---
 build.gradle | 1 -
 1 file changed, 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index 6611a8eb7..2ede63c40 100644
--- a/build.gradle
+++ b/build.gradle
@@ -104,7 +104,6 @@ sourceSets {
 }
 
 repositories {
-    mavenLocal()
     mavenCentral()
     maven {
         name "SquidDev"

From 74dae4ec17ea55a7e266afa03bb06c1b0b40f342 Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 28 Apr 2021 08:19:09 +0100
Subject: [PATCH 475/711] That's it, I'm adding pre-commit hooks

---
 src/test/resources/test-rom/spec/lua/coroutine_spec.lua | 4 ++--
 src/test/resources/test-rom/spec/lua/vm_spec.lua        | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/test/resources/test-rom/spec/lua/coroutine_spec.lua b/src/test/resources/test-rom/spec/lua/coroutine_spec.lua
index 6be0826c8..2bf29e260 100644
--- a/src/test/resources/test-rom/spec/lua/coroutine_spec.lua
+++ b/src/test/resources/test-rom/spec/lua/coroutine_spec.lua
@@ -7,7 +7,7 @@ describe("Coroutines", function()
     --- Run a function in a coroutine, "echoing" the yielded value back as the resumption value.
     local function coroutine_echo(f)
         local co = coroutine.create(f)
-        local result = {n = 0}
+        local result = { n = 0 }
         while coroutine.status(co) ~= "dead" do
             result = assert_resume(coroutine.resume(co, table.unpack(result, 1, result.n)))
         end
@@ -148,7 +148,7 @@ describe("Coroutines", function()
                         expect(y):eq(b)
 
                         return a.x < b.x
-                    end
+                    end,
                 }
 
                 local function create(val) return setmetatable({ x = val }, meta) end
diff --git a/src/test/resources/test-rom/spec/lua/vm_spec.lua b/src/test/resources/test-rom/spec/lua/vm_spec.lua
index 7f97c6fa1..702306939 100644
--- a/src/test/resources/test-rom/spec/lua/vm_spec.lua
+++ b/src/test/resources/test-rom/spec/lua/vm_spec.lua
@@ -2,7 +2,7 @@ describe("The VM", function()
     it("allows unpacking a large number of values", function()
         -- We don't allow arbitrarily many values, half a meg is probably fine.
         -- I don't actually have any numbers on this - maybe we do need more?
-        local len = 2^19
+        local len = 2 ^ 19
         local tbl = { (" "):rep(len):byte(1, -1) }
         expect(#tbl):eq(len)
     end)

From eb2d617ed84419c64245f08360e59de39a8e788d Mon Sep 17 00:00:00 2001
From: Jonathan Coates 
Date: Wed, 28 Apr 2021 21:24:27 +0100
Subject: [PATCH 476/711] Add a pre commit hook to lint code

This uses pre-commit [1] to check patches are well formed and run
several linters on them. We currently do some boring things (check files
are syntactically valid) as well as some project-specific ones:
 - Run illuaminate on the Lua files
 - Run checkstyle on Java

[1]: https://pre-commit.com/
---
 .editorconfig                                 |  3 --
 .github/workflows/main-ci.yml                 | 30 +++++++-----
 CONTRIBUTING.md                               |  8 ++--
 LICENSE                                       | 14 +++---
 config/idea/codeInspectionSettings.xml        |  2 +-
 config/idea/codeStyleSettings.xml             |  2 +-
 config/pre-commit/config.yml                  | 48 +++++++++++++++++++
 config/pre-commit/illuaminate-lint.sh         |  9 ++++
 doc/events/key.md                             |  2 +-
 .../computercraft/lua/rom/apis/colours.lua    |  2 +-
 .../computercraft/lua/rom/autorun/.ignoreme   |  2 +-
 tools/check-lines.py                          | 45 -----------------
 12 files changed, 90 insertions(+), 77 deletions(-)
 create mode 100644 config/pre-commit/config.yml
 create mode 100755 config/pre-commit/illuaminate-lint.sh
 delete mode 100644 tools/check-lines.py

diff --git a/.editorconfig b/.editorconfig
index f5f23d8d4..dadfafa5b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -16,6 +16,3 @@ indent_size = 2
 
 [*.yml]
 indent_size = 2
-
-[*.properties]
-insert_final_newline = false
diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml
index 64b5a89c0..646f3123c 100644
--- a/.github/workflows/main-ci.yml
+++ b/.github/workflows/main-ci.yml
@@ -23,10 +23,15 @@ jobs:
         restore-keys: |
           ${{ runner.os }}-gradle-
 
+    - name: Disable Gradle daemon
+      run: |
+        mkdir -p ~/.gradle
+        echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
+
     - name: Build with Gradle
       run: |
-        ./gradlew assemble --no-daemon || ./gradlew assemble --no-daemon
-        ./gradlew downloadAssets --no-daemon || ./gradlew downloadAssets --no-daemon
+        ./gradlew assemble || ./gradlew assemble
+        ./gradlew downloadAssets || ./gradlew downloadAssets
         ./gradlew build
 
     - name: Upload Jar
@@ -39,15 +44,14 @@ jobs:
       run: bash <(curl -s https://codecov.io/bash)
       continue-on-error: true
 
-    - name: Generate Java documentation stubs
-      run: ./gradlew luaJavadoc --no-daemon
-
-    - name: Lint Lua code
+    - name: Cache pre-commit
+      uses: actions/cache@v2
+      with:
+        path: ~/.cache/pre-commit
+        key: ${{ runner.os }}-pre-commit-${{ hashFiles('config/pre-commit/config.yml') }}
+        restore-keys: |
+          ${{ runner.os }}-pre-commit-
+    - name: Run linters
       run: |
-        test -d bin || mkdir bin
-        test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
-        chmod +x bin/illuaminate
-        bin/illuaminate lint
-
-    - name: Check whitespace
-      run: python3 tools/check-lines.py
+        pip install pre-commit
+        pre-commit run --config config/pre-commit/config.yml --show-diff-on-failure --all --color=always
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 24b3ce1ca..7c250e89c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,7 @@ Gradle should be your entrypoint to building most documentation. There's two tas
 
 #### Writing documentation
 illuaminate's documentation system is not currently documented (somewhat ironic), but is _largely_ the same as
-[ldoc][ldoc]. Documentation comments are written in Markdown, 
+[ldoc][ldoc]. Documentation comments are written in Markdown,
 
 Our markdown engine does _not_ support GitHub flavoured markdown, and so does not support all the features one might
 expect (such as tables). It is very much recommended that you build and preview the docs locally first.
@@ -77,18 +77,18 @@ entire test suite (and some additional bits of verification).
 Before we get into writing tests, it's worth mentioning the various test suites that CC: Tweaked has:
  - "Core" Java (`./src/test/java`): These test core bits of the mod which don't require any Minecraft interaction.
    This includes the `@LuaFunction` system, file system code, etc...
-   
+
    These tests are run by `./gradlew test`.
 
  - CraftOS (`./src/test/resources/test-rom/`): These tests are written in Lua, and ensure the Lua environment, libraries
    and programs work as expected. These are (generally) written to be able to be run on emulators too, to provide some
    sort of compliance test.
-   
+
    These tests are run by the '"Core" Java' test suite, and so are also run with `./gradlew test`.
 
  - In-game (`./src/test/java/dan200/computercraft/ingame/`): These tests are run on an actual Minecraft server, using
    [the same system Mojang do][mc-test]. The aim of these is to test in-game behaviour of blocks and peripherals.
-   
+
    These are run by `./gradlew testInGame`.
 
 ## CraftOS tests
diff --git a/LICENSE b/LICENSE
index 65a70f5ae..cf30d77a6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -19,14 +19,14 @@ Mod: The mod code designated by the present license, in source form, binary
 form, as obtained standalone, as part of a wider distribution or resulting from
 the compilation of the original or modified sources.
 
-Dependency: Code required for the mod to work properly. This includes 
+Dependency: Code required for the mod to work properly. This includes
 dependencies required to compile the code as well as any file or modification
 that is explicitly or implicitly required for the mod to be working.
 
 1. Scope
 --------
 
-The present license is granted to any user of the mod. As a prerequisite, 
+The present license is granted to any user of the mod. As a prerequisite,
 a user must own a legally acquired copy of Minecraft
 
 2. Liability
@@ -41,13 +41,13 @@ or misuse of this mod fall on the user.
 3. Play rights
 --------------
 
-The user is allowed to install this mod on a Minecraft client or server and to play 
+The user is allowed to install this mod on a Minecraft client or server and to play
 without restriction.
 
 4. Modification rights
 ----------------------
 
-The user has the right to decompile the source code, look at either the 
+The user has the right to decompile the source code, look at either the
 decompiled version or the original source code, and to modify it.
 
 5. Distribution of original or modified copy rights
@@ -61,10 +61,10 @@ include:
    - patch to its source or binary files
    - any copy of a portion of its binary source files
 
-The user is allowed to redistribute this mod partially, in totality, or 
+The user is allowed to redistribute this mod partially, in totality, or
 included in a distribution.
 
-When distributing binary files, the user must provide means to obtain its 
+When distributing binary files, the user must provide means to obtain its
 entire set of sources or modified sources at no cost.
 
 All distributions of this mod must remain licensed under the CCPL.
@@ -92,7 +92,7 @@ must be made available at no cost and remain licensed under the CCPL.
 ---------------
 
 If you choose to contribute code or assets to be included in this mod, you
-agree that, if added to to the main repository at 
+agree that, if added to to the main repository at
 https://github.com/dan200/ComputerCraft, your contributions will be covered by
 this license, and that Daniel Ratcliffe will retain the right to re-license the
 mod, including your contributions, in part or in whole, under other licenses.
diff --git a/config/idea/codeInspectionSettings.xml b/config/idea/codeInspectionSettings.xml
index 2862d72b4..57b8ed0d7 100644
--- a/config/idea/codeInspectionSettings.xml
+++ b/config/idea/codeInspectionSettings.xml
@@ -2488,4 +2488,4 @@
       
     
   
-
\ No newline at end of file
+
diff --git a/config/idea/codeStyleSettings.xml b/config/idea/codeStyleSettings.xml
index b4c9573fd..9a1e0f1d4 100644
--- a/config/idea/codeStyleSettings.xml
+++ b/config/idea/codeStyleSettings.xml
@@ -58,4 +58,4 @@